diff --git a/.eslintrc.json b/.eslintrc.json index 3e369153b..3da5dafd4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,5 @@ { + "root": true, "env": { "browser": true, "es2021": true, diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..d2f78c87b --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master, release ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '34 0 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.gitmodules b/.gitmodules index 23bde5b15..3d710f8d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,7 @@ [submodule "thirdparty/tesseract"] path = thirdparty/tesseract url = git@github.com:abhinavkgrd/tesseract.js.git +[submodule "ffmpeg-wasm"] + path = thirdparty/ffmpeg-wasm + url = https://github.com/abhinavkgrd/ffmpeg.wasm.git + branch = single-thread diff --git a/README.md b/README.md index b36b8f4dc..d90d2e134 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,58 @@ -Web application for [ente](https://ente.io) built with lots of â¤ī¸ and a little bit of JavaScript. +# ente - simple, safe photo storage -You can read more about ente's encryption protocol here: https://ente.io/architecture. +**ente** is a cloud storage provider that provides end-to-end encryption for your data. -For more information about the project please visit: https://ente.io. +We have open-source apps across [Android](https://github.com/ente-io/frame), [iOS](https://github.com/ente-io/frame), [web](https://github.com/ente-io/bada-frame) and [desktop](https://github.com/ente-io/bhari-frame) that automatically backup your photos and videos. + +This repository contains the code for our web app, built with a lot of â¤ī¸, and a little bit of JavaScript. +


+![App Screenshots](https://user-images.githubusercontent.com/1161789/154797467-a2c14f13-6b04-4282-ab61-f6a9f60c2026.png) + +## ✨ Features + +- Client side encryption (only you can view your photos and videos) +- Bulk uploader (from hard disk, Google Photos, Apple Photos, ...) +- Shareable links for albums +- Ability to filter photos by places, days, album and file names +- 2FA +- Recycle bin +- EXIF viewer +- Zero third-party tracking / analytics + +## đŸ’ģ Deployed Application + +The deployed application is accessible @ [web.ente.io](https://web.ente.io). + +## 🧑‍đŸ’ģ Building from source + +1. Clone this repository with `git clone git@github.com:ente-io/bada-frame.git` +2. Pull in all submodules with `git submodule update --init --recursive` +3. Install dependencies with `yarn install` +4. Finally, run the development server with `yarn dev` + +Open [http://localhost:3000](http://localhost:3000) on your browser to see the live application. + +## 🙋 Help + +We provide human support to our customers. Please write to [support@ente.io](mailto:support@ente.io) sharing as many details as possible about whatever it is that you need help with, and we will get back to you as soon as possible. + +## 🧭 Roadmap + +We maintain a public roadmap, that's driven by our community @ [roadmap.ente.io](https://roadmap.ente.io). + +## 🤗 Support + +If you like this project, please consider upgrading to a paid subscription. + +If you would like to motivate us to keep building, you can do so by [starring](https://github.com/ente-io/bada-frame/stargazers) this project. + +## â¤ī¸ Join the Community + +Follow us on [Twitter](https://twitter.com/enteio) and join [r/enteio](https://reddit.com/r/enteio) to get regular updates, connect with other customers, and discuss your ideas. + +An important part of our journey is to build better software by consistently listening to community feedback. Please feel free to [share your thoughts](mailto:feedback@ente.io) with us at any time. --- -## Building - -First, pull and install dependencies -```bash -git submodule update --init --recursive -yarn install -``` - -Then run the development server: - -```bash -npm run dev -# or -yarn dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - ---- - -If there's something you need help with, please write to [support@ente.io](mailto:support@ente.io), we'd be happy to help! +Cross-browser testing provided by +[](https://www.browserstack.com/open-source) diff --git a/configUtil.js b/configUtil.js index 47c36a1ad..274c3d786 100644 --- a/configUtil.js +++ b/configUtil.js @@ -17,15 +17,24 @@ module.exports = { }, CSP_DIRECTIVES: { - 'default-src': "'none'", - 'img-src': "'self' blob:", + // self is safe enough + 'default-src': "'self'", + // data to allow two factor qr code + 'img-src': "'self' blob: data:", + 'media-src': "'self' blob:", + 'manifest-src': "'self'", 'style-src': "'self' 'unsafe-inline'", 'font-src ': "'self'; script-src 'self' 'unsafe-eval' blob:", 'connect-src': - "'self' https://*.ente.io data: blob: https://ente-prod-eu.s3.eu-central-003.backblazeb2.com ", + "'self' https://*.ente.io http://localhost:8080 data: blob: https://ente-prod-eu.s3.eu-central-003.backblazeb2.com ", 'base-uri ': "'self'", + // to allow worker + 'child-src': "'self' blob:", + 'object-src': "'none'", 'frame-ancestors': " 'none'", 'form-action': "'none'", + 'report-uri': ' https://csp-reporter.ente.io/local', + 'report-to': ' https://csp-reporter.ente.io/local', }, WORKBOX_CONFIG: { diff --git a/next-env.d.ts b/next-env.d.ts index 9bc3dd46b..4f11a03dc 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,5 +1,4 @@ /// -/// /// // NOTE: This file should not be edited diff --git a/next.config.js b/next.config.js index 056b654ad..5b81c9910 100644 --- a/next.config.js +++ b/next.config.js @@ -6,6 +6,12 @@ const withWorkbox = require('@ente-io/next-with-workbox'); const { withSentryConfig } = require('@sentry/nextjs'); const { PHASE_DEVELOPMENT_SERVER } = require('next/constants'); +const withTM = require('next-transpile-modules')([ + '@mui/material', + '@mui/system', + '@mui/icons-material', +]); + const { getGitSha, convertToNextHeaderFormat, @@ -25,33 +31,36 @@ const IS_SENTRY_ENABLED = getIsSentryEnabled(); module.exports = (phase) => withSentryConfig( withWorkbox( - withBundleAnalyzer({ - env: { - SENTRY_RELEASE: GIT_SHA, - }, - workbox: WORKBOX_CONFIG, + withBundleAnalyzer( + withTM({ + env: { + SENTRY_RELEASE: GIT_SHA, + NEXT_PUBLIC_LATEST_COMMIT_HASH: GIT_SHA, + }, + workbox: WORKBOX_CONFIG, - headers() { - return [ - { - // Apply these headers to all routes in your application.... - source: ALL_ROUTES, - headers: convertToNextHeaderFormat({ - ...COOP_COEP_HEADERS, - ...WEB_SECURITY_HEADERS, - ...buildCSPHeader(CSP_DIRECTIVES), - }), - }, - ]; - }, - // https://dev.to/marcinwosinek/how-to-add-resolve-fallback-to-webpack-5-in-nextjs-10-i6j - webpack: (config, { isServer }) => { - if (!isServer) { - config.resolve.fallback.fs = false; - } - return config; - }, - }) + headers() { + return [ + { + // Apply these headers to all routes in your application.... + source: ALL_ROUTES, + headers: convertToNextHeaderFormat({ + ...COOP_COEP_HEADERS, + ...WEB_SECURITY_HEADERS, + ...buildCSPHeader(CSP_DIRECTIVES), + }), + }, + ]; + }, + // https://dev.to/marcinwosinek/how-to-add-resolve-fallback-to-webpack-5-in-nextjs-10-i6j + webpack: (config, { isServer }) => { + if (!isServer) { + config.resolve.fallback.fs = false; + } + return config; + }, + }) + ) ), { release: GIT_SHA, diff --git a/package.json b/package.json index feb307e06..62bc2ef19 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "bada-frame", - "version": "0.4.4", + "version": "1.0.0", "private": true, "scripts": { "dev": "next dev", "albums": "next dev -p 3002", - "prebuild": "eslint 'src/**/*.{js,jsx,ts,tsx}'", + "prebuild": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", "build": "next build", "build-analyze": "ANALYZE=true next build", "postbuild": "next export", @@ -13,9 +13,13 @@ "prepare": "husky install" }, "dependencies": { + "@date-io/date-fns": "^2.14.0", "@ente-io/next-with-workbox": "^1.0.3", - "@ffmpeg/core": "^0.10.0", - "@ffmpeg/ffmpeg": "^0.10.1", + "@mui/icons-material": "^5.6.2", + "@mui/material": "^5.6.2", + "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest", + "@mui/styled-engine-sc": "^5.6.1", + "@mui/x-date-pickers": "^5.0.0-alpha.6", "@sentry/nextjs": "^6.7.1", "@stripe/stripe-js": "^1.13.2", "@tensorflow-models/coco-ssd": "^2.2.2", @@ -31,6 +35,7 @@ "bip39": "^3.0.4", "blazeface-back": "^0.0.8", "bootstrap": "^4.5.2", + "bs58": "^4.0.1", "chrono-node": "^2.2.6", "comlink": "^4.3.0", "debounce-promise": "^3.1.2", @@ -41,7 +46,8 @@ "eslint-plugin-react-hooks": "^4.2.0", "eventemitter3": "^4.0.7", "exifr": "^7.1.3", - "file-type": "^16.5.3", + "ffmpeg-wasm": "file:./thirdparty/ffmpeg-wasm", + "file-type": "^16.5.4", "formik": "^2.1.5", "hdbscan": "0.0.1-alpha.5", "heic-convert": "^1.2.4", @@ -52,14 +58,13 @@ "libsodium-wrappers": "^0.7.8", "localforage": "^1.9.0", "ml-matrix": "^6.8.2", - "next": "^11.1.3", "p-queue": "^7.1.0", + "next": "^12.1.0", + "next-transpile-modules": "^9.0.0", "photoswipe": "file:./thirdparty/photoswipe", "piexifjs": "^1.0.6", "react": "^17.0.2", "react-bootstrap": "^1.3.0", - "react-burger-menu": "^3.0.4", - "react-collapse": "^5.1.0", "react-d3-tree": "^3.1.1", "react-datepicker": "^4.3.0", "react-dom": "^17.0.2", @@ -70,13 +75,12 @@ "react-top-loading-bar": "^2.0.1", "react-virtualized-auto-sizer": "^1.0.2", "react-window": "^1.8.6", - "react-window-infinite-loader": "^1.0.5", "scrypt-js": "^3.0.1", "similarity-transformation": "^0.0.1", - "styled-components": "^5.2.0", "tesseract.js": "file:./thirdparty/tesseract", "transformation-matrix": "^2.10.0", "tsne-js": "^1.0.3", + "styled-components": "^5.3.5", "workbox-precaching": "^6.1.5", "workbox-recipes": "^6.1.5", "workbox-routing": "^6.1.5", @@ -97,14 +101,20 @@ "@types/react-select": "^4.0.15", "@types/react-window": "^1.8.2", "@types/react-window-infinite-loader": "^1.0.3", - "@types/styled-components": "^5.1.3", "@types/wicg-file-system-access": "^2020.9.5", + "@types/styled-components": "^5.1.25", "@types/yup": "^0.29.7", + "@typescript-eslint/eslint-plugin": "^4.25.0", + "@typescript-eslint/parser": "^4.25.0", "babel-plugin-styled-components": "^1.11.1", "eslint": "^7.27.0", + "eslint-config-airbnb": "^18.2.1", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.23.3", + "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.23.2", + "eslint-plugin-react-hooks": "^4.2.0", "husky": "^7.0.1", "lint-staged": "^11.1.2", "prettier": "2.3.2", @@ -118,5 +128,8 @@ "eslint --fix", "prettier --write --ignore-unknown" ] + }, + "resolutions": { + "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest" } } diff --git a/public/_headers b/public/_headers index c127ebe28..388d4038c 100644 --- a/public/_headers +++ b/public/_headers @@ -8,5 +8,5 @@ X-Frame-Options: deny X-XSS-Protection: 1; mode=block Referrer-Policy: same-origin - Content-Security-Policy-Report-Only: default-src 'none'; img-src 'self' blob:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self' 'unsafe-eval' blob:; connect-src 'self' https://*.ente.io data: blob: https://ente-prod-eu.s3.eu-central-003.backblazeb2.com ; base-uri 'self'; frame-ancestors 'none'; form-action 'none'; report-uri https://csp-reporter.ente.io; report-to https://csp-reporter.ente.io; + Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' blob: data:; media-src 'self' blob:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self' 'unsafe-eval' blob:; manifest-src 'self'; child-src 'self' blob:; object-src 'none'; connect-src 'self' https://*.ente.io data: blob: https://ente-prod-eu.s3.eu-central-003.backblazeb2.com ; base-uri 'self'; frame-ancestors 'none'; form-action 'none'; report-uri https://csp-reporter.ente.io; report-to https://csp-reporter.ente.io; diff --git a/public/download_icon.png b/public/download_icon.png deleted file mode 100644 index 97bd7f8f6..000000000 Binary files a/public/download_icon.png and /dev/null differ diff --git a/public/fav-button.png b/public/fav-button.png deleted file mode 100644 index 3ec964d07..000000000 Binary files a/public/fav-button.png and /dev/null differ diff --git a/public/fonts/OFL.txt b/public/fonts/OFL.txt new file mode 100644 index 000000000..ad214842c --- /dev/null +++ b/public/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/public/fonts/UFL.txt b/public/fonts/UFL.txt deleted file mode 100644 index 6e722c88d..000000000 --- a/public/fonts/UFL.txt +++ /dev/null @@ -1,96 +0,0 @@ -------------------------------- -UBUNTU FONT LICENCE Version 1.0 -------------------------------- - -PREAMBLE -This licence allows the licensed fonts to be used, studied, modified and -redistributed freely. The fonts, including any derivative works, can be -bundled, embedded, and redistributed provided the terms of this licence -are met. The fonts and derivatives, however, cannot be released under -any other licence. The requirement for fonts to remain under this -licence does not require any document created using the fonts or their -derivatives to be published under this licence, as long as the primary -purpose of the document is not to be a vehicle for the distribution of -the fonts. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this licence and clearly marked as such. This may -include source files, build scripts and documentation. - -"Original Version" refers to the collection of Font Software components -as received under this licence. - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to -a new environment. - -"Copyright Holder(s)" refers to all individuals and companies who have a -copyright ownership of the Font Software. - -"Substantially Changed" refers to Modified Versions which can be easily -identified as dissimilar to the Font Software by users of the Font -Software comparing the Original Version with the Modified Version. - -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 and with or without charging -a redistribution fee), making available to the public, and in some -countries other activities as well. - -PERMISSION & CONDITIONS -This licence does not grant any rights under trademark law and all such -rights are reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of the Font Software, to propagate the Font Software, subject to -the below conditions: - -1) Each copy of the Font Software must contain the above copyright -notice and this licence. These can be included either as stand-alone -text files, human-readable headers or in the appropriate machine- -readable metadata fields within text or binary files as long as those -fields can be easily viewed by the user. - -2) The font name complies with the following: -(a) The Original Version must retain its name, unmodified. -(b) Modified Versions which are Substantially Changed must be renamed to -avoid use of the name of the Original Version or similar names entirely. -(c) Modified Versions which are not Substantially Changed must be -renamed to both (i) retain the name of the Original Version and (ii) add -additional naming elements to distinguish the Modified Version from the -Original Version. The name of such Modified Versions must be the name of -the Original Version, with "derivative X" where X represents the name of -the new work, appended to that name. - -3) The name(s) of the Copyright Holder(s) and any contributor to the -Font Software shall not be used to promote, endorse or advertise any -Modified Version, except (i) as required by this licence, (ii) to -acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with -their explicit written permission. - -4) The Font Software, modified or unmodified, in part or in whole, must -be distributed entirely under this licence, and must not be distributed -under any other licence. The requirement for fonts to remain under this -licence does not affect any document created using the Font Software, -except any version of the Font Software extracted from a document -created using the Font Software may only be distributed under this -licence. - -TERMINATION -This licence becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER -DEALINGS IN THE FONT SOFTWARE. diff --git a/public/fonts/inter-v11-latin-500.woff b/public/fonts/inter-v11-latin-500.woff new file mode 100644 index 000000000..a5b7c7a2a Binary files /dev/null and b/public/fonts/inter-v11-latin-500.woff differ diff --git a/public/fonts/inter-v11-latin-500.woff2 b/public/fonts/inter-v11-latin-500.woff2 new file mode 100644 index 000000000..0e3db59fe Binary files /dev/null and b/public/fonts/inter-v11-latin-500.woff2 differ diff --git a/public/fonts/inter-v11-latin-600.woff b/public/fonts/inter-v11-latin-600.woff new file mode 100644 index 000000000..03c1df0b8 Binary files /dev/null and b/public/fonts/inter-v11-latin-600.woff differ diff --git a/public/fonts/inter-v11-latin-600.woff2 b/public/fonts/inter-v11-latin-600.woff2 new file mode 100644 index 000000000..3eef889ee Binary files /dev/null and b/public/fonts/inter-v11-latin-600.woff2 differ diff --git a/public/fonts/inter-v11-latin-800.woff b/public/fonts/inter-v11-latin-800.woff new file mode 100644 index 000000000..feb91cc1d Binary files /dev/null and b/public/fonts/inter-v11-latin-800.woff differ diff --git a/public/fonts/inter-v11-latin-800.woff2 b/public/fonts/inter-v11-latin-800.woff2 new file mode 100644 index 000000000..595bcec65 Binary files /dev/null and b/public/fonts/inter-v11-latin-800.woff2 differ diff --git a/public/fonts/ubuntu-v15-latin-700.woff b/public/fonts/ubuntu-v15-latin-700.woff deleted file mode 100644 index 8f770546a..000000000 Binary files a/public/fonts/ubuntu-v15-latin-700.woff and /dev/null differ diff --git a/public/fonts/ubuntu-v15-latin-700.woff2 b/public/fonts/ubuntu-v15-latin-700.woff2 deleted file mode 100644 index e10142f55..000000000 Binary files a/public/fonts/ubuntu-v15-latin-700.woff2 and /dev/null differ diff --git a/public/fonts/ubuntu-v15-latin-regular.woff b/public/fonts/ubuntu-v15-latin-regular.woff deleted file mode 100644 index 2fc163ffb..000000000 Binary files a/public/fonts/ubuntu-v15-latin-regular.woff and /dev/null differ diff --git a/public/fonts/ubuntu-v15-latin-regular.woff2 b/public/fonts/ubuntu-v15-latin-regular.woff2 deleted file mode 100644 index a590b8a9e..000000000 Binary files a/public/fonts/ubuntu-v15-latin-regular.woff2 and /dev/null differ diff --git a/public/icon.svg b/public/icon.svg deleted file mode 100644 index a1ca5e53f..000000000 --- a/public/icon.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/public/images/black-thumbnail-b64.ts b/public/images/black-thumbnail-b64.ts deleted file mode 100644 index 94a0e11d7..000000000 --- a/public/images/black-thumbnail-b64.ts +++ /dev/null @@ -1,28 +0,0 @@ -export const BLACK_THUMBNAIL_BASE64 = - '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB' + - 'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ' + - 'EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARC' + - 'ACWASwDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF' + - 'BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk' + - '6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztL' + - 'W2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAA' + - 'AAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVY' + - 'nLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImK' + - 'kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oAD' + - 'AMBAAIRAxEAPwD/AD/6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + - 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + - 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAC' + - 'gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + - 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + - 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + - 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + - 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + - 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' + - 'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACg' + - 'AoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + - 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKA' + - 'CgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAK' + - 'ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA' + - 'KACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + - 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo' + - 'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD/9k='; diff --git a/public/images/black-thumbnail.jpeg b/public/images/black-thumbnail.jpeg deleted file mode 100644 index f8b2f3226..000000000 Binary files a/public/images/black-thumbnail.jpeg and /dev/null differ diff --git a/public/images/ente.svg b/public/images/ente.svg new file mode 100644 index 000000000..33bd74256 --- /dev/null +++ b/public/images/ente.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/ente-192.png b/public/images/ente/192.png similarity index 100% rename from public/images/ente-192.png rename to public/images/ente/192.png diff --git a/public/images/ente-256.png b/public/images/ente/256.png similarity index 100% rename from public/images/ente-256.png rename to public/images/ente/256.png diff --git a/public/images/ente-512.png b/public/images/ente/512.png similarity index 100% rename from public/images/ente-512.png rename to public/images/ente/512.png diff --git a/public/images/family-plan/1x.png b/public/images/family-plan/1x.png new file mode 100644 index 000000000..050c61862 Binary files /dev/null and b/public/images/family-plan/1x.png differ diff --git a/public/images/family-plan/2x.png b/public/images/family-plan/2x.png new file mode 100644 index 000000000..faf3df971 Binary files /dev/null and b/public/images/family-plan/2x.png differ diff --git a/public/images/family-plan/3x.png b/public/images/family-plan/3x.png new file mode 100644 index 000000000..0949dbf0e Binary files /dev/null and b/public/images/family-plan/3x.png differ diff --git a/public/images/gallery-locked/1x.png b/public/images/gallery-locked/1x.png new file mode 100644 index 000000000..8c5918bbe Binary files /dev/null and b/public/images/gallery-locked/1x.png differ diff --git a/public/images/gallery-locked/2x.png b/public/images/gallery-locked/2x.png new file mode 100644 index 000000000..2d0924ca7 Binary files /dev/null and b/public/images/gallery-locked/2x.png differ diff --git a/public/images/gallery-locked/3x.png b/public/images/gallery-locked/3x.png new file mode 100644 index 000000000..e8d0645c3 Binary files /dev/null and b/public/images/gallery-locked/3x.png differ diff --git a/public/images/gallery.png b/public/images/gallery.png deleted file mode 100644 index 38b8a2739..000000000 Binary files a/public/images/gallery.png and /dev/null differ diff --git a/public/images/onboarding-lock/1x.png b/public/images/onboarding-lock/1x.png new file mode 100644 index 000000000..c5f2db2be Binary files /dev/null and b/public/images/onboarding-lock/1x.png differ diff --git a/public/images/onboarding-lock/2x.png b/public/images/onboarding-lock/2x.png new file mode 100644 index 000000000..241517bbb Binary files /dev/null and b/public/images/onboarding-lock/2x.png differ diff --git a/public/images/onboarding-lock/3x.png b/public/images/onboarding-lock/3x.png new file mode 100644 index 000000000..a15af44b0 Binary files /dev/null and b/public/images/onboarding-lock/3x.png differ diff --git a/public/images/onboarding-safe/1x.png b/public/images/onboarding-safe/1x.png new file mode 100644 index 000000000..d8174de79 Binary files /dev/null and b/public/images/onboarding-safe/1x.png differ diff --git a/public/images/onboarding-safe/2x.png b/public/images/onboarding-safe/2x.png new file mode 100644 index 000000000..06f85e0ba Binary files /dev/null and b/public/images/onboarding-safe/2x.png differ diff --git a/public/images/onboarding-safe/3x.png b/public/images/onboarding-safe/3x.png new file mode 100644 index 000000000..350675112 Binary files /dev/null and b/public/images/onboarding-safe/3x.png differ diff --git a/public/images/onboarding-sync/1x.png b/public/images/onboarding-sync/1x.png new file mode 100644 index 000000000..04764a0d3 Binary files /dev/null and b/public/images/onboarding-sync/1x.png differ diff --git a/public/images/onboarding-sync/2x.png b/public/images/onboarding-sync/2x.png new file mode 100644 index 000000000..fd733e44d Binary files /dev/null and b/public/images/onboarding-sync/2x.png differ diff --git a/public/images/onboarding-sync/3x.png b/public/images/onboarding-sync/3x.png new file mode 100644 index 000000000..b7177ec4a Binary files /dev/null and b/public/images/onboarding-sync/3x.png differ diff --git a/public/images/slide-1.png b/public/images/slide-1.png deleted file mode 100644 index 551004a88..000000000 Binary files a/public/images/slide-1.png and /dev/null differ diff --git a/public/images/slide-2.png b/public/images/slide-2.png deleted file mode 100644 index cc5070968..000000000 Binary files a/public/images/slide-2.png and /dev/null differ diff --git a/public/images/slide-3.png b/public/images/slide-3.png deleted file mode 100644 index 1888ad6f1..000000000 Binary files a/public/images/slide-3.png and /dev/null differ diff --git a/public/images/subscription-card-background/1x.png b/public/images/subscription-card-background/1x.png new file mode 100644 index 000000000..724b8beb1 Binary files /dev/null and b/public/images/subscription-card-background/1x.png differ diff --git a/public/images/subscription-card-background/2x.png b/public/images/subscription-card-background/2x.png new file mode 100644 index 000000000..26be3d8fc Binary files /dev/null and b/public/images/subscription-card-background/2x.png differ diff --git a/public/images/subscription-card-background/3x.png b/public/images/subscription-card-background/3x.png new file mode 100644 index 000000000..8dfb56cd9 Binary files /dev/null and b/public/images/subscription-card-background/3x.png differ diff --git a/public/info_icon.png b/public/info_icon.png deleted file mode 100644 index 7d0740a8f..000000000 Binary files a/public/info_icon.png and /dev/null differ diff --git a/public/js/ffmpeg/ffmpeg-core.js b/public/js/ffmpeg/ffmpeg-core.js index a0fcddc34..f06ffde63 100644 --- a/public/js/ffmpeg/ffmpeg-core.js +++ b/public/js/ffmpeg/ffmpeg-core.js @@ -7,237 +7,154 @@ function(createFFmpegCore) { createFFmpegCore = createFFmpegCore || {}; -var f;f||(f=typeof createFFmpegCore !== 'undefined' ? createFFmpegCore : {});var ba,ca;f.ready=new Promise(function(a,b){ba=a;ca=b});var da={},ea;for(ea in f)f.hasOwnProperty(ea)&&(da[ea]=f[ea]);var fa=[],ha="./this.program";function ja(a,b){throw b;}var ka=!1,la=!1,h=!1,ma=!1;ka="object"===typeof window;la="function"===typeof importScripts;h="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node;ma=!ka&&!h&&!la;var l=f.ENVIRONMENT_IS_PTHREAD||!1; -l&&(oa=f.buffer);var pa="";function qa(a){return f.locateFile?f.locateFile(a,pa):pa+a}var ra,sa,ta,va; -if(h){pa=la?require("path").dirname(pa)+"/":__dirname+"/";ra=function(a,b){ta||(ta=require("fs"));va||(va=require("path"));a=va.normalize(a);return ta.readFileSync(a,b?null:"utf8")};sa=function(a){a=ra(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};1=c);){var e=a[b++];if(!e)break;if(e&128){var g=a[b++]&63;if(192==(e&224))d+=String.fromCharCode((e&31)<<6|g);else{var k=a[b++]&63;e=224==(e&240)?(e&15)<<12|g<<6|k:(e&7)<<18|g<<12|k<<6|a[b++]&63;65536>e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d}function C(a,b){return a?Ja(v,a,b):""} -function Ia(a,b,c,d){if(!(0=k){var m=a.charCodeAt(++g);k=65536+((k&1023)<<10)|m&1023}if(127>=k){if(c>=d)break;b[c++]=k}else{if(2047>=k){if(c+1>=d)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=d)break;b[c++]=224|k>>12}else{if(c+3>=d)break;b[c++]=240|k>>18;b[c++]=128|k>>12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-e} -function Ka(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}return b}function La(a){var b=Ka(a)+1,c=Ma(b);c&&Ia(a,y,c,b);return c}function Na(a){var b=Ka(a)+1,c=Ha(b);Ia(a,y,c,b);return c}function Pa(a,b,c){for(var d=0;d>0]=a.charCodeAt(d);c||(y[b>>0]=0)}var oa,y,v,Qa,Ra,E,F,G,Sa,Ta=f.INITIAL_MEMORY||2146435072; -if(l)Ca=f.wasmMemory,oa=f.buffer;else if(f.wasmMemory)Ca=f.wasmMemory;else if(Ca=new WebAssembly.Memory({initial:Ta/65536,maximum:Ta/65536,shared:!0}),!(Ca.buffer instanceof SharedArrayBuffer))throw u("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"),h&&console.log("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and also use a recent version)"), -Error("bad memory");Ca&&(oa=Ca.buffer);Ta=oa.byteLength;var Ua=oa;oa=Ua;f.HEAP8=y=new Int8Array(Ua);f.HEAP16=Qa=new Int16Array(Ua);f.HEAP32=E=new Int32Array(Ua);f.HEAPU8=v=new Uint8Array(Ua);f.HEAPU16=Ra=new Uint16Array(Ua);f.HEAPU32=F=new Uint32Array(Ua);f.HEAPF32=G=new Float32Array(Ua);f.HEAPF64=Sa=new Float64Array(Ua);var H,Va=[],Wa=[],Xa=[],Ya=[],Za=[];function $a(){var a=f.preRun.shift();Va.unshift(a)}var ab=0,bb=null,cb=null; -function eb(){assert(!l,"addRunDependency cannot be used in a pthread worker");ab++;f.monitorRunDependencies&&f.monitorRunDependencies(ab)}function fb(){ab--;f.monitorRunDependencies&&f.monitorRunDependencies(ab);if(0==ab&&(null!==bb&&(clearInterval(bb),bb=null),cb)){var a=cb;cb=null;a()}}f.preloadedImages={};f.preloadedAudios={}; -function n(a){if(f.onAbort)f.onAbort(a);l&&console.error("Pthread aborting at "+Error().stack);u(a);Ea=!0;a=new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");ca(a);throw a;}function gb(a){var b=hb;return String.prototype.startsWith?b.startsWith(a):0===b.indexOf(a)}function ib(){return gb("data:application/octet-stream;base64,")}var hb="ffmpeg-core.wasm";ib()||(hb=qa(hb)); -function jb(){try{if(Ba)return new Uint8Array(Ba);if(sa)return sa(hb);throw"both async and sync fetching of the wasm failed";}catch(a){n(a)}}function kb(){return Ba||!ka&&!la||"function"!==typeof fetch||gb("file://")?Promise.resolve().then(jb):fetch(hb,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+hb+"'";return a.arrayBuffer()}).catch(function(){return jb()})} -var J,L,mb={5454720:function(){throw"Canceled!";},5454940:function(a,b){setTimeout(function(){lb(a,b)},0)},5455042:function(){return 5242880}};function nb(a){for(;0=a||a>y.length||a&1||0>b)return-28;if(0==b)return 0;2147483647<=b&&(b=Infinity);var c=Atomics.load(E,M.Vf>>2),d=0;if(c==a&&Atomics.compareExchange(E,M.Vf>>2,c,0)==c&&(--b,d=1,0>=b))return 1;a=Atomics.notify(E,a>>2,b);if(0<=a)return a+d;throw"Atomics.notify returned an unexpected value "+a;}f._emscripten_futex_wake=tb; -function ub(a){if(l)throw"Internal Error! cancelThread() can only ever be called from main application thread!";if(!a)throw"Internal Error! Null pthread_ptr in cancelThread!";M.Ef[a].worker.postMessage({cmd:"cancel"})}function vb(a){if(l)throw"Internal Error! cleanupThread() can only ever be called from main application thread!";if(!a)throw"Internal Error! Null pthread_ptr in cleanupThread!";E[a+12>>2]=0;(a=M.Ef[a])&&M.Ag(a.worker)} -var M={Ph:1,nj:{Ih:0,Jh:0},Gf:[],Kf:[],lj:function(){},pi:function(){M.xf=Ma(232);for(var a=0;58>a;++a)F[M.xf/4+a]=0;E[M.xf+12>>2]=M.xf;a=M.xf+156;E[a>>2]=a;var b=Ma(512);for(a=0;128>a;++a)F[b/4+a]=0;Atomics.store(F,M.xf+104>>2,b);Atomics.store(F,M.xf+40>>2,M.xf);Atomics.store(F,M.xf+44>>2,42);M.Ch();sb(M.xf,!la,1);wb(M.xf)},ri:function(){M.Ch();ba(f);M.receiveObjectTransfer=M.Ii;M.setThreadStatus=M.Li;M.threadCancel=M.Pi;M.threadExit=M.Qi},Ch:function(){M.Vf=xb},Ef:{},Dg:[],Li:function(){},eh:function(){for(;0< -M.Dg.length;)M.Dg.pop()();l&&threadInfoStruct&&yb()},Qi:function(a){var b=pb|0;b&&(Atomics.store(F,b+4>>2,a),Atomics.store(F,b+0>>2,1),Atomics.store(F,b+60>>2,1),Atomics.store(F,b+64>>2,0),M.eh(),tb(b+0,2147483647),sb(0,0,0),threadInfoStruct=0,l&&postMessage({cmd:"exit"}))},Pi:function(){M.eh();Atomics.store(F,threadInfoStruct+4>>2,-1);Atomics.store(F,threadInfoStruct+0>>2,1);tb(threadInfoStruct+0,2147483647);threadInfoStruct=selfThreadId=0;sb(0,0,0);postMessage({cmd:"cancelDone"})},Oi:function(){for(var a in M.Ef){var b= -M.Ef[a];b&&b.worker&&M.Ag(b.worker)}M.Ef={};for(a=0;a>2];E[a.threadInfoStruct+104>>2]=0;zb(b);zb(a.threadInfoStruct)}a.threadInfoStruct=0;a.Kg&&a.Rf&&zb(a.Rf);a.Rf=0;a.worker&&(a.worker.yf=null)}},Ag:function(a){delete M.Ef[a.yf.Lh];M.Gf.push(a);M.Kf.splice(M.Kf.indexOf(a),1);M.Pg(a.yf);a.yf=void 0}, -Ii:function(){},vi:function(a,b){a.onmessage=function(c){var d=c.data,e=d.cmd;a.yf&&(M.Mg=a.yf.threadInfoStruct);if(d.targetThread&&d.targetThread!=(pb|0)){var g=M.Ef[d.xj];g?g.worker.postMessage(c.data,d.transferList):console.error('Internal error! Worker sent a message "'+e+'" to target pthread '+d.targetThread+", but that thread no longer exists!")}else if("processQueuedMainThreadWork"===e)Ab();else if("spawnThread"===e)Bb(c.data);else if("cleanupThread"===e)vb(d.thread);else if("killThread"=== -e){c=d.thread;if(l)throw"Internal Error! killThread() can only ever be called from main application thread!";if(!c)throw"Internal Error! Null pthread_ptr in killThread!";E[c+12>>2]=0;c=M.Ef[c];c.worker.terminate();M.Pg(c);M.Kf.splice(M.Kf.indexOf(c.worker),1);c.worker.yf=void 0}else if("cancelThread"===e)ub(d.thread);else if("loaded"===e)a.loaded=!0,b&&b(a),a.og&&(a.og(),delete a.og);else if("print"===e)ya("Thread "+d.threadId+": "+d.text);else if("printErr"===e)u("Thread "+d.threadId+": "+d.text); -else if("alert"===e)alert("Thread "+d.threadId+": "+d.text);else if("exit"===e)a.yf&&Atomics.load(F,a.yf.Lh+68>>2)&&M.Ag(a);else if("exitProcess"===e){noExitRuntime=!1;try{Cb(d.returnCode)}catch(k){if(k instanceof wa)return;throw k;}}else"cancelDone"===e?M.Ag(a):"objectTransfer"!==e&&("setimmediate"===c.data.target?a.postMessage(c.data):u("worker sent an unknown command "+e));M.Mg=void 0};a.onerror=function(c){u("pthread sent an error! "+c.filename+":"+c.lineno+": "+c.message)};h&&(a.on("message", -function(c){a.onmessage({data:c})}),a.on("error",function(c){a.onerror(c)}),a.on("exit",function(){}));a.postMessage({cmd:"load",urlOrBlob:f.mainScriptUrlOrBlob||_scriptDir,wasmMemory:Ca,wasmModule:Da})},Vh:function(){var a=qa("ffmpeg-core.worker.js");M.Gf.push(new Worker(a))},li:function(){0==M.Gf.length&&(M.Vh(),M.vi(M.Gf[0]));return 0>2]=a}function Gb(a,b){if(0===a)a=Date.now();else if(1===a||4===a)a=Db();else return Eb(28),-1;E[b>>2]=a/1E3|0;E[b+4>>2]=a%1E3*1E6|0;return 0}function Hb(a,b){if(l)return N(1,1,a,b);Ya.unshift({vh:a,Tf:b})} -function Ib(a,b){a=new Date(1E3*E[a>>2]);E[b>>2]=a.getUTCSeconds();E[b+4>>2]=a.getUTCMinutes();E[b+8>>2]=a.getUTCHours();E[b+12>>2]=a.getUTCDate();E[b+16>>2]=a.getUTCMonth();E[b+20>>2]=a.getUTCFullYear()-1900;E[b+24>>2]=a.getUTCDay();E[b+36>>2]=0;E[b+32>>2]=0;E[b+28>>2]=(a.getTime()-Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0))/864E5|0;Ib.ih||(Ib.ih=La("GMT"));E[b+40>>2]=Ib.ih;return b} -function Jb(){function a(k){return(k=k.toTimeString().match(/\(([A-Za-z ]+)\)$/))?k[1]:"GMT"}if(l)return N(2,1);if(!Jb.Yh){Jb.Yh=!0;var b=(new Date).getFullYear(),c=new Date(b,0,1),d=new Date(b,6,1);b=c.getTimezoneOffset();var e=d.getTimezoneOffset(),g=Math.max(b,e);E[Kb()>>2]=60*g;E[Lb()>>2]=Number(b!=e);c=a(c);d=a(d);c=La(c);d=La(d);e>2]=c,E[Mb()+4>>2]=d):(E[Mb()>>2]=d,E[Mb()+4>>2]=c)}} -function Nb(a,b){Jb();a=new Date(1E3*E[a>>2]);E[b>>2]=a.getSeconds();E[b+4>>2]=a.getMinutes();E[b+8>>2]=a.getHours();E[b+12>>2]=a.getDate();E[b+16>>2]=a.getMonth();E[b+20>>2]=a.getFullYear()-1900;E[b+24>>2]=a.getDay();var c=new Date(a.getFullYear(),0,1);E[b+28>>2]=(a.getTime()-c.getTime())/864E5|0;E[b+36>>2]=-(60*a.getTimezoneOffset());var d=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();c=c.getTimezoneOffset();a=(d!=c&&a.getTimezoneOffset()==Math.min(c,d))|0;E[b+32>>2]=a;a=E[Mb()+(a?4:0)>>2]; -E[b+40>>2]=a;return b}function Ob(a,b){for(var c=0,d=a.length-1;0<=d;d--){var e=a[d];"."===e?a.splice(d,1):".."===e?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a}function Pb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=Ob(a.split("/").filter(function(d){return!!d}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} -function Qb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function Rb(a){if("/"===a)return"/";a=Pb(a);a=a.replace(/\/$/,"");var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function Sb(a,b){return Pb(a+"/"+b)} -function Tb(){if("object"===typeof crypto&&"function"===typeof crypto.getRandomValues){var a=new Uint8Array(1);return function(){crypto.getRandomValues(a);return a[0]}}if(h)try{var b=require("crypto");return function(){return b.randomBytes(1)[0]}}catch(c){}return function(){n("randomDevice")}} -function Ub(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:O.cwd();if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=Ob(a.split("/").filter(function(d){return!!d}),!b).join("/");return(b?"/":"")+a||"."} -function Vb(a,b){function c(k){for(var m=0;mr?[]:k.slice(m,r-m+1)}a=Ub(a).substr(1);b=Ub(b).substr(1);a=c(a.split("/"));b=c(b.split("/"));for(var d=Math.min(a.length,b.length),e=d,g=0;g=b||(b=Math.max(b,c*(1048576>c?2:1.125)>>>0),0!=c&&(b=Math.max(b,256)),c=a.bf,a.bf=new Uint8Array(b),0b)a.bf.length=b;else for(;a.bf.length=a.node.gf)return 0;a=Math.min(a.node.gf-e,d);if(8b)throw new O.af(28);return b},fg:function(a,b,c){P.sh(a.node,b+c);a.node.gf=Math.max(a.node.gf,b+c)},Wf:function(a,b,c,d,e,g){assert(0===b);if(!O.isFile(a.node.mode))throw new O.af(43);a=a.node.bf;if(g&2||a.buffer!==oa){if(0>>0)%O.Cf.length},zh:function(a){var b=O.Sg(a.parent.id,a.name);a.Pf=O.Cf[b];O.Cf[b]=a},Ah:function(a){var b=O.Sg(a.parent.id,a.name);if(O.Cf[b]===a)O.Cf[b]=a.Pf; -else for(b=O.Cf[b];b;){if(b.Pf===a){b.Pf=a.Pf;break}b=b.Pf}},Bf:function(a,b){var c=O.yi(a);if(c)throw new O.af(c,a);for(c=O.Cf[O.Sg(a.id,b)];c;c=c.Pf){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return O.lookup(a,b)},createNode:function(a,b,c,d){a=new O.Oh(a,b,c,d);O.zh(a);return a},Ng:function(a){O.Ah(a)},wg:function(a){return a===a.parent},Nf:function(a){return!!a.lg},isFile:function(a){return 32768===(a&61440)},kf:function(a){return 16384===(a&61440)},Mf:function(a){return 40960===(a&61440)}, -hg:function(a){return 8192===(a&61440)},si:function(a){return 24576===(a&61440)},isFIFO:function(a){return 4096===(a&61440)},isSocket:function(a){return 49152===(a&49152)},ji:{r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218},Dh:function(a){var b=O.ji[a];if("undefined"===typeof b)throw Error("Unknown file open mode: "+a);return b},th:function(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b},Jf:function(a,b){if(O.Bh)return 0; -if(-1===b.indexOf("r")||a.mode&292){if(-1!==b.indexOf("w")&&!(a.mode&146)||-1!==b.indexOf("x")&&!(a.mode&73))return 2}else return 2;return 0},yi:function(a){var b=O.Jf(a,"x");return b?b:a.cf.lookup?0:2},Yg:function(a,b){try{return O.Bf(a,b),20}catch(c){}return O.Jf(a,"wx")},xg:function(a,b,c){try{var d=O.Bf(a,b)}catch(e){return e.ef}if(a=O.Jf(a,"wx"))return a;if(c){if(!O.kf(d.mode))return 54;if(O.wg(d)||O.If(d)===O.cwd())return 10}else if(O.kf(d.mode))return 31;return 0},zi:function(a,b){return a? -O.Mf(a.mode)?32:O.kf(a.mode)&&("r"!==O.th(b)||b&512)?31:O.Jf(a,O.th(b)):44},Qh:4096,Bi:function(a,b){b=b||O.Qh;for(a=a||0;a<=b;a++)if(!O.streams[a])return a;throw new O.af(33);},zf:function(a){return O.streams[a]},nh:function(a,b,c){O.Hg||(O.Hg=function(){},O.Hg.prototype={object:{get:function(){return this.node},set:function(g){this.node=g}}});var d=new O.Hg,e;for(e in a)d[e]=a[e];a=d;b=O.Bi(b,c);a.fd=b;return O.streams[b]=a},ai:function(a){O.streams[a]=null},$h:{open:function(a){a.df=O.ki(a.node.rdev).df; -a.df.open&&a.df.open(a)},tf:function(){throw new O.af(70);}},Wg:function(a){return a>>8},oj:function(a){return a&255},Of:function(a,b){return a<<8|b},dh:function(a,b){O.ph[a]={df:b}},ki:function(a){return O.ph[a]},wh:function(a){var b=[];for(a=[a];a.length;){var c=a.pop();b.push(c);a.push.apply(a,c.mg)}return b},Kh:function(a,b){function c(k){O.Cg--;return b(k)}function d(k){if(k){if(!d.gi)return d.gi=!0,c(k)}else++g>=e.length&&c(null)}"function"===typeof a&&(b=a,a=!1);O.Cg++;1b)throw new O.af(28);var c;"string"===typeof a?c=O.ff(a,{wf:!0}).node:c=a;if(!c.cf.nf)throw new O.af(63);if(O.kf(c.mode))throw new O.af(31);if(!O.isFile(c.mode))throw new O.af(28);if(a=O.Jf(c,"w"))throw new O.af(a); -c.cf.nf(c,{size:b,timestamp:Date.now()})},fj:function(a,b){a=O.zf(a);if(!a)throw new O.af(8);if(0===(a.flags&2097155))throw new O.af(28);O.truncate(a.node,b)},Aj:function(a,b,c){a=O.ff(a,{wf:!0}).node;a.cf.nf(a,{timestamp:Math.max(b,c)})},open:function(a,b,c,d,e){if(""===a)throw new O.af(44);b="string"===typeof b?O.Dh(b):b;c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;if("object"===typeof a)var g=a;else{a=Pb(a);try{g=O.ff(a,{wf:!(b&131072)}).node}catch(m){}}var k=!1;if(b&64)if(g){if(b&128)throw new O.af(20); -}else g=O.Ff(a,c,0),k=!0;if(!g)throw new O.af(44);O.hg(g.mode)&&(b&=-513);if(b&65536&&!O.kf(g.mode))throw new O.af(54);if(!k&&(c=O.zi(g,b)))throw new O.af(c);b&512&&O.truncate(g,0);b&=-131713;d=O.nh({node:g,path:O.If(g),flags:b,seekable:!0,position:0,df:g.df,Wi:[],error:!1},d,e);d.df.open&&d.df.open(d);!f.logReadFiles||b&1||(O.$g||(O.$g={}),a in O.$g||(O.$g[a]=1,u("FS.trackingDelegate error on read file: "+a)));try{O.mf.onOpenFile&&(e=0,1!==(b&2097155)&&(e|=O.Mh.Gh.Rh),0!==(b&2097155)&&(e|=O.Mh.Gh.Sh), -O.mf.onOpenFile(a,e))}catch(m){u("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+m.message)}return d},close:function(a){if(O.ig(a))throw new O.af(8);a.Lf&&(a.Lf=null);try{a.df.close&&a.df.close(a)}catch(b){throw b;}finally{O.ai(a.fd)}a.fd=null},ig:function(a){return null===a.fd},tf:function(a,b,c){if(O.ig(a))throw new O.af(8);if(!a.seekable||!a.df.tf)throw new O.af(70);if(0!=c&&1!=c&&2!=c)throw new O.af(28);a.position=a.df.tf(a,b,c);a.Wi=[];return a.position},read:function(a, -b,c,d,e){if(0>d||0>e)throw new O.af(28);if(O.ig(a))throw new O.af(8);if(1===(a.flags&2097155))throw new O.af(8);if(O.kf(a.node.mode))throw new O.af(31);if(!a.df.read)throw new O.af(28);var g="undefined"!==typeof e;if(!g)e=a.position;else if(!a.seekable)throw new O.af(70);b=a.df.read(a,b,c,d,e);g||(a.position+=b);return b},write:function(a,b,c,d,e,g){if(0>d||0>e)throw new O.af(28);if(O.ig(a))throw new O.af(8);if(0===(a.flags&2097155))throw new O.af(8);if(O.kf(a.node.mode))throw new O.af(31);if(!a.df.write)throw new O.af(28); -a.seekable&&a.flags&1024&&O.tf(a,0,2);var k="undefined"!==typeof e;if(!k)e=a.position;else if(!a.seekable)throw new O.af(70);b=a.df.write(a,b,c,d,e,g);k||(a.position+=b);try{if(a.path&&O.mf.onWriteToFile)O.mf.onWriteToFile(a.path)}catch(m){u("FS.trackingDelegate['onWriteToFile']('"+a.path+"') threw an exception: "+m.message)}return b},fg:function(a,b,c){if(O.ig(a))throw new O.af(8);if(0>b||0>=c)throw new O.af(28);if(0===(a.flags&2097155))throw new O.af(8);if(!O.isFile(a.node.mode)&&!O.kf(a.node.mode))throw new O.af(43); -if(!a.df.fg)throw new O.af(138);a.df.fg(a,b,c)},Wf:function(a,b,c,d,e,g){if(0!==(e&2)&&0===(g&2)&&2!==(a.flags&2097155))throw new O.af(2);if(1===(a.flags&2097155))throw new O.af(2);if(!a.df.Wf)throw new O.af(43);return a.df.Wf(a,b,c,d,e,g)},Xf:function(a,b,c,d,e){return a&&a.df.Xf?a.df.Xf(a,b,c,d,e):0},sj:function(){return 0},Uf:function(a,b,c){if(!a.df.Uf)throw new O.af(59);return a.df.Uf(a,b,c)},readFile:function(a,b){b=b||{};b.flags=b.flags||"r";b.encoding=b.encoding||"binary";if("utf8"!==b.encoding&& -"binary"!==b.encoding)throw Error('Invalid encoding type "'+b.encoding+'"');var c,d=O.open(a,b.flags);a=O.stat(a).size;var e=new Uint8Array(a);O.read(d,e,0,a,0);"utf8"===b.encoding?c=Ja(e,0):"binary"===b.encoding&&(c=e);O.close(d);return c},writeFile:function(a,b,c){c=c||{};c.flags=c.flags||"w";a=O.open(a,c.flags,c.mode);if("string"===typeof b){var d=new Uint8Array(Ka(b)+1);b=Ia(b,d,0,d.length);O.write(a,d,0,b,void 0,c.Zh)}else if(ArrayBuffer.isView(b))O.write(a,b,0,b.byteLength,void 0,c.Zh);else throw Error("Unsupported data type"); -O.close(a)},cwd:function(){return O.oh},chdir:function(a){a=O.ff(a,{wf:!0});if(null===a.node)throw new O.af(44);if(!O.kf(a.node.mode))throw new O.af(54);var b=O.Jf(a.node,"x");if(b)throw new O.af(b);O.oh=a.path},ci:function(){O.mkdir("/tmp");O.mkdir("/home");O.mkdir("/home/web_user")},bi:function(){O.mkdir("/dev");O.dh(O.Of(1,3),{read:function(){return 0},write:function(b,c,d,e){return e}});O.yg("/dev/null",O.Of(1,3));Xb(O.Of(5,0),$b);Xb(O.Of(6,0),dc);O.yg("/dev/tty",O.Of(5,0));O.yg("/dev/tty1",O.Of(6, -0));var a=Tb();O.Hf("/dev","random",a);O.Hf("/dev","urandom",a);O.mkdir("/dev/shm");O.mkdir("/dev/shm/tmp")},ei:function(){O.mkdir("/proc");O.mkdir("/proc/self");O.mkdir("/proc/self/fd");O.jf({jf:function(){var a=O.createNode("/proc/self","fd",16895,73);a.cf={lookup:function(b,c){var d=O.zf(+c);if(!d)throw new O.af(8);b={parent:null,jf:{Eh:"fake"},cf:{readlink:function(){return d.path}}};return b.parent=b}};return a}},{},"/proc/self/fd")},fi:function(){f.stdin?O.Hf("/dev","stdin",f.stdin):O.symlink("/dev/tty", -"/dev/stdin");f.stdout?O.Hf("/dev","stdout",null,f.stdout):O.symlink("/dev/tty","/dev/stdout");f.stderr?O.Hf("/dev","stderr",null,f.stderr):O.symlink("/dev/tty1","/dev/stderr");O.open("/dev/stdin","r");O.open("/dev/stdout","w");O.open("/dev/stderr","w")},rh:function(){O.af||(O.af=function(a,b){this.node=b;this.Ki=function(c){this.ef=c};this.Ki(a);this.message="FS error"},O.af.prototype=Error(),O.af.prototype.constructor=O.af,[44].forEach(function(a){O.Qg[a]=new O.af(a);O.Qg[a].stack=""}))}, -Ni:function(){O.rh();O.Cf=Array(4096);O.jf(P,{},"/");O.ci();O.bi();O.ei();O.ii={MEMFS:P}},gg:function(a,b,c){O.gg.Tg=!0;O.rh();f.stdin=a||f.stdin;f.stdout=b||f.stdout;f.stderr=c||f.stderr;O.fi()},quit:function(){O.gg.Tg=!1;var a=f._fflush;a&&a(0);for(a=0;athis.length-1||0>q)){var t=q%this.chunkSize;return this.yh(q/this.chunkSize|0)[t]}};g.prototype.Wh=function(q){this.yh=q};g.prototype.kh=function(){var q=new XMLHttpRequest;q.open("HEAD",c,!1);q.send(null);if(!(200<=q.status&&300>q.status||304===q.status))throw Error("Couldn't load "+ -c+". Status: "+q.status);var t=Number(q.getResponseHeader("Content-length")),w,B=(w=q.getResponseHeader("Accept-Ranges"))&&"bytes"===w;q=(w=q.getResponseHeader("Content-Encoding"))&&"gzip"===w;var p=1048576;B||(p=t);var x=this;x.Wh(function(z){var I=z*p,W=(z+1)*p-1;W=Math.min(W,t-1);if("undefined"===typeof x.Sf[z]){var db=x.Sf;if(I>W)throw Error("invalid range ("+I+", "+W+") or no bytes requested!");if(W>t-1)throw Error("only "+t+" bytes available! programmer error!");var K=new XMLHttpRequest;K.open("GET", -c,!1);t!==p&&K.setRequestHeader("Range","bytes="+I+"-"+W);"undefined"!=typeof Uint8Array&&(K.responseType="arraybuffer");K.overrideMimeType&&K.overrideMimeType("text/plain; charset=x-user-defined");K.send(null);if(!(200<=K.status&&300>K.status||304===K.status))throw Error("Couldn't load "+c+". Status: "+K.status);I=void 0!==K.response?new Uint8Array(K.response||[]):Zb(K.responseText||"",!0);db[z]=I}if("undefined"===typeof x.Sf[z])throw Error("doXHR failed!");return x.Sf[z]});if(q||!t)p=t=1,p=t=this.yh(0).length, -ya("LazyFiles on gzip forces download of the whole file when length is accessed");this.Uh=t;this.Th=p;this.Vg=!0};if("undefined"!==typeof XMLHttpRequest){if(!la)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var k=new g;Object.defineProperties(k,{length:{get:function(){this.Vg||this.kh();return this.Uh}},chunkSize:{get:function(){this.Vg||this.kh();return this.Th}}});k={Ug:!1,bf:k}}else k={Ug:!1,url:c};var m=O.di(a,b,k,d, -e);k.bf?m.bf=k.bf:k.url&&(m.bf=null,m.url=k.url);Object.defineProperties(m,{gf:{get:function(){return this.bf.length}}});var r={};Object.keys(m.df).forEach(function(q){var t=m.df[q];r[q]=function(){if(!O.uh(m))throw new O.af(29);return t.apply(null,arguments)}});r.read=function(q,t,w,B,p){if(!O.uh(m))throw new O.af(29);q=q.node.bf;if(p>=q.length)return 0;B=Math.min(q.length-p,B);if(q.slice)for(var x=0;x>2]=d.dev;E[c+4>>2]=0;E[c+8>>2]=d.ino;E[c+12>>2]=d.mode;E[c+16>>2]=d.nlink;E[c+20>>2]=d.uid;E[c+24>>2]=d.gid;E[c+28>>2]=d.rdev;E[c+32>>2]=0;L=[d.size>>>0,(J=d.size,1<=+Math.abs(J)?0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[c+40>>2]=L[0];E[c+44>>2]=L[1];E[c+48>>2]=4096;E[c+52>>2]=d.blocks;E[c+56>>2]=d.atime.getTime()/1E3|0;E[c+60>> -2]=0;E[c+64>>2]=d.mtime.getTime()/1E3|0;E[c+68>>2]=0;E[c+72>>2]=d.ctime.getTime()/1E3|0;E[c+76>>2]=0;L=[d.ino>>>0,(J=d.ino,1<=+Math.abs(J)?0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[c+80>>2]=L[0];E[c+84>>2]=L[1];return 0}var ic=void 0;function Q(){ic+=4;return E[ic-4>>2]}function jc(a){a=O.zf(a);if(!a)throw new O.af(8);return a} -function kc(a,b,c,d,e){if(l)return N(3,1,a,b,c,d,e);try{e=0;for(var g=b?E[b>>2]:0,k=b?E[b+4>>2]:0,m=c?E[c>>2]:0,r=c?E[c+4>>2]:0,q=d?E[d>>2]:0,t=d?E[d+4>>2]:0,w=0,B=0,p=0,x=0,z=0,I=0,W=(b?E[b>>2]:0)|(c?E[c>>2]:0)|(d?E[d>>2]:0),db=(b?E[b+4>>2]:0)|(c?E[c+4>>2]:0)|(d?E[d+4>>2]:0),K=0;KK?W&Y:db&Y){var ia=O.zf(K);if(!ia)throw new O.af(8);var na=5;ia.df.Zf&&(na=ia.df.Zf(ia));na&1&&(32>K?g&Y:k&Y)&&(32>K?w|=Y:B|=Y,e++);na&4&&(32>K?m&Y:r&Y)&&(32>K?p|=Y:x|=Y,e++);na&2&&(32>K?q&Y: -t&Y)&&(32>K?z|=Y:I|=Y,e++)}}b&&(E[b>>2]=w,E[b+4>>2]=B);c&&(E[c>>2]=p,E[c+4>>2]=x);d&&(E[d>>2]=z,E[d+4>>2]=I);return e}catch(ua){return"undefined"!==typeof O&&ua instanceof O.af||n(ua),-ua.ef}}function lc(a,b){if(l)return N(4,1,a,b);try{a=C(a);if(b&-8)var c=-28;else{var d;(d=O.ff(a,{wf:!0}).node)?(a="",b&4&&(a+="r"),b&2&&(a+="w"),b&1&&(a+="x"),c=a&&O.Jf(d,a)?-2:0):c=-44}return c}catch(e){return"undefined"!==typeof O&&e instanceof O.af||n(e),-e.ef}} -function mc(a,b,c){if(l)return N(5,1,a,b,c);ic=c;try{var d=jc(a);switch(b){case 0:var e=Q();return 0>e?-28:O.open(d.path,d.flags,0,e).fd;case 1:case 2:return 0;case 3:return d.flags;case 4:return e=Q(),d.flags|=e,0;case 12:return e=Q(),Qa[e+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return Eb(28),-1;default:return-28}}catch(g){return"undefined"!==typeof O&&g instanceof O.af||n(g),-g.ef}} -function nc(a,b){if(l)return N(6,1,a,b);try{var c=jc(a);return hc(O.stat,c.path,b)}catch(d){return"undefined"!==typeof O&&d instanceof O.af||n(d),-d.ef}} -function oc(a,b,c){if(l)return N(7,1,a,b,c);try{var d=jc(a);d.Lf||(d.Lf=O.readdir(d.path));a=0;for(var e=O.tf(d,0,1),g=Math.floor(e/280);g>>0,(J=m,1<=+Math.abs(J)?0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[b+a>>2]=L[0];E[b+a+4>>2]=L[1];L=[280*(g+1)>>>0,(J=280*(g+1),1<=+Math.abs(J)? -0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[b+a+8>>2]=L[0];E[b+a+12>>2]=L[1];Qa[b+a+16>>1]=280;y[b+a+18>>0]=r;Ia(k,v,b+a+19,256);a+=280;g+=1}O.tf(d,280*g,0);return a}catch(t){return"undefined"!==typeof O&&t instanceof O.af||n(t),-t.ef}}function pc(a,b){if(l)return N(8,1,a,b);try{return qc(b,0,136),E[b>>2]=1,E[b+4>>2]=2,E[b+8>>2]=3,E[b+12>>2]=4,0}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}} -function rc(a,b,c){if(l)return N(9,1,a,b,c);ic=c;try{var d=jc(a);switch(b){case 21509:case 21505:return d.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return d.tty?0:-59;case 21519:if(!d.tty)return-59;var e=Q();return E[e>>2]=0;case 21520:return d.tty?-28:-59;case 21531:return e=Q(),O.Uf(d,b,e);case 21523:return d.tty?0:-59;case 21524:return d.tty?0:-59;default:n("bad ioctl syscall "+b)}}catch(g){return"undefined"!==typeof O&&g instanceof O.af||n(g),-g.ef}} -function sc(a,b){if(l)return N(10,1,a,b);try{return a=C(a),hc(O.lstat,a,b)}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}}function tc(a,b){if(l)return N(11,1,a,b);try{return a=C(a),a=Pb(a),"/"===a[a.length-1]&&(a=a.substr(0,a.length-1)),O.mkdir(a,b,0),0}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}} -function uc(a,b,c,d,e,g){if(l)return N(12,1,a,b,c,d,e,g);try{a:{g<<=12;var k=!1;if(0!==(d&16)&&0!==a%16384)var m=-28;else{if(0!==(d&32)){var r=vc(16384,b);if(!r){m=-48;break a}qc(r,0,b);k=!0}else{var q=O.zf(e);if(!q){m=-8;break a}var t=O.Wf(q,a,b,g,c,d);r=t.Hi;k=t.Jg}fc[r]={xi:r,ui:b,Jg:k,fd:e,Gi:c,flags:d,offset:g};m=r}}return m}catch(w){return"undefined"!==typeof O&&w instanceof O.af||n(w),-w.ef}} -function wc(a,b){if(l)return N(13,1,a,b);try{if(-1===(a|0)||0===b)var c=-28;else{var d=fc[a];if(d&&b===d.ui){var e=O.zf(d.fd);if(d.Gi&2){var g=d.flags,k=d.offset,m=v.slice(a,a+b);O.Xf(e,m,k,b,g)}fc[a]=null;d.Jg&&zb(d.xi)}c=0}return c}catch(r){return"undefined"!==typeof O&&r instanceof O.af||n(r),-r.ef}}function xc(a,b,c){if(l)return N(14,1,a,b,c);ic=c;try{var d=C(a),e=Q();return O.open(d,b,e).fd}catch(g){return"undefined"!==typeof O&&g instanceof O.af||n(g),-g.ef}} -function yc(a,b,c){if(l)return N(15,1,a,b,c);try{for(var d=c=0;d>1],k=32,m=O.zf(E[e>>2]);m&&(k=5,m.df.Zf&&(k=m.df.Zf(m)));(k&=g|24)&&c++;Qa[e+6>>1]=k}return c}catch(r){return"undefined"!==typeof O&&r instanceof O.af||n(r),-r.ef}}function zc(a,b,c,d){if(l)return N(16,1,a,b,c,d);try{return d&&(E[d>>2]=-1,E[d+4>>2]=-1,E[d+8>>2]=-1,E[d+12>>2]=-1),0}catch(e){return"undefined"!==typeof O&&e instanceof O.af||n(e),-e.ef}} -function Ac(a,b,c){if(l)return N(17,1,a,b,c);try{var d=jc(a);return O.read(d,y,b,c)}catch(e){return"undefined"!==typeof O&&e instanceof O.af||n(e),-e.ef}}function Bc(a,b){if(l)return N(18,1,a,b);try{return a=C(a),b=C(b),O.rename(a,b),0}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}}function Cc(a){if(l)return N(19,1,a);try{return a=C(a),O.rmdir(a),0}catch(b){return"undefined"!==typeof O&&b instanceof O.af||n(b),-b.ef}} -var R={jf:function(){f.websocket=f.websocket&&"object"===typeof f.websocket?f.websocket:{};f.websocket.Ig={};f.websocket.on=function(a,b){"function"===typeof b&&(this.Ig[a]=b);return this};f.websocket.emit=function(a,b){"function"===typeof this.Ig[a]&&this.Ig[a].call(this,b)};return O.createNode(null,"/",16895,0)},createSocket:function(a,b,c){b&=-526337;c&&assert(1==b==(6==c));a={family:a,type:b,protocol:c,lf:null,error:null,ng:{},pending:[],ag:[],pf:R.qf};b=R.zg();c=O.createNode(R.root,b,49152,0); -c.bg=a;b=O.nh({path:b,node:c,flags:O.Dh("r+"),seekable:!1,df:R.df});a.stream=b;return a},mi:function(a){return(a=O.zf(a))&&O.isSocket(a.node.mode)?a.node.bg:null},df:{Zf:function(a){a=a.node.bg;return a.pf.Zf(a)},Uf:function(a,b,c){a=a.node.bg;return a.pf.Uf(a,b,c)},read:function(a,b,c,d){a=a.node.bg;d=a.pf.bh(a,d);if(!d)return 0;b.set(d.buffer,c);return d.buffer.length},write:function(a,b,c,d){a=a.node.bg;return a.pf.fh(a,b,c,d)},close:function(a){a=a.node.bg;a.pf.close(a)}},zg:function(){R.zg.current|| -(R.zg.current=0);return"socket["+R.zg.current++ +"]"},qf:{tg:function(a,b,c){if("object"===typeof b){var d=b;c=b=null}if(d)if(d._socket)b=d._socket.remoteAddress,c=d._socket.remotePort;else{c=/ws[s]?:\/\/([^:]+):(\d+)/.exec(d.url);if(!c)throw Error("WebSocket URL must be in the format ws(s)://address:port");b=c[1];c=parseInt(c[2],10)}else try{var e=f.websocket&&"object"===typeof f.websocket,g="ws:#".replace("#","//");e&&"string"===typeof f.websocket.url&&(g=f.websocket.url);if("ws://"===g||"wss://"=== -g){var k=b.split("/");g=g+k[0]+":"+c+"/"+k.slice(1).join("/")}k="binary";e&&"string"===typeof f.websocket.subprotocol&&(k=f.websocket.subprotocol);var m=void 0;"null"!==k&&(k=k.replace(/^ +| +$/g,"").split(/ *, */),m=h?{protocol:k.toString()}:k);e&&null===f.websocket.subprotocol&&(m=void 0);d=new (h?require("ws"):WebSocket)(g,m);d.binaryType="arraybuffer"}catch(r){throw new O.af(23);}b={hf:b,port:c,socket:d,ug:[]};R.qf.jh(a,b);R.qf.ni(a,b);2===a.type&&"undefined"!==typeof a.Qf&&b.ug.push(new Uint8Array([255, -255,255,255,112,111,114,116,(a.Qf&65280)>>8,a.Qf&255]));return b},vg:function(a,b,c){return a.ng[b+":"+c]},jh:function(a,b){a.ng[b.hf+":"+b.port]=b},Hh:function(a,b){delete a.ng[b.hf+":"+b.port]},ni:function(a,b){function c(){f.websocket.emit("open",a.stream.fd);try{for(var g=b.ug.shift();g;)b.socket.send(g),g=b.ug.shift()}catch(k){b.socket.close()}}function d(g){if("string"===typeof g)g=(new TextEncoder).encode(g);else{assert(void 0!==g.byteLength);if(0==g.byteLength)return;g=new Uint8Array(g)}var k= -e;e=!1;k&&10===g.length&&255===g[0]&&255===g[1]&&255===g[2]&&255===g[3]&&112===g[4]&&111===g[5]&&114===g[6]&&116===g[7]?(g=g[8]<<8|g[9],R.qf.Hh(a,b),b.port=g,R.qf.jh(a,b)):(a.ag.push({hf:b.hf,port:b.port,data:g}),f.websocket.emit("message",a.stream.fd))}var e=!0;h?(b.socket.on("open",c),b.socket.on("message",function(g,k){k.Yi&&d((new Uint8Array(g)).buffer)}),b.socket.on("close",function(){f.websocket.emit("close",a.stream.fd)}),b.socket.on("error",function(){a.error=14;f.websocket.emit("error",[a.stream.fd, -a.error,"ECONNREFUSED: Connection refused"])})):(b.socket.onopen=c,b.socket.onclose=function(){f.websocket.emit("close",a.stream.fd)},b.socket.onmessage=function(g){d(g.data)},b.socket.onerror=function(){a.error=14;f.websocket.emit("error",[a.stream.fd,a.error,"ECONNREFUSED: Connection refused"])})},Zf:function(a){if(1===a.type&&a.lf)return a.pending.length?65:0;var b=0,c=1===a.type?R.qf.vg(a,a.sf,a.vf):null;if(a.ag.length||!c||c&&c.socket.readyState===c.socket.CLOSING||c&&c.socket.readyState===c.socket.CLOSED)b|= -65;if(!c||c&&c.socket.readyState===c.socket.OPEN)b|=4;if(c&&c.socket.readyState===c.socket.CLOSING||c&&c.socket.readyState===c.socket.CLOSED)b|=16;return b},Uf:function(a,b,c){switch(b){case 21531:return b=0,a.ag.length&&(b=a.ag[0].data.length),E[c>>2]=b,0;default:return 28}},close:function(a){if(a.lf){try{a.lf.close()}catch(e){}a.lf=null}for(var b=Object.keys(a.ng),c=0;cb;b++){var c=Number(a[b]);if(isNaN(c))return null;a[b]=c}return(a[0]|a[1]<<8|a[2]<<16|a[3]<<24)>>>0} -function Ec(a){var b,c,d=[];if(!/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i.test(a))return null;if("::"===a)return[0,0,0,0,0,0,0,0];a=0===a.indexOf("::")?a.replace("::","Z:"):a.replace("::",":Z:");0b,"exceeded max address mappings of 65535"),b="172.29."+(b&255)+"."+(b&65280),Ic[b]=a,Hc[a]=b);return b}function Kc(a){return Ic[a]?Ic[a]:null}function Lc(a){return(a&255)+"."+(a>>8&255)+"."+(a>>16&255)+"."+(a>>24&255)} -function Mc(a){var b="",c,d=0,e=0,g=0,k=0;a=[a[0]&65535,a[0]>>16,a[1]&65535,a[1]>>16,a[2]&65535,a[2]>>16,a[3]&65535,a[3]>>16];var m=!0;for(c=0;5>c;c++)if(0!==a[c]){m=!1;break}if(m){c=Lc(a[6]|a[7]<<16);if(-1===a[5])return"::ffff:"+c;if(0===a[5])return"0.0.0.0"===c&&(c=""),"0.0.0.1"===c&&(c="1"),"::"+c}for(c=0;8>c;c++)0===a[c]&&(1d&&(d=k,g=c-d+1);for(c=0;8>c;c++)1=g&&cc?":":"");return b} -function Oc(a,b){var c=Qa[a>>1],d=Nc(Ra[a+2>>1]);switch(c){case 2:if(16!==b)return{ef:28};a=E[a+4>>2];a=Lc(a);break;case 10:if(28!==b)return{ef:28};a=[E[a+8>>2],E[a+12>>2],E[a+16>>2],E[a+20>>2]];a=Mc(a);break;default:return{ef:5}}return{family:c,hf:a,port:d}} -function Pc(a,b,c,d){switch(b){case 2:c=Dc(c);Qa[a>>1]=b;E[a+4>>2]=c;Qa[a+2>>1]=Fc(d);break;case 10:c=Ec(c);E[a>>2]=b;E[a+8>>2]=c[0];E[a+12>>2]=c[1];E[a+16>>2]=c[2];E[a+20>>2]=c[3];Qa[a+2>>1]=Fc(d);E[a+4>>2]=0;E[a+24>>2]=0;break;default:return{ef:5}}return{}} -function Qc(a,b){if(l)return N(20,1,a,b);try{ic=b;b=function(){var aa=R.mi(Q());if(!aa)throw new O.af(8);return aa};var c=function(aa){var pd=Q(),ge=Q();if(aa&&0===pd)return null;aa=Oc(pd,ge);if(aa.ef)throw new O.af(aa.ef);aa.hf=Kc(aa.hf)||aa.hf;return aa};switch(a){case 1:var d=Q(),e=Q(),g=Q(),k=R.createSocket(d,e,g);return k.stream.fd;case 2:k=b();var m=c();k.pf.bind(k,m.hf,m.port);return 0;case 3:return k=b(),m=c(),k.pf.connect(k,m.hf,m.port),0;case 4:k=b();var r=Q();k.pf.listen(k,r);return 0; -case 5:k=b();var q=Q();Q();var t=k.pf.accept(k);q&&Pc(q,t.family,Jc(t.sf),t.vf);return t.stream.fd;case 6:return k=b(),q=Q(),Q(),Pc(q,k.family,Jc(k.Bg||"0.0.0.0"),k.Qf),0;case 7:k=b();q=Q();Q();if(!k.sf)return-53;Pc(q,k.family,Jc(k.sf),k.vf);return 0;case 11:k=b();var w=Q(),B=Q();Q();var p=c(!0);return p?k.pf.fh(k,y,w,B,p.hf,p.port):O.write(k.stream,y,w,B);case 12:k=b();var x=Q(),z=Q();Q();q=Q();Q();var I=k.pf.bh(k,z);if(!I)return 0;q&&Pc(q,k.family,Jc(I.hf),I.port);v.set(I.buffer,x);return I.buffer.byteLength; -case 14:return-50;case 15:k=b();var W=Q(),db=Q(),K=Q(),Y=Q();return 1===W&&4===db?(E[K>>2]=k.error,E[Y>>2]=4,k.error=null,0):-50;case 16:k=b();w=Q();Q();var ia=E[w+8>>2],na=E[w+12>>2],ua=E[w>>2],he=E[w+4>>2];if(ua){m=Oc(ua,he);if(m.ef)return-m.ef;var ie=m.port;q=Kc(m.hf)||m.hf}for(var Oa=0,X=0;X>2];var qd=new Uint8Array(Oa);for(X=B=0;X>2],bc=E[ia+(8*X+4)>>2];for(x=0;x>0]}return k.pf.fh(k,qd,0,Oa,q,ie);case 17:k=b();w=Q();Q(); -ia=E[w+8>>2];na=E[w+12>>2];for(X=Oa=0;X>2];I=k.pf.bh(k,Oa);if(!I)return 0;(ua=E[w>>2])&&Pc(ua,k.family,Jc(I.hf),I.port);k=0;var cc=I.buffer.byteLength;for(X=0;0>2],bc=E[ia+(8*X+4)>>2])B=Math.min(bc,cc),x=I.buffer.subarray(k,k+B),v.set(x,ac+k),k+=B,cc-=B;return k;default:return-52}}catch(aa){return"undefined"!==typeof O&&aa instanceof O.af||n(aa),-aa.ef}} -function Rc(a,b){if(l)return N(21,1,a,b);try{return a=C(a),hc(O.stat,a,b)}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}}function Sc(a){if(l)return N(22,1,a);try{return a=C(a),O.unlink(a),0}catch(b){return"undefined"!==typeof O&&b instanceof O.af||n(b),-b.ef}}function Tc(){void 0===Tc.start&&(Tc.start=Date.now());return 1E3*(Date.now()-Tc.start)|0} -function Uc(){h||la||(za||(za={}),za["Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread"]||(za["Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread"]=1,u("Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread")))} -function Vc(a,b,c){if(0>=a||a>y.length||a&1)return-28;if(ka){if(Atomics.load(E,a>>2)!=b)return-6;var d=performance.now();c=d+c;for(Atomics.exchange(E,M.Vf>>2,a);;){d=performance.now();if(d>c)return Atomics.exchange(E,M.Vf>>2,0),-73;d=Atomics.exchange(E,M.Vf>>2,0);if(0==d)break;Ab();if(Atomics.load(E,a>>2)!=b)return-6;Atomics.exchange(E,M.Vf>>2,a)}return 0}a=Atomics.wait(E,a>>2,b,c);if("timed-out"===a)return-73;if("not-equal"===a)return-6;if("ok"===a)return 0;throw"Atomics.wait returned an unexpected value "+ -a;}function Wc(a){var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=function(c,d){b.vertexAttribDivisorANGLE(c,d)},a.drawArraysInstanced=function(c,d,e,g){b.drawArraysInstancedANGLE(c,d,e,g)},a.drawElementsInstanced=function(c,d,e,g,k){b.drawElementsInstancedANGLE(c,d,e,g,k)})} -function Xc(a){var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=function(){return b.createVertexArrayOES()},a.deleteVertexArray=function(c){b.deleteVertexArrayOES(c)},a.bindVertexArray=function(c){b.bindVertexArrayOES(c)},a.isVertexArray=function(c){return b.isVertexArrayOES(c)})}function Yc(a){var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=function(c,d){b.drawBuffersWEBGL(c,d)})}var Zc=1,$c=[],S=[],ad=[],bd=[],cd=[],T=[],dd=[],ed=[],fd=[],gd={},hd={},id=4; -function U(a){jd||(jd=a)}function kd(a){for(var b=Zc++,c=a.length;c>2]=k}}function rd(a,b,c,d,e,g,k,m){b=S[b];if(a=V[a](b,c))d=m&&Ia(a.name,v,m,d),e&&(E[e>>2]=d),g&&(E[g>>2]=a.size),k&&(E[k>>2]=a.type)}function sd(a,b){F[a>>2]=b;F[a+4>>2]=(b-F[a>>2])/4294967296} -function td(a,b,c){if(b){var d=void 0;switch(a){case 36346:d=1;break;case 36344:0!=c&&1!=c&&U(1280);return;case 36345:d=0;break;case 34466:var e=V.getParameter(34467);d=e?e.length:0}if(void 0===d)switch(e=V.getParameter(a),typeof e){case "number":d=e;break;case "boolean":d=e?1:0;break;case "string":U(1280);return;case "object":if(null===e)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 34068:d=0;break;default:U(1280);return}else{if(e instanceof Float32Array|| -e instanceof Uint32Array||e instanceof Int32Array||e instanceof Array){for(a=0;a>2]=e[a];break;case 2:G[b+4*a>>2]=e[a];break;case 4:y[b+a>>0]=e[a]?1:0}return}try{d=e.name|0}catch(g){U(1280);u("GL_INVALID_ENUM in glGet"+c+"v: Unknown object returned from WebGL getParameter("+a+")! (error: "+g+")");return}}break;default:U(1280);u("GL_INVALID_ENUM in glGet"+c+"v: Native code calling glGet"+c+"v("+a+") and it returns "+e+" of type "+typeof e+"!");return}switch(c){case 1:sd(b, -d);break;case 0:E[b>>2]=d;break;case 2:G[b>>2]=d;break;case 4:y[b>>0]=d?1:0}}else U(1281)}function ud(a){var b=Ka(a)+1,c=Ma(b);Ia(a,v,c,b);return c}function vd(a,b,c,d){if(c)if(a=V.getUniform(S[a],T[b]),"number"==typeof a||"boolean"==typeof a)switch(d){case 0:E[c>>2]=a;break;case 2:G[c>>2]=a}else for(b=0;b>2]=a[b];break;case 2:G[c+4*b>>2]=a[b]}else U(1281)} -function wd(a,b,c,d){if(c)if(a=V.getVertexAttrib(a,b),34975==b)E[c>>2]=a&&a.name;else if("number"==typeof a||"boolean"==typeof a)switch(d){case 0:E[c>>2]=a;break;case 2:G[c>>2]=a;break;case 5:E[c>>2]=Math.fround(a)}else for(b=0;b>2]=a[b];break;case 2:G[c+4*b>>2]=a[b];break;case 5:E[c+4*b>>2]=Math.fround(a[b])}else U(1281)} -function xd(a,b,c,d,e){a-=5120;a=1==a?v:4==a?E:6==a?G:5==a||28922==a?F:Ra;var g=31-Math.clz32(a.BYTES_PER_ELEMENT),k=id;return a.subarray(e>>g,e+d*(c*({5:3,6:4,8:2,29502:3,29504:4}[b-6402]||1)*(1<>g)}var yd=[],zd=[];function N(a,b){for(var c=arguments.length-2,d=A(),e=Ha(8*c),g=e>>3,k=0;k>2]=b,E[d.sg+4>>2]=c);if(d.Fh||!d.aj)d.Fh&&(d=d.Fh),a=!1,d.rg&&d.rg.qg&&(a=d.rg.qg.getParameter(2978),a=0===a[0]&&0===a[1]&&a[2]===d.width&&a[3]===d.height),d.width=b,d.height=c,a&&d.rg.qg.viewport(0,0,b,c);else{if(d.sg){a=a?C(a):"";d=E[d.sg+8>>2];var e=A(),g=Ha(12),k=0;a&&(k=ud(a));E[g>>2]=k;E[g+4>>2]=b;E[g+8>>2]=c;Gd(0,d,657457152,0,k,g);D(e);return 1}return-4}return 0}function Hd(a,b,c){return l?N(23,1,a,b,c):Fd(a,b,c)} -var Id=["default","low-power","high-performance"],Jd={};function Kd(){if(!Ld){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:ha||"./this.program"},b;for(b in Jd)a[b]=Jd[b];var c=[];for(b in a)c.push(b+"="+a[b]);Ld=c}return Ld}var Ld; -function Md(a){if(l)return N(24,1,a);try{var b=jc(a);O.close(b);return 0}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),c.ef}}function Nd(a,b){if(l)return N(25,1,a,b);try{var c=jc(a);y[b>>0]=c.tty?2:O.kf(c.mode)?3:O.Mf(c.mode)?7:4;return 0}catch(d){return"undefined"!==typeof O&&d instanceof O.af||n(d),d.ef}} -function Od(a,b,c,d){if(l)return N(26,1,a,b,c,d);try{a:{for(var e=jc(a),g=a=0;g>2],m=O.read(e,y,E[b+8*g>>2],k,void 0);if(0>m){var r=-1;break a}a+=m;if(m>2]=r;return 0}catch(q){return"undefined"!==typeof O&&q instanceof O.af||n(q),q.ef}} -function Pd(a,b,c,d,e){if(l)return N(27,1,a,b,c,d,e);try{var g=jc(a);a=4294967296*c+(b>>>0);if(-9007199254740992>=a||9007199254740992<=a)return-61;O.tf(g,a,d);L=[g.position>>>0,(J=g.position,1<=+Math.abs(J)?0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[e>>2]=L[0];E[e+4>>2]=L[1];g.Lf&&0===a&&0===d&&(g.Lf=null);return 0}catch(k){return"undefined"!==typeof O&&k instanceof O.af||n(k),k.ef}} -function Qd(a,b,c,d){if(l)return N(28,1,a,b,c,d);try{a:{for(var e=jc(a),g=a=0;g>2],E[b+(8*g+4)>>2],void 0);if(0>k){var m=-1;break a}a+=k}m=a}E[d>>2]=m;return 0}catch(r){return"undefined"!==typeof O&&r instanceof O.af||n(r),r.ef}}var Rd={}; -function Sd(a){Sd.buffer||(Sd.buffer=Ma(256),Rd["0"]="Success",Rd["-1"]="Invalid value for 'ai_flags' field",Rd["-2"]="NAME or SERVICE is unknown",Rd["-3"]="Temporary failure in name resolution",Rd["-4"]="Non-recoverable failure in name res",Rd["-6"]="'ai_family' not supported",Rd["-7"]="'ai_socktype' not supported",Rd["-8"]="SERVICE not supported for 'ai_socktype'",Rd["-10"]="Memory allocation failure",Rd["-11"]="System error returned in 'errno'",Rd["-12"]="Argument buffer overflow");var b="Unknown error"; -a in Rd&&(255>2]=w;E[z+8>>2]=B;E[z+12>>2]=p;E[z+24>>2]=x;E[z+20>>2]=W;E[z+16>>2]=10===w?28:16;E[z+28>>2]=0;return z}if(l)return N(29,1,a,b,c,d);var g=0,k=0,m=0,r=0,q=0,t=0;c&&(m=E[c>>2],r=E[c+4>>2],q=E[c+8>>2],t=E[c+12>>2]);q&&!t&&(t=2===q?17:6);!q&&t&&(q=17===t?2:1);0===t&&(t=6);0===q&&(q=1);if(!a&&!b)return-2;if(m&-1088||0!==c&&E[c>>2]&2&&!a)return-1;if(m&32)return-2;if(0!== -q&&1!==q&&2!==q)return-7;if(0!==r&&2!==r&&10!==r)return-6;if(b&&(b=C(b),k=parseInt(b,10),isNaN(k)))return m&1024?-2:-8;if(!a)return 0===r&&(r=2),0===(m&1)&&(2===r?g=Ud(2130706433):g=[0,0,0,1]),a=e(r,q,t,null,g,k),E[d>>2]=a,0;a=C(a);g=Dc(a);if(null!==g)if(0===r||2===r)r=2;else if(10===r&&m&8)g=[0,0,Ud(65535),g],r=10;else return-2;else if(g=Ec(a),null!==g)if(0===r||10===r)r=10;else return-2;if(null!=g)return a=e(r,q,t,a,g,k),E[d>>2]=a,0;if(m&4)return-2;a=Jc(a);g=Dc(a);0===r?r=2:10===r&&(g=[0,0,Ud(65535), -g]);a=e(r,q,t,null,g,k);E[d>>2]=a;return 0} -function Bb(a){if(l)throw"Internal Error! spawnThread() can only ever be called from main application thread!";var b=M.li();if(void 0!==b.yf)throw"Internal error!";if(!a.$f)throw"Internal error, no pthread ptr!";M.Kf.push(b);for(var c=Ma(512),d=0;128>d;++d)E[c+4*d>>2]=0;var e=a.Rf+a.cg;d=M.Ef[a.$f]={worker:b,Rf:a.Rf,cg:a.cg,Kg:a.Kg,Lh:a.$f,threadInfoStruct:a.$f};var g=d.threadInfoStruct>>2;Atomics.store(F,g,0);Atomics.store(F,g+1,0);Atomics.store(F,g+2,0);Atomics.store(F,g+17,a.detached);Atomics.store(F, -g+26,c);Atomics.store(F,g+12,0);Atomics.store(F,g+10,d.threadInfoStruct);Atomics.store(F,g+11,42);Atomics.store(F,g+27,a.cg);Atomics.store(F,g+21,a.cg);Atomics.store(F,g+20,e);Atomics.store(F,g+29,e);Atomics.store(F,g+30,a.detached);Atomics.store(F,g+32,a.Ih);Atomics.store(F,g+33,a.Jh);c=Vd()+40;Atomics.store(F,g+44,c);b.yf=d;var k={cmd:"run",start_routine:a.Mi,arg:a.Tf,threadInfoStruct:a.$f,selfThreadId:a.$f,parentThreadId:a.Fi,stackBase:a.Rf,stackSize:a.cg};b.og=function(){k.time=performance.now(); -b.postMessage(k,a.Vi)};b.loaded&&(b.og(),delete b.og)}function Wd(){return pb|0}f._pthread_self=Wd; -function Xd(a,b){if(!a)return u("pthread_join attempted on a null thread pointer!"),71;if(l&&selfThreadId==a)return u("PThread "+a+" is attempting to join to itself!"),16;if(!l&&M.xf==a)return u("Main thread "+a+" is attempting to join to itself!"),16;if(E[a+12>>2]!==a)return u("pthread_join attempted on thread "+a+", which does not point to a valid thread, or does not exist anymore!"),71;if(Atomics.load(F,a+68>>2))return u("Attempted to join thread "+a+", which was already detached!"),28;for(Uc();;){var c= -Atomics.load(F,a>>2);if(1==c)return c=Atomics.load(F,a+4>>2),b&&(E[b>>2]=c),Atomics.store(F,a+68>>2,1),l?postMessage({cmd:"cleanupThread",thread:a}):vb(a),0;if(l&&threadInfoStruct&&!Atomics.load(F,threadInfoStruct+60>>2)&&2==Atomics.load(F,threadInfoStruct+0>>2))throw"Canceled!";l||Ab();Vc(a,c,l?100:1)}}function Yd(a){return 0===a%4&&(0!==a%100||0===a%400)}function Zd(a,b){for(var c=0,d=0;d<=b;c+=a[d++]);return c}var $d=[31,29,31,30,31,30,31,31,30,31,30,31],ae=[31,28,31,30,31,30,31,31,30,31,30,31]; -function be(a,b){for(a=new Date(a.getTime());0d-a.getDate())b-=d-a.getDate()+1,a.setDate(1),11>c?a.setMonth(c+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+b);break}}return a} -function ce(a){if(l)return N(30,1,a);switch(a){case 30:return 16384;case 85:return v.length/16384;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1; -case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1E3;case 89:return 700;case 71:return 256; -case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"===typeof navigator?navigator.hardwareConcurrency||1:1}Eb(28);return-1}function de(a,b,c,d){a||(a=this);this.parent=a;this.jf=a.jf;this.lg=null;this.id=O.Ai++;this.name=b;this.mode=c;this.cf={};this.df={};this.rdev=d} -Object.defineProperties(de.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}},ti:{get:function(){return O.kf(this.mode)}},Ug:{get:function(){return O.hg(this.mode)}}});O.Oh=de;O.Ni();for(var ec,V,ee=0;32>ee;++ee)nd.push(Array(ee));var fe=new Float32Array(288);for(ee=0;288>ee;++ee)yd[ee]=fe.subarray(0,ee+1);var je=new Int32Array(288); -for(ee=0;288>ee;++ee)zd[ee]=je.subarray(0,ee+1);var ke=[null,Hb,Jb,kc,lc,mc,nc,oc,pc,rc,sc,tc,uc,wc,xc,yc,zc,Ac,Bc,Cc,Qc,Rc,Sc,Hd,Md,Nd,Od,Pd,Qd,Td,ce];function Zb(a,b){var c=Array(Ka(a)+1);a=Ia(a,c,0,c.length);b&&(c.length=a);return c}l||Wa.push({vh:function(){le()}}); -var Fe={c:function(a,b,c,d){n("Assertion failed: "+C(a)+", at: "+[b?C(b):"unknown filename",c,d?C(d):"unknown function"])},K:function(a,b){a=me(a,b);if(!noExitRuntime)return postMessage({cmd:"exitProcess",returnCode:a}),a},W:function(a,b){return Gb(a,b)},aa:function(a,b){return Hb(a,b)},va:function(a,b){return Ib(a,b)},ua:function(a,b){return Nb(a,b)},Ma:kc,Ea:lc,u:mc,Na:nc,Ka:oc,Ha:pc,V:rc,Oa:sc,Pa:tc,ya:uc,Aa:function(){return 0},za:wc,Da:function(){return-63},Y:xc,La:yc,Ja:zc,Ca:Ac,wa:Bc,Ga:Cc, -Ia:function(){return 0},t:Qc,X:Rc,Fa:function(a){try{if(!a)return-21;var b={__size__:390,sysname:0,nodename:65,release:130,version:195,machine:260,domainname:325};Pa("Emscripten",a+b.sysname);Pa("emscripten",a+b.nodename);Pa("1.0",a+b.release);Pa("#1",a+b.version);Pa("x86-JS",a+b.machine);return 0}catch(c){return"undefined"!==typeof O&&c instanceof O.af||n(c),-c.ef}},Ba:Sc,pa:function(a,b){if(a==b)postMessage({cmd:"processQueuedMainThreadWork"});else if(l)postMessage({targetThread:a,cmd:"processThreadQueue"}); -else{a=(a=M.Ef[a])&&a.worker;if(!a)return;a.postMessage({cmd:"processThreadQueue"})}return 1},b:function(){n()},Qa:Tc,Ta:Gb,$:function(){n("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")},Ua:function(){n("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")},F:function(a,b,c){Cd.length=0;var d;for(c>>=2;d=v[b++];)(d=105>d)&&c&1&&c++,Cd.push(d?Sa[c++>> -1]:E[c]),++c;return mb[a].apply(null,Cd)},qa:Uc,I:function(){},A:Vc,p:tb,z:Db,Ed:function(a){V.activeTexture(a)},Dd:function(a,b){V.attachShader(S[a],dd[b])},ea:function(a,b){V.uf.beginQueryEXT(a,fd[b])},Cd:function(a,b,c){V.bindAttribLocation(S[a],b,C(c))},Bd:function(a,b){V.bindBuffer(a,$c[b])},Ad:function(a,b){V.bindFramebuffer(a,ad[b])},zd:function(a,b){V.bindRenderbuffer(a,bd[b])},yd:function(a,b){V.bindTexture(a,cd[b])},Md:function(a){V.bindVertexArray(ed[a])},xd:function(a,b,c,d){V.blendColor(a, -b,c,d)},wd:function(a){V.blendEquation(a)},vd:function(a,b){V.blendEquationSeparate(a,b)},ud:function(a,b){V.blendFunc(a,b)},td:function(a,b,c,d){V.blendFuncSeparate(a,b,c,d)},sd:function(a,b,c,d){V.bufferData(a,c?v.subarray(c,c+b):b,d)},rd:function(a,b,c,d){V.bufferSubData(a,b,v.subarray(d,d+c))},qd:function(a){return V.checkFramebufferStatus(a)},pd:function(a){V.clear(a)},od:function(a,b,c,d){V.clearColor(a,b,c,d)},nd:function(a){V.clearDepth(a)},md:function(a){V.clearStencil(a)},ld:function(a, -b,c,d){V.colorMask(!!a,!!b,!!c,!!d)},kd:function(a){V.compileShader(dd[a])},jd:function(a,b,c,d,e,g,k,m){V.compressedTexImage2D(a,b,c,d,e,g,m?v.subarray(m,m+k):null)},id:function(a,b,c,d,e,g,k,m,r){V.compressedTexSubImage2D(a,b,c,d,e,g,k,r?v.subarray(r,r+m):null)},hd:function(a,b,c,d,e,g,k,m){V.copyTexImage2D(a,b,c,d,e,g,k,m)},gd:function(a,b,c,d,e,g,k,m){V.copyTexSubImage2D(a,b,c,d,e,g,k,m)},fd:function(){var a=kd(S),b=V.createProgram();b.name=a;S[a]=b;return a},ed:function(a){var b=kd(dd);dd[b]= -V.createShader(a);return b},dd:function(a){V.cullFace(a)},cd:function(a,b){for(var c=0;c>2],e=$c[d];e&&(V.deleteBuffer(e),e.name=0,$c[d]=null)}},bd:function(a,b){for(var c=0;c>2],e=ad[d];e&&(V.deleteFramebuffer(e),e.name=0,ad[d]=null)}},ad:function(a){if(a){var b=S[a];b?(V.deleteProgram(b),b.name=0,S[a]=null,gd[a]=null):U(1281)}},ga:function(a,b){for(var c=0;c>2],e=fd[d];e&&(V.uf.deleteQueryEXT(e),fd[d]=null)}},$c:function(a,b){for(var c= -0;c>2],e=bd[d];e&&(V.deleteRenderbuffer(e),e.name=0,bd[d]=null)}},_c:function(a){if(a){var b=dd[a];b?(V.deleteShader(b),dd[a]=null):U(1281)}},Zc:function(a,b){for(var c=0;c>2],e=cd[d];e&&(V.deleteTexture(e),e.name=0,cd[d]=null)}},Ld:function(a,b){for(var c=0;c>2];V.deleteVertexArray(ed[d]);ed[d]=null}},Yc:function(a){V.depthFunc(a)},Xc:function(a){V.depthMask(!!a)},Wc:function(a,b){V.depthRange(a,b)},Vc:function(a,b){V.detachShader(S[a], -dd[b])},Uc:function(a){V.disable(a)},Tc:function(a){V.disableVertexAttribArray(a)},Sc:function(a,b,c){V.drawArrays(a,b,c)},Hd:function(a,b,c,d){V.drawArraysInstanced(a,b,c,d)},Id:function(a,b){for(var c=nd[a],d=0;d>2];V.drawBuffers(c)},Rc:function(a,b,c,d){V.drawElements(a,b,c,d)},Gd:function(a,b,c,d,e){V.drawElementsInstanced(a,b,c,d,e)},Qc:function(a){V.enable(a)},Pc:function(a){V.enableVertexAttribArray(a)},da:function(a){V.uf.endQueryEXT(a)},Oc:function(){V.finish()},Nc:function(){V.flush()}, -Mc:function(a,b,c,d){V.framebufferRenderbuffer(a,b,c,bd[d])},Lc:function(a,b,c,d,e){V.framebufferTexture2D(a,b,c,cd[d],e)},Kc:function(a){V.frontFace(a)},Jc:function(a,b){od(a,b,"createBuffer",$c)},Hc:function(a,b){od(a,b,"createFramebuffer",ad)},ha:function(a,b){for(var c=0;c>2]=0;break}var e=kd(fd);d.name=e;fd[e]=d;E[b+4*c>>2]=e}},Gc:function(a,b){od(a,b,"createRenderbuffer",bd)},Fc:function(a,b){od(a,b,"createTexture",cd)},Kd:function(a, -b){od(a,b,"createVertexArray",ed)},Ic:function(a){V.generateMipmap(a)},Ec:function(a,b,c,d,e,g,k){rd("getActiveAttrib",a,b,c,d,e,g,k)},Dc:function(a,b,c,d,e,g,k){rd("getActiveUniform",a,b,c,d,e,g,k)},Cc:function(a,b,c,d){a=V.getAttachedShaders(S[a]);var e=a.length;e>b&&(e=b);E[c>>2]=e;for(b=0;b>2]=dd.indexOf(a[b])},Bc:function(a,b){return V.getAttribLocation(S[a],C(b))},Ac:function(a,b){td(a,b,4)},zc:function(a,b,c){c?E[c>>2]=V.getBufferParameter(a,b):U(1281)},yc:function(){var a=V.getError()|| -jd;jd=0;return a},xc:function(a,b){td(a,b,2)},wc:function(a,b,c,d){a=V.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;E[d>>2]=a},vc:function(a,b){td(a,b,0)},tc:function(a,b,c,d){a=V.getProgramInfoLog(S[a]);null===a&&(a="(unknown error)");b=0>2]=b)},uc:function(a,b,c){if(c)if(a>=Zc)U(1281);else{var d=gd[a];if(d)if(35716==b)a=V.getProgramInfoLog(S[a]),null===a&&(a="(unknown error)"),E[c>>2]=a.length+1;else if(35719== -b)E[c>>2]=d.Xg;else if(35722==b){if(-1==d.jg){a=S[a];var e=V.getProgramParameter(a,35721);for(b=d.jg=0;b>2]=d.jg}else if(35381==b){if(-1==d.kg)for(a=S[a],e=V.getProgramParameter(a,35382),b=d.kg=0;b>2]=d.kg}else E[c>>2]=V.getProgramParameter(S[a],b);else U(1282)}else U(1281)},Od:function(a,b,c){if(c){a=V.uf.getQueryObjectEXT(fd[a],b);var d;"boolean"==typeof a? -d=a?1:0:d=a;sd(c,d)}else U(1281)},Qd:function(a,b,c){if(c){a=V.uf.getQueryObjectEXT(fd[a],b);var d;"boolean"==typeof a?d=a?1:0:d=a;E[c>>2]=d}else U(1281)},Nd:function(a,b,c){if(c){a=V.uf.getQueryObjectEXT(fd[a],b);var d;"boolean"==typeof a?d=a?1:0:d=a;sd(c,d)}else U(1281)},Pd:function(a,b,c){if(c){a=V.uf.getQueryObjectEXT(fd[a],b);var d;"boolean"==typeof a?d=a?1:0:d=a;E[c>>2]=d}else U(1281)},Rd:function(a,b,c){c?E[c>>2]=V.uf.getQueryEXT(a,b):U(1281)},sc:function(a,b,c){c?E[c>>2]=V.getRenderbufferParameter(a, -b):U(1281)},qc:function(a,b,c,d){a=V.getShaderInfoLog(dd[a]);null===a&&(a="(unknown error)");b=0>2]=b)},pc:function(a,b,c,d){a=V.getShaderPrecisionFormat(a,b);E[c>>2]=a.rangeMin;E[c+4>>2]=a.rangeMax;E[d>>2]=a.precision},oc:function(a,b,c,d){if(a=V.getShaderSource(dd[a]))b=0>2]=b)},rc:function(a,b,c){c?35716==b?(a=V.getShaderInfoLog(dd[a]),null===a&&(a="(unknown error)"),E[c>>2]=a?a.length+1:0):35720==b?(a=V.getShaderSource(dd[a]),E[c>>2]=a?a.length+ -1:0):E[c>>2]=V.getShaderParameter(dd[a],b):U(1281)},nc:function(a){if(hd[a])return hd[a];switch(a){case 7939:var b=V.getSupportedExtensions()||[];b=b.concat(b.map(function(d){return"GL_"+d}));b=ud(b.join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=V.getParameter(a))||U(1280);b=ud(b);break;case 7938:b=ud("OpenGL ES 2.0 ("+V.getParameter(7938)+")");break;case 35724:b=V.getParameter(35724);var c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"), -b="OpenGL ES GLSL ES "+c[1]+" ("+b+")");b=ud(b);break;default:return U(1280),0}return hd[a]=b},mc:function(a,b,c){c?G[c>>2]=V.getTexParameter(a,b):U(1281)},lc:function(a,b,c){c?E[c>>2]=V.getTexParameter(a,b):U(1281)},ic:function(a,b){b=C(b);var c=0;if("]"==b[b.length-1]){var d=b.lastIndexOf("[");c="]"!=b[d+1]?parseInt(b.slice(d+1)):0;b=b.slice(0,d)}return(a=gd[a]&&gd[a].Nh[b])&&0<=c&&c>2]=V.getVertexAttribOffset(a, -b):U(1281)},hc:function(a,b,c){wd(a,b,c,2)},gc:function(a,b,c){wd(a,b,c,5)},ec:function(a,b){V.hint(a,b)},dc:function(a){return(a=$c[a])?V.isBuffer(a):0},cc:function(a){return V.isEnabled(a)},bc:function(a){return(a=ad[a])?V.isFramebuffer(a):0},ac:function(a){return(a=S[a])?V.isProgram(a):0},fa:function(a){return(a=fd[a])?V.uf.isQueryEXT(a):0},$b:function(a){return(a=bd[a])?V.isRenderbuffer(a):0},_b:function(a){return(a=dd[a])?V.isShader(a):0},Zb:function(a){return(a=cd[a])?V.isTexture(a):0},Jd:function(a){return(a= -ed[a])?V.isVertexArray(a):0},Yb:function(a){V.lineWidth(a)},Xb:function(a){V.linkProgram(S[a]);var b=S[a];a=gd[a]={Nh:{},Xg:0,jg:-1,kg:-1};for(var c=a.Nh,d=V.getProgramParameter(b,35718),e=0;e>2]:-1;e+=C(E[c+4*g>>2],0>k?void 0:k)}V.shaderSource(dd[a],e)},Nb:function(a, -b,c){V.stencilFunc(a,b,c)},Mb:function(a,b,c,d){V.stencilFuncSeparate(a,b,c,d)},Lb:function(a){V.stencilMask(a)},Kb:function(a,b){V.stencilMaskSeparate(a,b)},Jb:function(a,b,c){V.stencilOp(a,b,c)},Ib:function(a,b,c,d){V.stencilOpSeparate(a,b,c,d)},Hb:function(a,b,c,d,e,g,k,m,r){V.texImage2D(a,b,c,d,e,g,k,m,r?xd(m,k,d,e,r):null)},Gb:function(a,b,c){V.texParameterf(a,b,c)},Fb:function(a,b,c){V.texParameterf(a,b,G[c>>2])},Eb:function(a,b,c){V.texParameteri(a,b,c)},Db:function(a,b,c){V.texParameteri(a, -b,E[c>>2])},Cb:function(a,b,c,d,e,g,k,m,r){var q=null;r&&(q=xd(m,k,e,g,r));V.texSubImage2D(a,b,c,d,e,g,k,m,q)},Bb:function(a,b){V.uniform1f(T[a],b)},Ab:function(a,b,c){if(288>=b)for(var d=yd[b-1],e=0;e>2];else d=G.subarray(c>>2,c+4*b>>2);V.uniform1fv(T[a],d)},zb:function(a,b){V.uniform1i(T[a],b)},yb:function(a,b,c){if(288>=b)for(var d=zd[b-1],e=0;e>2];else d=E.subarray(c>>2,c+4*b>>2);V.uniform1iv(T[a],d)},xb:function(a,b,c){V.uniform2f(T[a],b,c)},wb:function(a, -b,c){if(144>=b)for(var d=yd[2*b-1],e=0;e<2*b;e+=2)d[e]=G[c+4*e>>2],d[e+1]=G[c+(4*e+4)>>2];else d=G.subarray(c>>2,c+8*b>>2);V.uniform2fv(T[a],d)},vb:function(a,b,c){V.uniform2i(T[a],b,c)},ub:function(a,b,c){if(144>=b)for(var d=zd[2*b-1],e=0;e<2*b;e+=2)d[e]=E[c+4*e>>2],d[e+1]=E[c+(4*e+4)>>2];else d=E.subarray(c>>2,c+8*b>>2);V.uniform2iv(T[a],d)},tb:function(a,b,c,d){V.uniform3f(T[a],b,c,d)},sb:function(a,b,c){if(96>=b)for(var d=yd[3*b-1],e=0;e<3*b;e+=3)d[e]=G[c+4*e>>2],d[e+1]=G[c+(4*e+4)>>2],d[e+2]= -G[c+(4*e+8)>>2];else d=G.subarray(c>>2,c+12*b>>2);V.uniform3fv(T[a],d)},rb:function(a,b,c,d){V.uniform3i(T[a],b,c,d)},qb:function(a,b,c){if(96>=b)for(var d=zd[3*b-1],e=0;e<3*b;e+=3)d[e]=E[c+4*e>>2],d[e+1]=E[c+(4*e+4)>>2],d[e+2]=E[c+(4*e+8)>>2];else d=E.subarray(c>>2,c+12*b>>2);V.uniform3iv(T[a],d)},pb:function(a,b,c,d,e){V.uniform4f(T[a],b,c,d,e)},ob:function(a,b,c){if(72>=b){var d=yd[4*b-1];c>>=2;for(var e=0;e<4*b;e+=4){var g=c+e;d[e]=G[g];d[e+1]=G[g+1];d[e+2]=G[g+2];d[e+3]=G[g+3]}}else d=G.subarray(c>> -2,c+16*b>>2);V.uniform4fv(T[a],d)},nb:function(a,b,c,d,e){V.uniform4i(T[a],b,c,d,e)},mb:function(a,b,c){if(72>=b)for(var d=zd[4*b-1],e=0;e<4*b;e+=4)d[e]=E[c+4*e>>2],d[e+1]=E[c+(4*e+4)>>2],d[e+2]=E[c+(4*e+8)>>2],d[e+3]=E[c+(4*e+12)>>2];else d=E.subarray(c>>2,c+16*b>>2);V.uniform4iv(T[a],d)},lb:function(a,b,c,d){if(72>=b)for(var e=yd[4*b-1],g=0;g<4*b;g+=4)e[g]=G[d+4*g>>2],e[g+1]=G[d+(4*g+4)>>2],e[g+2]=G[d+(4*g+8)>>2],e[g+3]=G[d+(4*g+12)>>2];else e=G.subarray(d>>2,d+16*b>>2);V.uniformMatrix2fv(T[a], -!!c,e)},kb:function(a,b,c,d){if(32>=b)for(var e=yd[9*b-1],g=0;g<9*b;g+=9)e[g]=G[d+4*g>>2],e[g+1]=G[d+(4*g+4)>>2],e[g+2]=G[d+(4*g+8)>>2],e[g+3]=G[d+(4*g+12)>>2],e[g+4]=G[d+(4*g+16)>>2],e[g+5]=G[d+(4*g+20)>>2],e[g+6]=G[d+(4*g+24)>>2],e[g+7]=G[d+(4*g+28)>>2],e[g+8]=G[d+(4*g+32)>>2];else e=G.subarray(d>>2,d+36*b>>2);V.uniformMatrix3fv(T[a],!!c,e)},jb:function(a,b,c,d){if(18>=b){var e=yd[16*b-1];d>>=2;for(var g=0;g<16*b;g+=16){var k=d+g;e[g]=G[k];e[g+1]=G[k+1];e[g+2]=G[k+2];e[g+3]=G[k+3];e[g+4]=G[k+4]; -e[g+5]=G[k+5];e[g+6]=G[k+6];e[g+7]=G[k+7];e[g+8]=G[k+8];e[g+9]=G[k+9];e[g+10]=G[k+10];e[g+11]=G[k+11];e[g+12]=G[k+12];e[g+13]=G[k+13];e[g+14]=G[k+14];e[g+15]=G[k+15]}}else e=G.subarray(d>>2,d+64*b>>2);V.uniformMatrix4fv(T[a],!!c,e)},ib:function(a){V.useProgram(S[a])},hb:function(a){V.validateProgram(S[a])},gb:function(a,b){V.vertexAttrib1f(a,b)},fb:function(a,b){V.vertexAttrib1f(a,G[b>>2])},eb:function(a,b,c){V.vertexAttrib2f(a,b,c)},db:function(a,b){V.vertexAttrib2f(a,G[b>>2],G[b+4>>2])},cb:function(a, -b,c,d){V.vertexAttrib3f(a,b,c,d)},bb:function(a,b){V.vertexAttrib3f(a,G[b>>2],G[b+4>>2],G[b+8>>2])},ab:function(a,b,c,d,e){V.vertexAttrib4f(a,b,c,d,e)},$a:function(a,b){V.vertexAttrib4f(a,G[b>>2],G[b+4>>2],G[b+8>>2],G[b+12>>2])},Fd:function(a,b){V.vertexAttribDivisor(a,b)},_a:function(a,b,c,d,e,g){V.vertexAttribPointer(a,b,c,!!d,e,g)},Za:function(a,b,c,d){V.viewport(a,b,c,d)},ka:function(){return"undefined"!==typeof SharedArrayBuffer},G:function(){return rb|0},R:function(){return qb|0},f:function(a, -b){Z(a,b||1);throw"longjmp";},ja:function(a,b,c){v.copyWithin(a,b,b+c)},ma:function(a,b,c){Bd.length=b;c>>=3;for(var d=0;da?mb[-a-1]:ke[a]).apply(null,Bd)},ra:function(){n("OOM")},na:function(a,b,c){return Ed(a)?Fd(a,b,c):Hd(a,b,c)},Q:function(){},la:function(){},oa:function(a,b){var c={};b>>=2;c.alpha=!!E[b];c.depth=!!E[b+1];c.stencil=!!E[b+2];c.antialias=!!E[b+3];c.premultipliedAlpha=!!E[b+4];c.preserveDrawingBuffer=!!E[b+5];c.powerPreference=Id[E[b+6]];c.failIfMajorPerformanceCaveat= -!!E[b+7];c.wi=E[b+8];c.pj=E[b+9];c.qh=E[b+10];c.hi=E[b+11];c.uj=E[b+12];c.vj=E[b+13];a=Ed(a);if(!a||c.hi)c=0;else if(a=a.getContext("webgl",c)){b=Ma(8);E[b+4>>2]=pb|0;var d={jj:b,attributes:c,version:c.wi,qg:a};a.canvas&&(a.canvas.rg=d);("undefined"===typeof c.qh||c.qh)&&ld(d);c=b}else c=0;return c},sa:function(a,b){var c=0;Kd().forEach(function(d,e){var g=b+c;E[a+4*e>>2]=g;Pa(d,g);c+=d.length+1});return 0},ta:function(a,b){var c=Kd();E[a>>2]=c.length;var d=0;c.forEach(function(e){d+=e.length+1}); -E[b>>2]=d;return 0},D:function(a){Cb(a)},H:Md,U:Nd,xa:Od,Va:Pd,M:Qd,B:Sd,d:function(){return Aa|0},y:Td,v:function(a,b,c,d,e,g,k){b=Oc(a,b);if(b.ef)return-6;a=b.port;var m=b.hf;b=!1;if(c&&d){var r;if(k&1||!(r=Kc(m))){if(k&8)return-2}else m=r;c=Ia(m,v,c,d);c+1>=d&&(b=!0)}e&&g&&(c=Ia(""+a,v,e,g),c+1>=g&&(b=!0));return b?-12:0},l:function(a){var b=Date.now();E[a>>2]=b/1E3|0;E[a+4>>2]=b%1E3*1E3|0;return 0},r:Ib,ia:function(){M.pi()},ba:ne,j:oe,h:pe,C:qe,P:re,_:se,O:te,Xa:ue,Wa:ve,k:we,w:xe,J:ye,g:ze, -N:Ae,Sa:Be,Z:Ce,Ya:De,q:Nb,a:Ca||f.wasmMemory,T:function(a){Jb();var b=new Date(E[a+20>>2]+1900,E[a+16>>2],E[a+12>>2],E[a+8>>2],E[a+4>>2],E[a>>2],0),c=E[a+32>>2],d=b.getTimezoneOffset(),e=new Date(b.getFullYear(),0,1),g=(new Date(b.getFullYear(),6,1)).getTimezoneOffset(),k=e.getTimezoneOffset(),m=Math.min(k,g);0>c?E[a+32>>2]=Number(g!=k&&m==d):0>2]=b.getDay();E[a+28>>2]=(b.getTime()-e.getTime())/864E5|0;return b.getTime()/ -1E3|0},Ra:function(a){if(a===M.Ph)return u("Main thread (id="+a+") cannot be canceled!"),71;if(!a)return u("pthread_cancel attempted on a null thread pointer!"),71;if(E[a+12>>2]!==a)return u("pthread_cancel attempted on thread "+a+", which does not point to a valid thread, or does not exist anymore!"),71;Atomics.compareExchange(F,a>>2,0,2);l?postMessage({cmd:"cancelThread",thread:a}):ub(a);return 0},S:function(a){var b=M.Dg.pop();a&&b()},L:function(a,b){M.Dg.push(function(){H.get(a)(b)})},n:function(a, -b,c,d){if("undefined"===typeof SharedArrayBuffer)return u("Current environment does not support SharedArrayBuffer, pthreads are not available!"),6;if(!a)return u("pthread_create called with a null thread pointer!"),28;var e=[];if(l&&0===e.length)return Ee(687865856,a,b,c,d);var g=0,k=0,m=0,r=0;if(b){var q=E[b>>2];q+=81920;g=E[b+8>>2];k=0!==E[b+12>>2];if(0===E[b+16>>2]){var t=E[b+20>>2],w=E[b+24>>2];m=b+20;r=b+24;var B=M.Mg?M.Mg:pb|0;if(m||r)if(B)if(E[B+12>>2]!==B)u("pthread_getschedparam attempted on thread "+ -B+", which does not point to a valid thread, or does not exist anymore!");else{var p=Atomics.load(F,B+128>>2);B=Atomics.load(F,B+132>>2);m&&(E[m>>2]=p);r&&(E[r>>2]=B)}else u("pthread_getschedparam called with a null thread pointer!");m=E[b+20>>2];r=E[b+24>>2];E[b+20>>2]=t;E[b+24>>2]=w}else m=E[b+20>>2],r=E[b+24>>2]}else q=2097152;(b=0==g)?g=vc(16,q):(g-=q,assert(0w;++w)F[(t>>2)+w]=0;E[a>>2]=t;E[t+12>>2]=t;a=t+156;E[a>>2]=a;c={Rf:g,cg:q,Kg:b,Ih:m,Jh:r,detached:k,Mi:c,$f:t, -Fi:pb|0,Tf:d,Vi:e};l?(c.$i="spawnThread",postMessage(c,e)):Bb(c);return 0},o:function(a,b){return Xd(a,b)},i:Wd,e:function(a){Aa=a|0},E:function(){return 0},m:function(a,b,c,d){function e(p,x,z){for(p="number"===typeof p?p.toString():p||"";p.lengthW?-1:0=k(z,p)?0>=k(x,p)?p.getFullYear()+1:p.getFullYear():p.getFullYear()-1}var q=E[d+40>>2];d={Ti:E[d>>2],Si:E[d+4>> -2],Eg:E[d+8>>2],pg:E[d+12>>2],dg:E[d+16>>2],rf:E[d+20>>2],Fg:E[d+24>>2],Gg:E[d+28>>2],yj:E[d+32>>2],Ri:E[d+36>>2],Ui:q?C(q):""};c=C(c);q={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"}; -for(var t in q)c=c.replace(new RegExp(t,"g"),q[t]);var w="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),B="January February March April May June July August September October November December".split(" ");q={"%a":function(p){return w[p.Fg].substring(0,3)},"%A":function(p){return w[p.Fg]},"%b":function(p){return B[p.dg].substring(0,3)},"%B":function(p){return B[p.dg]},"%C":function(p){return g((p.rf+1900)/100|0,2)},"%d":function(p){return g(p.pg,2)},"%e":function(p){return e(p.pg, -2," ")},"%g":function(p){return r(p).toString().substring(2)},"%G":function(p){return r(p)},"%H":function(p){return g(p.Eg,2)},"%I":function(p){p=p.Eg;0==p?p=12:12p.Eg?"AM":"PM"},"%S":function(p){return g(p.Ti,2)},"%t":function(){return"\t"},"%u":function(p){return p.Fg|| -7},"%U":function(p){var x=new Date(p.rf+1900,0,1),z=0===x.getDay()?x:be(x,7-x.getDay());p=new Date(p.rf+1900,p.dg,p.pg);return 0>k(z,p)?g(Math.ceil((31-z.getDate()+(Zd(Yd(p.getFullYear())?$d:ae,p.getMonth()-1)-31)+p.getDate())/7),2):0===k(z,x)?"01":"00"},"%V":function(p){var x=new Date(p.rf+1901,0,4),z=m(new Date(p.rf+1900,0,4));x=m(x);var I=be(new Date(p.rf+1900,0,1),p.Gg);return 0>k(I,z)?"53":0>=k(x,I)?"01":g(Math.ceil((z.getFullYear()k(z,p)?g(Math.ceil((31-z.getDate()+(Zd(Yd(p.getFullYear())?$d:ae,p.getMonth()-1)-31)+p.getDate())/7),2):0===k(z,x)?"01":"00"},"%y":function(p){return(p.rf+1900).toString().substring(2)},"%Y":function(p){return p.rf+1900},"%z":function(p){p=p.Ri;var x=0<=p;p=Math.abs(p)/60;return(x?"+":"-")+String("0000"+(p/60*100+p%60)).slice(-4)},"%Z":function(p){return p.Ui}, -"%%":function(){return"%"}};for(t in q)0<=c.indexOf(t)&&(c=c.replace(new RegExp(t,"g"),q[t](d)));t=Zb(c,!1);if(t.length>b)return 0;y.set(t,a);return t.length-1},x:ce,s:function(a){var b=Date.now()/1E3|0;a&&(E[a>>2]=b);return b}}; -(function(){function a(e,g){f.asm=e.exports;H=f.asm.Sd;Da=g;l||fb()}function b(e){a(e.instance,e.module)}function c(e){return kb().then(function(g){return WebAssembly.instantiate(g,d)}).then(e,function(g){u("failed to asynchronously prepare wasm: "+g);n(g)})}var d={a:Fe};l||eb();if(f.instantiateWasm)try{return f.instantiateWasm(d,a)}catch(e){return u("Module.instantiateWasm callback failed with error: "+e),!1}(function(){return Ba||"function"!==typeof WebAssembly.instantiateStreaming||ib()||gb("file://")|| -"function"!==typeof fetch?c(b):fetch(hb,{credentials:"same-origin"}).then(function(e){return WebAssembly.instantiateStreaming(e,d).then(b,function(g){u("wasm streaming compile failed: "+g);u("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ca);return{}})(); -var le=f.___wasm_call_ctors=function(){return(le=f.___wasm_call_ctors=f.asm.Td).apply(null,arguments)},zb=f._free=function(){return(zb=f._free=f.asm.Ud).apply(null,arguments)},Ma=f._malloc=function(){return(Ma=f._malloc=f.asm.Vd).apply(null,arguments)},Fb=f.___errno_location=function(){return(Fb=f.___errno_location=f.asm.Wd).apply(null,arguments)},qc=f._memset=function(){return(qc=f._memset=f.asm.Xd).apply(null,arguments)};f._fflush=function(){return(f._fflush=f.asm.Yd).apply(null,arguments)}; -var vc=f._memalign=function(){return(vc=f._memalign=f.asm.Zd).apply(null,arguments)},Nc=f._ntohs=function(){return(Nc=f._ntohs=f.asm._d).apply(null,arguments)},Fc=f._htons=function(){return(Fc=f._htons=f.asm.$d).apply(null,arguments)},me=f._main=function(){return(me=f._main=f.asm.ae).apply(null,arguments)},Vd=f._emscripten_get_global_libc=function(){return(Vd=f._emscripten_get_global_libc=f.asm.be).apply(null,arguments)}; -f.___em_js__initPthreadsJS=function(){return(f.___em_js__initPthreadsJS=f.asm.ce).apply(null,arguments)}; -var Ud=f._htonl=function(){return(Ud=f._htonl=f.asm.de).apply(null,arguments)},Mb=f.__get_tzname=function(){return(Mb=f.__get_tzname=f.asm.ee).apply(null,arguments)},Lb=f.__get_daylight=function(){return(Lb=f.__get_daylight=f.asm.fe).apply(null,arguments)},Kb=f.__get_timezone=function(){return(Kb=f.__get_timezone=f.asm.ge).apply(null,arguments)},A=f.stackSave=function(){return(A=f.stackSave=f.asm.he).apply(null,arguments)},D=f.stackRestore=function(){return(D=f.stackRestore=f.asm.ie).apply(null,arguments)}, -Ha=f.stackAlloc=function(){return(Ha=f.stackAlloc=f.asm.je).apply(null,arguments)},Z=f._setThrew=function(){return(Z=f._setThrew=f.asm.ke).apply(null,arguments)};f._emscripten_main_browser_thread_id=function(){return(f._emscripten_main_browser_thread_id=f.asm.le).apply(null,arguments)}; -var yb=f.___pthread_tsd_run_dtors=function(){return(yb=f.___pthread_tsd_run_dtors=f.asm.me).apply(null,arguments)},Ab=f._emscripten_main_thread_process_queued_calls=function(){return(Ab=f._emscripten_main_thread_process_queued_calls=f.asm.ne).apply(null,arguments)};f._emscripten_current_thread_process_queued_calls=function(){return(f._emscripten_current_thread_process_queued_calls=f.asm.oe).apply(null,arguments)}; -var wb=f._emscripten_register_main_browser_thread_id=function(){return(wb=f._emscripten_register_main_browser_thread_id=f.asm.pe).apply(null,arguments)},lb=f._do_emscripten_dispatch_to_thread=function(){return(lb=f._do_emscripten_dispatch_to_thread=f.asm.qe).apply(null,arguments)};f._emscripten_async_run_in_main_thread=function(){return(f._emscripten_async_run_in_main_thread=f.asm.re).apply(null,arguments)}; -f._emscripten_sync_run_in_main_thread=function(){return(f._emscripten_sync_run_in_main_thread=f.asm.se).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_0=function(){return(f._emscripten_sync_run_in_main_thread_0=f.asm.te).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_1=function(){return(f._emscripten_sync_run_in_main_thread_1=f.asm.ue).apply(null,arguments)}; -f._emscripten_sync_run_in_main_thread_2=function(){return(f._emscripten_sync_run_in_main_thread_2=f.asm.ve).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_xprintf_varargs=function(){return(f._emscripten_sync_run_in_main_thread_xprintf_varargs=f.asm.we).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_3=function(){return(f._emscripten_sync_run_in_main_thread_3=f.asm.xe).apply(null,arguments)}; -var Ee=f._emscripten_sync_run_in_main_thread_4=function(){return(Ee=f._emscripten_sync_run_in_main_thread_4=f.asm.ye).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_5=function(){return(f._emscripten_sync_run_in_main_thread_5=f.asm.ze).apply(null,arguments)};f._emscripten_sync_run_in_main_thread_6=function(){return(f._emscripten_sync_run_in_main_thread_6=f.asm.Ae).apply(null,arguments)}; -f._emscripten_sync_run_in_main_thread_7=function(){return(f._emscripten_sync_run_in_main_thread_7=f.asm.Be).apply(null,arguments)};var Ad=f._emscripten_run_in_main_runtime_thread_js=function(){return(Ad=f._emscripten_run_in_main_runtime_thread_js=f.asm.Ce).apply(null,arguments)},Gd=f.__emscripten_call_on_thread=function(){return(Gd=f.__emscripten_call_on_thread=f.asm.De).apply(null,arguments)};f._proxy_main=function(){return(f._proxy_main=f.asm.Ee).apply(null,arguments)}; -f._emscripten_tls_init=function(){return(f._emscripten_tls_init=f.asm.Fe).apply(null,arguments)};f.dynCall_ijiii=function(){return(f.dynCall_ijiii=f.asm.Ge).apply(null,arguments)};var Ge=f.dynCall_vijjjid=function(){return(Ge=f.dynCall_vijjjid=f.asm.He).apply(null,arguments)},He=f.dynCall_iiiijj=function(){return(He=f.dynCall_iiiijj=f.asm.Ie).apply(null,arguments)};f.dynCall_iiijiii=function(){return(f.dynCall_iiijiii=f.asm.Je).apply(null,arguments)}; -f.dynCall_jiiii=function(){return(f.dynCall_jiiii=f.asm.Ke).apply(null,arguments)};f.dynCall_jii=function(){return(f.dynCall_jii=f.asm.Le).apply(null,arguments)};var Ie=f.dynCall_iij=function(){return(Ie=f.dynCall_iij=f.asm.Me).apply(null,arguments)};f.dynCall_viiijj=function(){return(f.dynCall_viiijj=f.asm.Ne).apply(null,arguments)};f.dynCall_jij=function(){return(f.dynCall_jij=f.asm.Oe).apply(null,arguments)};f.dynCall_jiji=function(){return(f.dynCall_jiji=f.asm.Pe).apply(null,arguments)}; -f.dynCall_iiiji=function(){return(f.dynCall_iiiji=f.asm.Qe).apply(null,arguments)};f.dynCall_iiiiij=function(){return(f.dynCall_iiiiij=f.asm.Re).apply(null,arguments)};f.dynCall_jiiij=function(){return(f.dynCall_jiiij=f.asm.Se).apply(null,arguments)};f.dynCall_iiijjji=function(){return(f.dynCall_iiijjji=f.asm.Te).apply(null,arguments)};f.dynCall_iiiiiij=function(){return(f.dynCall_iiiiiij=f.asm.Ue).apply(null,arguments)};f.dynCall_jiiji=function(){return(f.dynCall_jiiji=f.asm.Ve).apply(null,arguments)}; -f.dynCall_viiiiijji=function(){return(f.dynCall_viiiiijji=f.asm.We).apply(null,arguments)};f.dynCall_viiiji=function(){return(f.dynCall_viiiji=f.asm.Xe).apply(null,arguments)};f.dynCall_viiiiji=function(){return(f.dynCall_viiiiji=f.asm.Ye).apply(null,arguments)};f.dynCall_jiiiii=function(){return(f.dynCall_jiiiii=f.asm.Ze).apply(null,arguments)};f.dynCall_jiii=function(){return(f.dynCall_jiii=f.asm._e).apply(null,arguments)}; -f.dynCall_jiiiiii=function(){return(f.dynCall_jiiiiii=f.asm.$e).apply(null,arguments)};f._ff_h264_cabac_tables=2115974;var xb=f._main_thread_futex=17195328;function pe(a,b,c){var d=A();try{return H.get(a)(b,c)}catch(e){D(d);if(e!==e+0&&"longjmp"!==e)throw e;Z(1,0)}}function we(a,b){var c=A();try{H.get(a)(b)}catch(d){D(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}}function ze(a,b,c,d,e){var g=A();try{H.get(a)(b,c,d,e)}catch(k){D(g);if(k!==k+0&&"longjmp"!==k)throw k;Z(1,0)}} -function xe(a,b,c){var d=A();try{H.get(a)(b,c)}catch(e){D(d);if(e!==e+0&&"longjmp"!==e)throw e;Z(1,0)}}function oe(a,b){var c=A();try{return H.get(a)(b)}catch(d){D(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}}function re(a,b,c,d,e){var g=A();try{return H.get(a)(b,c,d,e)}catch(k){D(g);if(k!==k+0&&"longjmp"!==k)throw k;Z(1,0)}}function te(a,b,c,d,e,g,k,m,r){var q=A();try{return H.get(a)(b,c,d,e,g,k,m,r)}catch(t){D(q);if(t!==t+0&&"longjmp"!==t)throw t;Z(1,0)}} -function ye(a,b,c,d){var e=A();try{H.get(a)(b,c,d)}catch(g){D(e);if(g!==g+0&&"longjmp"!==g)throw g;Z(1,0)}}function ne(a){var b=A();try{return H.get(a)()}catch(c){D(b);if(c!==c+0&&"longjmp"!==c)throw c;Z(1,0)}}function Ae(a,b,c,d,e,g){var k=A();try{H.get(a)(b,c,d,e,g)}catch(m){D(k);if(m!==m+0&&"longjmp"!==m)throw m;Z(1,0)}}function qe(a,b,c,d){var e=A();try{return H.get(a)(b,c,d)}catch(g){D(e);if(g!==g+0&&"longjmp"!==g)throw g;Z(1,0)}} -function se(a,b,c,d,e,g){var k=A();try{return H.get(a)(b,c,d,e,g)}catch(m){D(k);if(m!==m+0&&"longjmp"!==m)throw m;Z(1,0)}}function Ce(a,b,c,d,e,g,k,m,r){var q=A();try{H.get(a)(b,c,d,e,g,k,m,r)}catch(t){D(q);if(t!==t+0&&"longjmp"!==t)throw t;Z(1,0)}}function Be(a,b,c,d,e,g,k){var m=A();try{H.get(a)(b,c,d,e,g,k)}catch(r){D(m);if(r!==r+0&&"longjmp"!==r)throw r;Z(1,0)}}function De(a,b,c,d,e,g,k,m,r,q){var t=A();try{Ge(a,b,c,d,e,g,k,m,r,q)}catch(w){D(t);if(w!==w+0&&"longjmp"!==w)throw w;Z(1,0)}} -function ue(a,b,c,d,e,g,k,m){var r=A();try{return He(a,b,c,d,e,g,k,m)}catch(q){D(r);if(q!==q+0&&"longjmp"!==q)throw q;Z(1,0)}}function ve(a,b,c,d){var e=A();try{return Ie(a,b,c,d)}catch(g){D(e);if(g!==g+0&&"longjmp"!==g)throw g;Z(1,0)}}f.ccall=Ga;f.cwrap=function(a,b,c,d){c=c||[];var e=c.every(function(g){return"number"===g});return"string"!==b&&e&&!d?Fa(a):function(){return Ga(a,b,c,arguments,d)}}; -f.setValue=function(a,b,c){c=c||"i8";"*"===c.charAt(c.length-1)&&(c="i32");switch(c){case "i1":y[a>>0]=b;break;case "i8":y[a>>0]=b;break;case "i16":Qa[a>>1]=b;break;case "i32":E[a>>2]=b;break;case "i64":L=[b>>>0,(J=b,1<=+Math.abs(J)?0>>0:~~+Math.ceil((J-+(~~J>>>0))/4294967296)>>>0:0)];E[a>>2]=L[0];E[a+4>>2]=L[1];break;case "float":G[a>>2]=b;break;case "double":Sa[a>>3]=b;break;default:n("invalid type for setValue: "+c)}};f.writeAsciiToMemory=Pa; -f.FS=O;f.PThread=M;f.PThread=M;f._pthread_self=Wd;f.wasmMemory=Ca;f.ExitStatus=wa;var Je;function wa(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}cb=function Ke(){Je||Le();Je||(cb=Ke)}; -function Le(a){function b(){if(!Je&&(Je=!0,f.calledRun=!0,!Ea)){f.noFSInit||O.gg.Tg||O.gg();R.root=O.jf(R,{},null);nb(Wa);l||(O.Bh=!1,nb(Xa));ba(f);if(f.onRuntimeInitialized)f.onRuntimeInitialized();if(Me){var c=a;c=c||[];var d=c.length+1,e=Ha(4*(d+1));E[e>>2]=Na(ha);for(var g=1;g>2)+g]=Na(c[g-1]);E[(e>>2)+d]=0;f._proxy_main(d,e)}if(!l){if(f.postRun)for("function"==typeof f.postRun&&(f.postRun=[f.postRun]);f.postRun.length;)c=f.postRun.shift(),Za.unshift(c);nb(Za)}}}a=a||fa;if(!(0>>0);return r}},g=va(a),h=[];a=0;if(d)for(var n=0;n>>=0;var d=b+c;for(c=b;a[c>>>0]&&!(c>=d);)++c;if(16>>0,c>>>0));for(d="";b>>0];if(f&128){var g=a[b++>>>0]&63;if(192==(f&224))d+=String.fromCharCode((f&31)<<6|g);else{var h=a[b++>>>0]&63;f=224==(f&240)?(f&15)<<12|g<<6|h:(f&7)<<18|g<<12|h<<6|a[b++>>>0]&63;65536>f?d+=String.fromCharCode(f):(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else d+=String.fromCharCode(f)}return d} +function H(a){return(a>>>=0)?za(D,a,void 0):""} +function C(a,b,c,d){c>>>=0;if(!(0=h){var n=a.charCodeAt(++g);h=65536+((h&1023)<<10)|n&1023}if(127>=h){if(c>=d)break;b[c++>>>0]=h}else{if(2047>=h){if(c+1>=d)break;b[c++>>>0]=192|h>>6}else{if(65535>=h){if(c+2>=d)break;b[c++>>>0]=224|h>>12}else{if(c+3>=d)break;b[c++>>>0]=240|h>>18;b[c++>>>0]=128|h>>12&63}b[c++>>>0]=128|h>>6&63}b[c++>>>0]=128|h&63}}b[c>>>0]=0;return c-f} +function Aa(a){for(var b=0,c=0;c=d&&(d=65536+((d&1023)<<10)|a.charCodeAt(++c)&1023);127>=d?++b:b=2047>=d?b+2:65535>=d?b+3:b+4}return b}function Ba(a){var b=Aa(a)+1,c=Ca(b);c&&C(a,E,c,b);return c}function Da(a){var b=Aa(a)+1,c=xa(b);C(a,E,c,b);return c}function K(a,b,c){for(var d=0;d>0>>>0]=a.charCodeAt(d);c||(E[b>>0>>>0]=0)}var Ea,E,D,L,Fa,M,Ga,Ha; +function Ia(){var a=ta.buffer;Ea=a;e.HEAP8=E=new Int8Array(a);e.HEAP16=L=new Int16Array(a);e.HEAP32=M=new Int32Array(a);e.HEAPU8=D=new Uint8Array(a);e.HEAPU16=Fa=new Uint16Array(a);e.HEAPU32=new Uint32Array(a);e.HEAPF32=Ga=new Float32Array(a);e.HEAPF64=Ha=new Float64Array(a)}var O,Ja=[],Ka=[],La=[],Ma=[];function Na(){var a=e.preRun.shift();Ja.unshift(a)}var Qa=0,Ra=null,Sa=null;function Ta(){Qa++;e.monitorRunDependencies&&e.monitorRunDependencies(Qa)} +function Ua(){Qa--;e.monitorRunDependencies&&e.monitorRunDependencies(Qa);if(0==Qa&&(null!==Ra&&(clearInterval(Ra),Ra=null),Sa)){var a=Sa;Sa=null;a()}}e.preloadedImages={};e.preloadedAudios={};function B(a){if(e.onAbort)e.onAbort(a);k(a);ua=!0;a=new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");ba(a);throw a;}function Va(){return P.startsWith("data:application/octet-stream;base64,")}var P;P="ffmpeg-core.wasm"; +if(!Va()){var Wa=P;P=e.locateFile?e.locateFile(Wa,y):y+Wa}function Xa(){var a=P;try{if(a==P&&sa)return new Uint8Array(sa);if(oa)return oa(a);throw"both async and sync fetching of the wasm failed";}catch(b){B(b)}} +function Ya(){if(!sa&&(ka||v)){if("function"===typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+P+"'";return a.arrayBuffer()}).catch(function(){return Xa()});if(na)return new Promise(function(a,b){na(P,function(c){a(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return Xa()})}var Q,R; +function Za(a){for(;0>2>>>0]=28,-1;M[b>>2>>>0]=a/1E3|0;M[b+4>>2>>>0]=a%1E3*1E6|0;return 0} +function eb(a,b){a=new Date(1E3*M[a>>2>>>0]);M[b>>2>>>0]=a.getUTCSeconds();M[b+4>>2>>>0]=a.getUTCMinutes();M[b+8>>2>>>0]=a.getUTCHours();M[b+12>>2>>>0]=a.getUTCDate();M[b+16>>2>>>0]=a.getUTCMonth();M[b+20>>2>>>0]=a.getUTCFullYear()-1900;M[b+24>>2>>>0]=a.getUTCDay();M[b+36>>2>>>0]=0;M[b+32>>2>>>0]=0;M[b+28>>2>>>0]=(a.getTime()-Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0))/864E5|0;eb.Hc||(eb.Hc=Ba("GMT"));M[b+40>>2>>>0]=eb.Hc;return b} +function fb(){function a(h){return(h=h.toTimeString().match(/\(([A-Za-z ]+)\)$/))?h[1]:"GMT"}if(!gb){gb=!0;var b=(new Date).getFullYear(),c=new Date(b,0,1),d=new Date(b,6,1);b=c.getTimezoneOffset();var f=d.getTimezoneOffset(),g=Math.max(b,f);M[hb()>>2>>>0]=60*g;M[ib()>>2>>>0]=Number(b!=f);c=a(c);d=a(d);c=Ba(c);d=Ba(d);f>2>>>0]=c,M[jb()+4>>2>>>0]=d):(M[jb()>>2>>>0]=d,M[jb()+4>>2>>>0]=c)}}var gb; +function kb(a,b){fb();a=new Date(1E3*M[a>>2>>>0]);M[b>>2>>>0]=a.getSeconds();M[b+4>>2>>>0]=a.getMinutes();M[b+8>>2>>>0]=a.getHours();M[b+12>>2>>>0]=a.getDate();M[b+16>>2>>>0]=a.getMonth();M[b+20>>2>>>0]=a.getFullYear()-1900;M[b+24>>2>>>0]=a.getDay();var c=new Date(a.getFullYear(),0,1);M[b+28>>2>>>0]=(a.getTime()-c.getTime())/864E5|0;M[b+36>>2>>>0]=-(60*a.getTimezoneOffset());var d=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();c=c.getTimezoneOffset();a=(d!=c&&a.getTimezoneOffset()==Math.min(c, +d))|0;M[b+32>>2>>>0]=a;a=M[jb()+(a?4:0)>>2>>>0];M[b+40>>2>>>0]=a;return b}function lb(a,b){for(var c=0,d=a.length-1;0<=d;d--){var f=a[d];"."===f?a.splice(d,1):".."===f?(a.splice(d,1),c++):c&&(a.splice(d,1),c--)}if(b)for(;c;c--)a.unshift("..");return a}function mb(a){var b="/"===a.charAt(0),c="/"===a.substr(-1);(a=lb(a.split("/").filter(function(d){return!!d}),!b).join("/"))||b||(a=".");a&&c&&(a+="/");return(b?"/":"")+a} +function nb(a){var b=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(a).slice(1);a=b[0];b=b[1];if(!a&&!b)return".";b&&(b=b.substr(0,b.length-1));return a+b}function S(a){if("/"===a)return"/";a=mb(a);a=a.replace(/\/$/,"");var b=a.lastIndexOf("/");return-1===b?a:a.substr(b+1)}function pb(a,b){return mb(a+"/"+b)} +function qb(){if("object"===typeof crypto&&"function"===typeof crypto.getRandomValues){var a=new Uint8Array(1);return function(){crypto.getRandomValues(a);return a[0]}}if(x)try{var b=require("crypto");return function(){return b.randomBytes(1)[0]}}catch(c){}return function(){B("randomDevice")}} +function rb(){for(var a="",b=!1,c=arguments.length-1;-1<=c&&!b;c--){b=0<=c?arguments[c]:T.cwd();if("string"!==typeof b)throw new TypeError("Arguments to path.resolve must be strings");if(!b)return"";a=b+"/"+a;b="/"===b.charAt(0)}a=lb(a.split("/").filter(function(d){return!!d}),!b).join("/");return(b?"/":"")+a||"."} +function sb(a,b){function c(h){for(var n=0;np?[]:h.slice(n,p-n+1)}a=rb(a).substr(1);b=rb(b).substr(1);a=c(a.split("/"));b=c(b.split("/"));for(var d=Math.min(a.length,b.length),f=d,g=0;g>>=0;var c=a.cb? +a.cb.length:0;c>=b||(b=Math.max(b,c*(1048576>c?2:1.125)>>>0),0!=c&&(b=Math.max(b,256)),c=a.cb,a.cb=new Uint8Array(b),0>>=0;if(a.fb!=b)if(0==b)a.cb=null,a.fb=0;else{var c=a.cb;a.cb=new Uint8Array(b);c&&a.cb.set(c.subarray(0,Math.min(b,a.fb)));a.fb=b}},$a:{ub:function(a){var b={};b.dev=T.Ub(a.mode)?a.id:1;b.ino=a.id;b.mode=a.mode;b.nlink=1;b.uid=0;b.gid=0;b.rdev=a.rdev;T.ib(a.mode)?b.size=4096:T.isFile(a.mode)?b.size=a.fb:T.Db(a.mode)?b.size= +a.link.length:b.size=0;b.atime=new Date(a.timestamp);b.mtime=new Date(a.timestamp);b.ctime=new Date(a.timestamp);b.od=4096;b.blocks=Math.ceil(b.size/b.od);return b},lb:function(a,b){void 0!==b.mode&&(a.mode=b.mode);void 0!==b.timestamp&&(a.timestamp=b.timestamp);void 0!==b.size&&U.Rd(a,b.size)},lookup:function(){throw T.tc[44];},yb:function(a,b,c,d){return U.createNode(a,b,c,d)},rename:function(a,b,c){if(T.ib(a.mode)){try{var d=T.vb(b,c)}catch(g){}if(d)for(var f in d.cb)throw new T.Za(55);}delete a.parent.cb[a.name]; +a.parent.timestamp=Date.now();a.name=c;b.cb[c]=a;b.timestamp=a.parent.timestamp;a.parent=b},unlink:function(a,b){delete a.cb[b];a.timestamp=Date.now()},rmdir:function(a,b){var c=T.vb(a,b),d;for(d in c.cb)throw new T.Za(55);delete a.cb[b];a.timestamp=Date.now()},readdir:function(a){var b=[".",".."],c;for(c in a.cb)a.cb.hasOwnProperty(c)&&b.push(c);return b},symlink:function(a,b,c){a=U.createNode(a,b,41471,0);a.link=c;return a},readlink:function(a){if(!T.Db(a.mode))throw new T.Za(28);return a.link}}, +ab:{read:function(a,b,c,d,f){var g=a.node.cb;if(f>=a.node.fb)return 0;a=Math.min(a.node.fb-f,d);if(8b)throw new T.Za(28);return b},Sb:function(a,b,c){U.Qc(a.node,b+c);a.node.fb=Math.max(a.node.fb,b+c)},Kb:function(a,b,c,d,f,g){if(0!==b)throw new T.Za(28);if(!T.isFile(a.node.mode))throw new T.Za(43);a=a.node.cb;if(g&2||a.buffer!==Ea){if(0>>0]=0;c=b;if(!c)throw new T.Za(48);c>>>=0;E.set(a,c>>>0)}else d=!1,c=a.byteOffset;return{Qd:c,oc:d}},Lb:function(a,b,c,d,f){if(!T.isFile(a.node.mode))throw new T.Za(43);if(f&2)return 0;U.ab.write(a,b,0,d,c,!1);return 0}}},T={root:null,Xb:[],Oc:{},streams:[],Kd:1,wb:null,Nc:"/",wc:!1,Yc:!0,kb:{},ed:{$c:{kd:1,ld:2}},Za:null,tc:{},yd:null,ic:0,eb:function(a,b){a=rb(T.cwd(),a);b=b||{};if(!a)return{path:"",node:null};var c={sc:!0,Dc:0},d; +for(d in c)void 0===b[d]&&(b[d]=c[d]);if(8>>0)%T.wb.length},Wc:function(a){var b=T.vc(a.parent.id,a.name);a.Gb=T.wb[b];T.wb[b]=a},Xc:function(a){var b=T.vc(a.parent.id,a.name);if(T.wb[b]===a)T.wb[b]=a.Gb;else for(b=T.wb[b];b;){if(b.Gb===a){b.Gb=a.Gb;break}b=b.Gb}},vb:function(a,b){var c=T.Hd(a);if(c)throw new T.Za(c,a);for(c=T.wb[T.vc(a.id,b)];c;c=c.Gb){var d=c.name;if(c.parent.id===a.id&&d===b)return c}return T.lookup(a, +b)},createNode:function(a,b,c,d){a=new T.hd(a,b,c,d);T.Wc(a);return a},rc:function(a){T.Xc(a)},cc:function(a){return a===a.parent},Eb:function(a){return!!a.Wb},isFile:function(a){return 32768===(a&61440)},ib:function(a){return 16384===(a&61440)},Db:function(a){return 40960===(a&61440)},Ub:function(a){return 8192===(a&61440)},Dd:function(a){return 24576===(a&61440)},isFIFO:function(a){return 4096===(a&61440)},isSocket:function(a){return 49152===(a&49152)},zd:{r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090}, +Jd:function(a){var b=T.zd[a];if("undefined"===typeof b)throw Error("Unknown file open mode: "+a);return b},Rc:function(a){var b=["r","w","rw"][a&3];a&512&&(b+="w");return b},Bb:function(a,b){if(T.Yc)return 0;if(!b.includes("r")||a.mode&292){if(b.includes("w")&&!(a.mode&146)||b.includes("x")&&!(a.mode&73))return 2}else return 2;return 0},Hd:function(a){var b=T.Bb(a,"x");return b?b:a.$a.lookup?0:2},Ac:function(a,b){try{return T.vb(a,b),20}catch(c){}return T.Bb(a,"wx")},dc:function(a,b,c){try{var d= +T.vb(a,b)}catch(f){return f.bb}if(a=T.Bb(a,"wx"))return a;if(c){if(!T.ib(d.mode))return 54;if(T.cc(d)||T.Ab(d)===T.cwd())return 10}else if(T.ib(d.mode))return 31;return 0},Id:function(a,b){return a?T.Db(a.mode)?32:T.ib(a.mode)&&("r"!==T.Rc(b)||b&512)?31:T.Bb(a,T.Rc(b)):44},jd:4096,Ld:function(a,b){b=b||T.jd;for(a=a||0;a<=b;a++)if(!T.streams[a])return a;throw new T.Za(33);},tb:function(a){return T.streams[a]},Mc:function(a,b,c){T.mc||(T.mc=function(){},T.mc.prototype={object:{get:function(){return this.node}, +set:function(g){this.node=g}}});var d=new T.mc,f;for(f in a)d[f]=a[f];a=d;b=T.Ld(b,c);a.fd=b;return T.streams[b]=a},rd:function(a){T.streams[a]=null},qd:{open:function(a){a.ab=T.Ad(a.node.rdev).ab;a.ab.open&&a.ab.open(a)},pb:function(){throw new T.Za(70);}},zc:function(a){return a>>8},je:function(a){return a&255},Fb:function(a,b){return a<<8|b},Ec:function(a,b){T.Oc[a]={ab:b}},Ad:function(a){return T.Oc[a]},Tc:function(a){var b=[];for(a=[a];a.length;){var c=a.pop();b.push(c);a.push.apply(a,c.Xb)}return b}, +dd:function(a,b){function c(h){T.ic--;return b(h)}function d(h){if(h){if(!d.xd)return d.xd=!0,c(h)}else++g>=f.length&&c(null)}"function"===typeof a&&(b=a,a=!1);T.ic++;1b)throw new T.Za(28);a="string"===typeof a?T.eb(a,{sb:!0}).node:a;if(!a.$a.lb)throw new T.Za(63);if(T.ib(a.mode))throw new T.Za(31); +if(!T.isFile(a.mode))throw new T.Za(28);var c=T.Bb(a,"w");if(c)throw new T.Za(c);a.$a.lb(a,{size:b,timestamp:Date.now()})},ee:function(a,b){a=T.tb(a);if(!a)throw new T.Za(8);if(0===(a.flags&2097155))throw new T.Za(28);T.truncate(a.node,b)},qe:function(a,b,c){a=T.eb(a,{sb:!0}).node;a.$a.lb(a,{timestamp:Math.max(b,c)})},open:function(a,b,c,d,f){if(""===a)throw new T.Za(44);b="string"===typeof b?T.Jd(b):b;c=b&64?("undefined"===typeof c?438:c)&4095|32768:0;if("object"===typeof a)var g=a;else{a=mb(a); +try{g=T.eb(a,{sb:!(b&131072)}).node}catch(n){}}var h=!1;if(b&64)if(g){if(b&128)throw new T.Za(20);}else g=T.yb(a,c,0),h=!0;if(!g)throw new T.Za(44);T.Ub(g.mode)&&(b&=-513);if(b&65536&&!T.ib(g.mode))throw new T.Za(54);if(!h&&(c=T.Id(g,b)))throw new T.Za(c);b&512&&T.truncate(g,0);b&=-131713;d=T.Mc({node:g,path:T.Ab(g),flags:b,seekable:!0,position:0,ab:g.ab,Yd:[],error:!1},d,f);d.ab.open&&d.ab.open(d);!e.logReadFiles||b&1||(T.Cc||(T.Cc={}),a in T.Cc||(T.Cc[a]=1,k("FS.trackingDelegate error on read file: "+ +a)));try{T.kb.onOpenFile&&(f=0,1!==(b&2097155)&&(f|=T.ed.$c.kd),0!==(b&2097155)&&(f|=T.ed.$c.ld),T.kb.onOpenFile(a,f))}catch(n){k("FS.trackingDelegate['onOpenFile']('"+a+"', flags) threw an exception: "+n.message)}return d},close:function(a){if(T.Vb(a))throw new T.Za(8);a.Cb&&(a.Cb=null);try{a.ab.close&&a.ab.close(a)}catch(b){throw b;}finally{T.rd(a.fd)}a.fd=null},Vb:function(a){return null===a.fd},pb:function(a,b,c){if(T.Vb(a))throw new T.Za(8);if(!a.seekable||!a.ab.pb)throw new T.Za(70);if(0!=c&& +1!=c&&2!=c)throw new T.Za(28);a.position=a.ab.pb(a,b,c);a.Yd=[];return a.position},read:function(a,b,c,d,f){c>>>=0;if(0>d||0>f)throw new T.Za(28);if(T.Vb(a))throw new T.Za(8);if(1===(a.flags&2097155))throw new T.Za(8);if(T.ib(a.node.mode))throw new T.Za(31);if(!a.ab.read)throw new T.Za(28);var g="undefined"!==typeof f;if(!g)f=a.position;else if(!a.seekable)throw new T.Za(70);b=a.ab.read(a,b,c,d,f);g||(a.position+=b);return b},write:function(a,b,c,d,f,g){c>>>=0;if(0>d||0>f)throw new T.Za(28);if(T.Vb(a))throw new T.Za(8); +if(0===(a.flags&2097155))throw new T.Za(8);if(T.ib(a.node.mode))throw new T.Za(31);if(!a.ab.write)throw new T.Za(28);a.seekable&&a.flags&1024&&T.pb(a,0,2);var h="undefined"!==typeof f;if(!h)f=a.position;else if(!a.seekable)throw new T.Za(70);b=a.ab.write(a,b,c,d,f,g);h||(a.position+=b);try{if(a.path&&T.kb.onWriteToFile)T.kb.onWriteToFile(a.path)}catch(n){k("FS.trackingDelegate['onWriteToFile']('"+a.path+"') threw an exception: "+n.message)}return b},Sb:function(a,b,c){if(T.Vb(a))throw new T.Za(8); +if(0>b||0>=c)throw new T.Za(28);if(0===(a.flags&2097155))throw new T.Za(8);if(!T.isFile(a.node.mode)&&!T.ib(a.node.mode))throw new T.Za(43);if(!a.ab.Sb)throw new T.Za(138);a.ab.Sb(a,b,c)},Kb:function(a,b,c,d,f,g){b>>>=0;if(0!==(f&2)&&0===(g&2)&&2!==(a.flags&2097155))throw new T.Za(2);if(1===(a.flags&2097155))throw new T.Za(2);if(!a.ab.Kb)throw new T.Za(43);return a.ab.Kb(a,b,c,d,f,g)},Lb:function(a,b,c,d,f){return a&&a.ab.Lb?a.ab.Lb(a,b,c>>>0,d,f):0},le:function(){return 0},Jb:function(a,b,c){if(!a.ab.Jb)throw new T.Za(59); +return a.ab.Jb(a,b,c)},readFile:function(a,b){b=b||{};b.flags=b.flags||0;b.encoding=b.encoding||"binary";if("utf8"!==b.encoding&&"binary"!==b.encoding)throw Error('Invalid encoding type "'+b.encoding+'"');var c,d=T.open(a,b.flags);a=T.stat(a).size;var f=new Uint8Array(a);T.read(d,f,0,a,0);"utf8"===b.encoding?c=za(f,0):"binary"===b.encoding&&(c=f);T.close(d);return c},writeFile:function(a,b,c){c=c||{};c.flags=c.flags||577;a=T.open(a,c.flags,c.mode);if("string"===typeof b){var d=new Uint8Array(Aa(b)+ +1);b=C(b,d,0,d.length);T.write(a,d,0,b,void 0,c.pd)}else if(ArrayBuffer.isView(b))T.write(a,b,0,b.byteLength,void 0,c.pd);else throw Error("Unsupported data type");T.close(a)},cwd:function(){return T.Nc},chdir:function(a){a=T.eb(a,{sb:!0});if(null===a.node)throw new T.Za(44);if(!T.ib(a.node.mode))throw new T.Za(54);var b=T.Bb(a.node,"x");if(b)throw new T.Za(b);T.Nc=a.path},td:function(){T.mkdir("/tmp");T.mkdir("/home");T.mkdir("/home/web_user")},sd:function(){T.mkdir("/dev");T.Ec(T.Fb(1,3),{read:function(){return 0}, +write:function(b,c,d,f){return f}});T.ec("/dev/null",T.Fb(1,3));ub(T.Fb(5,0),xb);ub(T.Fb(6,0),yb);T.ec("/dev/tty",T.Fb(5,0));T.ec("/dev/tty1",T.Fb(6,0));var a=qb();T.zb("/dev","random",a);T.zb("/dev","urandom",a);T.mkdir("/dev/shm");T.mkdir("/dev/shm/tmp")},vd:function(){T.mkdir("/proc");var a=T.mkdir("/proc/self");T.mkdir("/proc/self/fd");T.gb({gb:function(){var b=T.createNode(a,"fd",16895,73);b.$a={lookup:function(c,d){var f=T.tb(+d);if(!f)throw new T.Za(8);c={parent:null,gb:{Zc:"fake"},$a:{readlink:function(){return f.path}}}; +return c.parent=c}};return b}},{},"/proc/self/fd")},wd:function(){e.stdin?T.zb("/dev","stdin",e.stdin):T.symlink("/dev/tty","/dev/stdin");e.stdout?T.zb("/dev","stdout",null,e.stdout):T.symlink("/dev/tty","/dev/stdout");e.stderr?T.zb("/dev","stderr",null,e.stderr):T.symlink("/dev/tty1","/dev/stderr");T.open("/dev/stdin",0);T.open("/dev/stdout",1);T.open("/dev/stderr",1)},Pc:function(){T.Za||(T.Za=function(a,b){this.node=b;this.Sd=function(c){this.bb=c};this.Sd(a);this.message="FS error"},T.Za.prototype= +Error(),T.Za.prototype.constructor=T.Za,[44].forEach(function(a){T.tc[a]=new T.Za(a);T.tc[a].stack=""}))},Td:function(){T.Pc();T.wb=Array(4096);T.gb(U,{},"/");T.td();T.sd();T.vd();T.yd={MEMFS:U}},Tb:function(a,b,c){T.Tb.wc=!0;T.Pc();e.stdin=a||e.stdin;e.stdout=b||e.stdout;e.stderr=c||e.stderr;T.wd()},quit:function(){T.Tb.wc=!1;var a=e._fflush;a&&a(0);for(a=0;athis.length-1||0>q)){var r=q%this.chunkSize;return this.Vc(q/this.chunkSize|0)[r]}};g.prototype.gd=function(q){this.Vc=q};g.prototype.Jc=function(){var q=new XMLHttpRequest;q.open("HEAD",c,!1);q.send(null);if(!(200<=q.status&&300>q.status||304===q.status))throw Error("Couldn't load "+c+". Status: "+q.status);var r=Number(q.getResponseHeader("Content-length")),w,z=(w=q.getResponseHeader("Accept-Ranges"))&&"bytes"===w;q=(w=q.getResponseHeader("Content-Encoding"))&& +"gzip"===w;var m=1048576;z||(m=r);var t=this;t.gd(function(u){var F=u*m,J=(u+1)*m-1;J=Math.min(J,r-1);if("undefined"===typeof t.Ib[u]){var db=t.Ib;if(F>J)throw Error("invalid range ("+F+", "+J+") or no bytes requested!");if(J>r-1)throw Error("only "+r+" bytes available! programmer error!");var A=new XMLHttpRequest;A.open("GET",c,!1);r!==m&&A.setRequestHeader("Range","bytes="+F+"-"+J);"undefined"!=typeof Uint8Array&&(A.responseType="arraybuffer");A.overrideMimeType&&A.overrideMimeType("text/plain; charset=x-user-defined"); +A.send(null);if(!(200<=A.status&&300>A.status||304===A.status))throw Error("Couldn't load "+c+". Status: "+A.status);F=void 0!==A.response?new Uint8Array(A.response||[]):wb(A.responseText||"",!0);db[u]=F}if("undefined"===typeof t.Ib[u])throw Error("doXHR failed!");return t.Ib[u]});if(q||!r)m=r=1,m=r=this.Vc(0).length,ea("LazyFiles on gzip forces download of the whole file when length is accessed");this.nd=r;this.md=m;this.yc=!0};if("undefined"!==typeof XMLHttpRequest){if(!v)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"; +var h=new g;Object.defineProperties(h,{length:{get:function(){this.yc||this.Jc();return this.nd}},chunkSize:{get:function(){this.yc||this.Jc();return this.md}}});h={xc:!1,cb:h}}else h={xc:!1,url:c};var n=T.ud(a,b,h,d,f);h.cb?n.cb=h.cb:h.url&&(n.cb=null,n.url=h.url);Object.defineProperties(n,{fb:{get:function(){return this.cb.length}}});var p={};Object.keys(n.ab).forEach(function(q){var r=n.ab[q];p[q]=function(){T.Sc(n);return r.apply(null,arguments)}});p.read=function(q,r,w,z,m){T.Sc(n);q=q.node.cb; +if(m>=q.length)return 0;z=Math.min(q.length-m,z);if(q.slice)for(var t=0;t>2>>>0]=d.dev;M[c+4>>2>>>0]=0;M[c+8>>2>>>0]=d.ino;M[c+12>>2>>>0]=d.mode;M[c+16>>2>>>0]=d.nlink;M[c+20>>2>>>0]=d.uid;M[c+24>>2>>>0]=d.gid;M[c+28>>2>>>0]=d.rdev;M[c+32>>2>>>0]=0;R=[d.size>>>0,(Q=d.size,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[c+40>>2>>>0]=R[0];M[c+44>>2>>>0]=R[1];M[c+48>>2>>>0]=4096;M[c+52>>2>>>0]= +d.blocks;M[c+56>>2>>>0]=d.atime.getTime()/1E3|0;M[c+60>>2>>>0]=0;M[c+64>>2>>>0]=d.mtime.getTime()/1E3|0;M[c+68>>2>>>0]=0;M[c+72>>2>>>0]=d.ctime.getTime()/1E3|0;M[c+76>>2>>>0]=0;R=[d.ino>>>0,(Q=d.ino,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[c+80>>2>>>0]=R[0];M[c+84>>2>>>0]=R[1];return 0}var Cb=void 0;function Db(){Cb+=4;return M[Cb-4>>2>>>0]}function V(a){a=T.tb(a);if(!a)throw new T.Za(8);return a} +var W={gb:function(){e.websocket=e.websocket&&"object"===typeof e.websocket?e.websocket:{};e.websocket.nc={};e.websocket.on=function(a,b){"function"===typeof b&&(this.nc[a]=b);return this};e.websocket.emit=function(a,b){"function"===typeof this.nc[a]&&this.nc[a].call(this,b)};return T.createNode(null,"/",16895,0)},createSocket:function(a,b,c){b&=-526337;c&&assert(1==b==(6==c));a={family:a,type:b,protocol:c,jb:null,error:null,Yb:{},pending:[],Ob:[],qb:W.mb};b=W.fc();c=T.createNode(W.root,b,49152,0); +c.Pb=a;b=T.Mc({path:b,node:c,flags:2,seekable:!1,ab:W.ab});a.stream=b;return a},Bd:function(a){return(a=T.tb(a))&&T.isSocket(a.node.mode)?a.node.Pb:null},ab:{Nb:function(a){a=a.node.Pb;return a.qb.Nb(a)},Jb:function(a,b,c){a=a.node.Pb;return a.qb.Jb(a,b,c)},read:function(a,b,c,d){a=a.node.Pb;d=a.qb.ad(a,d);if(!d)return 0;b.set(d.buffer,c);return d.buffer.length},write:function(a,b,c,d){a=a.node.Pb;return a.qb.cd(a,b,c,d)},close:function(a){a=a.node.Pb;a.qb.close(a)}},fc:function(){W.fc.current||(W.fc.current= +0);return"socket["+W.fc.current++ +"]"},mb:{$b:function(a,b,c){if("object"===typeof b){var d=b;c=b=null}if(d)if(d._socket)b=d._socket.remoteAddress,c=d._socket.remotePort;else{c=/ws[s]?:\/\/([^:]+):(\d+)/.exec(d.url);if(!c)throw Error("WebSocket URL must be in the format ws(s)://address:port");b=c[1];c=parseInt(c[2],10)}else try{var f=e.websocket&&"object"===typeof e.websocket,g="ws:#".replace("#","//");f&&"string"===typeof e.websocket.url&&(g=e.websocket.url);if("ws://"===g||"wss://"===g){var h= +b.split("/");g=g+h[0]+":"+c+"/"+h.slice(1).join("/")}h="binary";f&&"string"===typeof e.websocket.subprotocol&&(h=e.websocket.subprotocol);var n=void 0;"null"!==h&&(h=h.replace(/^ +| +$/g,"").split(/ *, */),n=x?{protocol:h.toString()}:h);f&&null===e.websocket.subprotocol&&(n=void 0);d=new (x?require("ws"):WebSocket)(g,n);d.binaryType="arraybuffer"}catch(p){throw new T.Za(23);}b={hb:b,port:c,socket:d,ac:[]};W.mb.Ic(a,b);W.mb.Cd(a,b);2===a.type&&"undefined"!==typeof a.Hb&&b.ac.push(new Uint8Array([255, +255,255,255,112,111,114,116,(a.Hb&65280)>>8,a.Hb&255]));return b},bc:function(a,b,c){return a.Yb[b+":"+c]},Ic:function(a,b){a.Yb[b.hb+":"+b.port]=b},bd:function(a,b){delete a.Yb[b.hb+":"+b.port]},Cd:function(a,b){function c(){e.websocket.emit("open",a.stream.fd);try{for(var g=b.ac.shift();g;)b.socket.send(g),g=b.ac.shift()}catch(h){b.socket.close()}}function d(g){if("string"===typeof g)g=(new TextEncoder).encode(g);else{assert(void 0!==g.byteLength);if(0==g.byteLength)return;g=new Uint8Array(g)}var h= +f;f=!1;h&&10===g.length&&255===g[0]&&255===g[1]&&255===g[2]&&255===g[3]&&112===g[4]&&111===g[5]&&114===g[6]&&116===g[7]?(g=g[8]<<8|g[9],W.mb.bd(a,b),b.port=g,W.mb.Ic(a,b)):(a.Ob.push({hb:b.hb,port:b.port,data:g}),e.websocket.emit("message",a.stream.fd))}var f=!0;x?(b.socket.on("open",c),b.socket.on("message",function(g,h){h.$d&&d((new Uint8Array(g)).buffer)}),b.socket.on("close",function(){e.websocket.emit("close",a.stream.fd)}),b.socket.on("error",function(){a.error=14;e.websocket.emit("error",[a.stream.fd, +a.error,"ECONNREFUSED: Connection refused"])})):(b.socket.onopen=c,b.socket.onclose=function(){e.websocket.emit("close",a.stream.fd)},b.socket.onmessage=function(g){d(g.data)},b.socket.onerror=function(){a.error=14;e.websocket.emit("error",[a.stream.fd,a.error,"ECONNREFUSED: Connection refused"])})},Nb:function(a){if(1===a.type&&a.jb)return a.pending.length?65:0;var b=0,c=1===a.type?W.mb.bc(a,a.ob,a.rb):null;if(a.Ob.length||!c||c&&c.socket.readyState===c.socket.CLOSING||c&&c.socket.readyState===c.socket.CLOSED)b|= +65;if(!c||c&&c.socket.readyState===c.socket.OPEN)b|=4;if(c&&c.socket.readyState===c.socket.CLOSING||c&&c.socket.readyState===c.socket.CLOSED)b|=16;return b},Jb:function(a,b,c){switch(b){case 21531:return b=0,a.Ob.length&&(b=a.Ob[0].data.length),M[c>>2>>>0]=b,0;default:return 28}},close:function(a){if(a.jb){try{a.jb.close()}catch(f){}a.jb=null}for(var b=Object.keys(a.Yb),c=0;cb;b++){var c=Number(a[b]);if(isNaN(c))return null;a[b]=c}return(a[0]|a[1]<<8|a[2]<<16|a[3]<<24)>>>0} +function Fb(a){var b,c,d=[];if(!/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i.test(a))return null;if("::"===a)return[0,0,0,0,0,0,0,0];a=a.startsWith("::")?a.replace("::","Z:"):a.replace("::",":Z:");0>2>>>0]=16);L[a>>1>>>0]=b;M[a+4>>2>>>0]=c;L[a+2>>1>>>0]=Gb(d);R=[0,(Q=0,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[a+8>>2>>>0]=R[0];M[a+12>>2>>>0]=R[1];break;case 10:c=Fb(c);f&&(M[f>>2>>>0]=28);M[a>>2>>>0]=b;M[a+8>>2>>>0]=c[0];M[a+12>>2>>>0]=c[1];M[a+16>>2>>>0]=c[2];M[a+20>>2>>>0]=c[3];L[a+2>>1>>>0]=Gb(d);M[a+4>>2>>>0]=0;M[a+24>>2>>>0]=0;break;default:return 5}return 0} +var Ib=1,Jb={},Kb={};function Lb(a){var b=Eb(a);if(null!==b)return a;b=Fb(a);if(null!==b)return a;Jb[a]?b=Jb[a]:(b=Ib++,assert(65535>b,"exceeded max address mappings of 65535"),b="172.29."+(b&255)+"."+(b&65280),Kb[b]=a,Jb[a]=b);return b}function Mb(a){return(a&255)+"."+(a>>8&255)+"."+(a>>16&255)+"."+(a>>24&255)} +function Nb(a){var b="",c,d=0,f=0,g=0,h=0;a=[a[0]&65535,a[0]>>16,a[1]&65535,a[1]>>16,a[2]&65535,a[2]>>16,a[3]&65535,a[3]>>16];var n=!0;for(c=0;5>c;c++)if(0!==a[c]){n=!1;break}if(n){c=Mb(a[6]|a[7]<<16);if(-1===a[5])return"::ffff:"+c;if(0===a[5])return"0.0.0.0"===c&&(c=""),"0.0.0.1"===c&&(c="1"),"::"+c}for(c=0;8>c;c++)0===a[c]&&(1d&&(d=h,g=c-d+1);for(c=0;8>c;c++)1=g&&cc?":":"");return b} +function Pb(a,b){var c=L[a>>1>>>0],d=Ob(Fa[a+2>>1>>>0]);switch(c){case 2:if(16!==b)return{bb:28};a=M[a+4>>2>>>0];a=Mb(a);break;case 10:if(28!==b)return{bb:28};a=[M[a+8>>2>>>0],M[a+12>>2>>>0],M[a+16>>2>>>0],M[a+20>>2>>>0]];a=Nb(a);break;default:return{bb:5}}return{family:c,hb:a,port:d}}function Qb(a,b,c){if(c&&0===a)return null;a=Pb(a,b);if(a.bb)throw new T.Za(a.bb);b=a.hb;a.hb=(Kb[b]?Kb[b]:null)||a.hb;return a} +function Rb(){void 0===Rb.start&&(Rb.start=Date.now());return 1E3*(Date.now()-Rb.start)|0}var Sb={};function Tb(){if(!Ub){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"===typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:ia||"./this.program"},b;for(b in Sb)void 0===Sb[b]?delete a[b]:a[b]=Sb[b];var c=[];for(b in a)c.push(b+"="+a[b]);Ub=c}return Ub}var Ub,Y={}; +function Vb(a){Vb.buffer||(Vb.buffer=Ca(256),Y["0"]="Success",Y["-1"]="Invalid value for 'ai_flags' field",Y["-2"]="NAME or SERVICE is unknown",Y["-3"]="Temporary failure in name resolution",Y["-4"]="Non-recoverable failure in name res",Y["-6"]="'ai_family' not supported",Y["-7"]="'ai_socktype' not supported",Y["-8"]="SERVICE not supported for 'ai_socktype'",Y["-10"]="Memory allocation failure",Y["-11"]="System error returned in 'errno'",Y["-12"]="Argument buffer overflow");var b="Unknown error"; +a in Y&&(255d-a.getDate())b-=d-a.getDate()+1,a.setDate(1),11>c?a.setMonth(c+1):(a.setMonth(0),a.setFullYear(a.getFullYear()+1));else{a.setDate(a.getDate()+b);break}}return a}function ac(a,b,c,d){a||(a=this);this.parent=a;this.gb=a.gb;this.Wb=null;this.id=T.Kd++;this.name=b;this.mode=c;this.$a={};this.ab={};this.rdev=d} +Object.defineProperties(ac.prototype,{read:{get:function(){return 365===(this.mode&365)},set:function(a){a?this.mode|=365:this.mode&=-366}},write:{get:function(){return 146===(this.mode&146)},set:function(a){a?this.mode|=146:this.mode&=-147}},Ed:{get:function(){return T.ib(this.mode)}},xc:{get:function(){return T.Ub(this.mode)}}});T.hd=ac;T.Td();var zb;function wb(a,b){var c=Array(Aa(a)+1);a=C(a,c,0,c.length);b&&(c.length=a);return c} +var vc={b:function(a,b,c,d){B("Assertion failed: "+H(a)+", at: "+[b?H(b):"unknown filename",c,d?H(d):"unknown function"])},la:function(a,b){return bb(a,b)},ca:function(a,b){return eb(a,b)},ba:function(a,b){return kb(a,b)},na:function(a,b,c,d){try{for(var f=0,g=b?M[b>>2>>>0]:0,h=b?M[b+4>>2>>>0]:0,n=c?M[c>>2>>>0]:0,p=c?M[c+4>>2>>>0]:0,q=d?M[d>>2>>>0]:0,r=d?M[d+4>>2>>>0]:0,w=0,z=0,m=0,t=0,u=0,F=0,J=(b?M[b>>2>>>0]:0)|(c?M[c>>2>>>0]:0)|(d?M[d>>2>>>0]:0),db=(b?M[b+4>>2>>>0]:0)|(c?M[c+4>>2>>>0]:0)|(d?M[d+ +4>>2>>>0]:0),A=0;AA?J&N:db&N){var Oa=T.tb(A);if(!Oa)throw new T.Za(8);var Pa=5;Oa.ab.Nb&&(Pa=Oa.ab.Nb(Oa));Pa&1&&(32>A?g&N:h&N)&&(32>A?w|=N:z|=N,f++);Pa&4&&(32>A?n&N:p&N)&&(32>A?m|=N:t|=N,f++);Pa&2&&(32>A?q&N:r&N)&&(32>A?u|=N:F|=N,f++)}}b&&(M[b>>2>>>0]=w,M[b+4>>2>>>0]=z);c&&(M[c>>2>>>0]=m,M[c+4>>2>>>0]=t);d&&(M[d>>2>>>0]=u,M[d+4>>2>>>0]=F);return f}catch(ob){return"undefined"!==typeof T&&ob instanceof T.Za||B(ob),-ob.bb}},S:function(a,b,c){try{var d=X(a),f=d.qb.accept(d); +b&&Hb(b,f.family,Lb(f.ob),f.rb,c);return f.stream.fd}catch(g){return"undefined"!==typeof T&&g instanceof T.Za||B(g),-g.bb}},pa:function(a,b){try{a=H(a);if(b&-8)var c=-28;else{var d;(d=T.eb(a,{sb:!0}).node)?(a="",b&4&&(a+="r"),b&2&&(a+="w"),b&1&&(a+="x"),c=a&&T.Bb(d,a)?-2:0):c=-44}return c}catch(f){return"undefined"!==typeof T&&f instanceof T.Za||B(f),-f.bb}},V:function(a,b,c){try{var d=X(a),f=Qb(b,c);d.qb.bind(d,f.hb,f.port);return 0}catch(g){return"undefined"!==typeof T&&g instanceof T.Za||B(g), +-g.bb}},U:function(a,b,c){try{var d=X(a),f=Qb(b,c);d.qb.connect(d,f.hb,f.port);return 0}catch(g){return"undefined"!==typeof T&&g instanceof T.Za||B(g),-g.bb}},l:function(a,b,c){Cb=c;try{var d=V(a);switch(b){case 0:var f=Db();return 0>f?-28:T.open(d.path,d.flags,0,f).fd;case 1:case 2:return 0;case 3:return d.flags;case 4:return f=Db(),d.flags|=f,0;case 12:return f=Db(),L[f+0>>1>>>0]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return M[cb()>>2>>>0]=28,-1;default:return-28}}catch(g){return"undefined"!== +typeof T&&g instanceof T.Za||B(g),-g.bb}},va:function(a,b){try{var c=V(a);return Bb(T.stat,c.path,b)}catch(d){return"undefined"!==typeof T&&d instanceof T.Za||B(d),-d.bb}},ga:function(a,b,c){try{var d=V(a);d.Cb||(d.Cb=T.readdir(d.path));a=0;for(var f=T.pb(d,0,1),g=Math.floor(f/280);g>>0,(Q=n,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[b+a>>2>>>0]=R[0];M[b+a+4>>2>>>0]=R[1];R=[280*(g+1)>>>0,(Q=280*(g+1),1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[b+a+8>>2>>>0]=R[0];M[b+a+12>>2>>>0]=R[1];L[b+a+16>>1>>>0]=280;E[b+a+18>>0>>>0]=p;C(h,D,b+a+19,256);a+=280;g+=1}T.pb(d,280*g,0);return a}catch(r){return"undefined"!==typeof T&&r instanceof T.Za||B(r),-r.bb}},Q:function(a,b,c){try{var d=X(a); +if(!d.ob)return-53;Hb(b,d.family,Lb(d.ob),d.rb,c);return 0}catch(f){return"undefined"!==typeof T&&f instanceof T.Za||B(f),-f.bb}},ja:function(a,b){try{return bc(b,0,136),M[b>>2>>>0]=1,M[b+4>>2>>>0]=2,M[b+8>>2>>>0]=3,M[b+12>>2>>>0]=4,0}catch(c){return"undefined"!==typeof T&&c instanceof T.Za||B(c),-c.bb}},R:function(a,b,c){try{k("__sys_getsockname "+a);var d=X(a);Hb(b,d.family,Lb(d.hc||"0.0.0.0"),d.Hb,c);return 0}catch(f){return"undefined"!==typeof T&&f instanceof T.Za||B(f),-f.bb}},N:function(a,b, +c,d,f){try{var g=X(a);return 1===b&&4===c?(M[d>>2>>>0]=g.error,M[f>>2>>>0]=4,g.error=null,0):-50}catch(h){return"undefined"!==typeof T&&h instanceof T.Za||B(h),-h.bb}},B:function(a,b,c){Cb=c;try{var d=V(a);switch(b){case 21509:case 21505:return d.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return d.tty?0:-59;case 21519:if(!d.tty)return-59;var f=Db();return M[f>>2>>>0]=0;case 21520:return d.tty?-28:-59;case 21531:return f=Db(),T.Jb(d,b,f);case 21523:return d.tty?0:-59; +case 21524:return d.tty?0:-59;default:B("bad ioctl syscall "+b)}}catch(g){return"undefined"!==typeof T&&g instanceof T.Za||B(g),-g.bb}},T:function(a,b){try{var c=X(a);c.qb.listen(c,b);return 0}catch(d){return"undefined"!==typeof T&&d instanceof T.Za||B(d),-d.bb}},wa:function(a,b){try{return a=H(a),Bb(T.lstat,a,b)}catch(c){return"undefined"!==typeof T&&c instanceof T.Za||B(c),-c.bb}},xa:function(a,b){try{return a=H(a),a=mb(a),"/"===a[a.length-1]&&(a=a.substr(0,a.length-1)),T.mkdir(a,b,0),0}catch(c){return"undefined"!== +typeof T&&c instanceof T.Za||B(c),-c.bb}},ea:function(a,b,c,d,f,g){try{a:{g<<=12;var h=!1;if(0!==(d&16)&&0!==a%65536)var n=-28;else{if(0!==(d&32)){var p=cc(65536,b);if(!p){n=-48;break a}bc(p,0,b);h=!0}else{var q=T.tb(f);if(!q){n=-8;break a}var r=T.Kb(q,a,b,g,c,d);p=r.Qd;h=r.oc}p>>>=0;Ab[p]={Gd:p,Fd:b,oc:h,fd:f,Pd:c,flags:d,offset:g};n=p}}return n}catch(w){return"undefined"!==typeof T&&w instanceof T.Za||B(w),-w.bb}},fa:function(){return 0},da:function(a,b){try{a>>>=0;if(-1===(a|0)||0===b)var c=-28; +else{var d=Ab[a];if(d&&b===d.Fd){var f=T.tb(d.fd);if(f&&d.Pd&2){var g=d.flags,h=d.offset,n=D.slice(a,a+b);T.Lb(f,n,h,b,g)}Ab[a]=null;d.oc&&dc(d.Gd)}c=0}return c}catch(p){return"undefined"!==typeof T&&p instanceof T.Za||B(p),-p.bb}},sa:function(){return-63},D:function(a,b,c){Cb=c;try{var d=H(a),f=c?Db():0;return T.open(d,b,f).fd}catch(g){return"undefined"!==typeof T&&g instanceof T.Za||B(g),-g.bb}},ma:function(a,b){try{for(var c=0,d=0;d>1>>>0],h=32,n=T.tb(M[f>>2>>>0]);n&& +(h=5,n.ab.Nb&&(h=n.ab.Nb(n)));(h&=g|24)&&c++;L[f+6>>1>>>0]=h}return c}catch(p){return"undefined"!==typeof T&&p instanceof T.Za||B(p),-p.bb}},ia:function(a,b,c,d){try{return d&&(M[d>>2>>>0]=-1,M[d+4>>2>>>0]=-1,M[d+8>>2>>>0]=-1,M[d+12>>2>>>0]=-1),0}catch(f){return"undefined"!==typeof T&&f instanceof T.Za||B(f),-f.bb}},O:function(a,b,c,d,f,g){try{var h=X(a),n=h.qb.ad(h,c);if(!n)return 0;f&&Hb(f,h.family,Lb(n.hb),n.port,g);D.set(n.buffer,b>>>0);return n.buffer.byteLength}catch(p){return"undefined"!== +typeof T&&p instanceof T.Za||B(p),-p.bb}},ua:function(a,b){try{return a=H(a),b=H(b),T.rename(a,b),0}catch(c){return"undefined"!==typeof T&&c instanceof T.Za||B(c),-c.bb}},qa:function(a){try{return a=H(a),T.rmdir(a),0}catch(b){return"undefined"!==typeof T&&b instanceof T.Za||B(b),-b.bb}},P:function(a,b,c,d,f,g){try{var h=X(a),n=Qb(f,g,!0);return n?h.qb.cd(h,E,b,c,n.hb,n.port):T.write(h.stream,E,b,c)}catch(p){return"undefined"!==typeof T&&p instanceof T.Za||B(p),-p.bb}},ha:function(){return 0},M:function(){return-50}, +W:function(a){try{return X(a),-52}catch(b){return"undefined"!==typeof T&&b instanceof T.Za||B(b),-b.bb}},z:function(a,b,c){try{return W.createSocket(a,b,c).stream.fd}catch(d){return"undefined"!==typeof T&&d instanceof T.Za||B(d),-d.bb}},E:function(a,b){try{return a=H(a),Bb(T.stat,a,b)}catch(c){return"undefined"!==typeof T&&c instanceof T.Za||B(c),-c.bb}},ka:function(a){try{if(!a)return-21;var b={__size__:390,domainname:325,machine:260,nodename:65,release:130,sysname:0,version:195};K("Emscripten", +a+b.sysname);K("emscripten",a+b.nodename);K("1.0",a+b.release);K("#1",a+b.version);K("wasm32",a+b.machine);return 0}catch(c){return"undefined"!==typeof T&&c instanceof T.Za||B(c),-c.bb}},ra:function(a){try{return a=H(a),T.unlink(a),0}catch(b){return"undefined"!==typeof T&&b instanceof T.Za||B(b),-b.bb}},Z:function(){throw"longjmp";},a:function(){B()},ta:Rb,ya:bb,H:function(){B("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")}, +Aa:function(){B("To use dlopen, you need to use Emscripten's linking support, see https://github.com/emscripten-core/emscripten/wiki/Linking")},oa:function(){return 4294901760},X:function(a,b,c){D.copyWithin(a>>>0,b>>>0,b+c>>>0)},Y:function(a){var b=D.length;a>>>=0;if(4294901760=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(a,d);0>>16);Ia();var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1}, +aa:function(a){for(var b=ab();ab()-b>2>>>0]=g;K(d,g);c+=d.length+1});return 0}catch(d){return"undefined"!==typeof T&&d instanceof T.Za||B(d),d.bb}},$:function(a,b){try{var c=Tb();M[a>>2>>>0]=c.length;var d=0;c.forEach(function(f){d+=f.length+1});M[b>>2>>>0]=d;return 0}catch(f){return"undefined"!==typeof T&&f instanceof T.Za||B(f),f.bb}},s:function(a){da(a)},t:function(a){try{var b=V(a);T.close(b);return 0}catch(c){return"undefined"!== +typeof T&&c instanceof T.Za||B(c),c.bb}},A:function(a,b){try{var c=V(a);E[b>>0>>>0]=c.tty?2:T.ib(c.mode)?3:T.Db(c.mode)?7:4;return 0}catch(d){return"undefined"!==typeof T&&d instanceof T.Za||B(d),d.bb}},C:function(a,b,c,d){try{a:{for(var f=V(a),g=a=0;g>2>>>0],n=T.read(f,E,M[b+8*g>>2>>>0],h,void 0);if(0>n){var p=-1;break a}a+=n;if(n>2>>>0]=p;return 0}catch(q){return"undefined"!==typeof T&&q instanceof T.Za||B(q),q.bb}},I:function(a,b,c,d,f){try{var g=V(a); +a=4294967296*c+(b>>>0);if(-9007199254740992>=a||9007199254740992<=a)return-61;T.pb(g,a,d);R=[g.position>>>0,(Q=g.position,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[f>>2>>>0]=R[0];M[f+4>>2>>>0]=R[1];g.Cb&&0===a&&0===d&&(g.Cb=null);return 0}catch(h){return"undefined"!==typeof T&&h instanceof T.Za||B(h),h.bb}},v:function(a,b,c,d){try{a:{for(var f=V(a),g=a=0;g>2>>>0],M[b+(8*g+4)>>2>>>0], +void 0);if(0>h){var n=-1;break a}a+=h}n=a}M[d>>2>>>0]=n;return 0}catch(p){return"undefined"!==typeof T&&p instanceof T.Za||B(p),p.bb}},q:Vb,c:function(){return ra},o:function(a,b,c,d){function f(w,z,m,t,u,F){var J=10===w?28:16;u=10===w?Nb(u):Mb(u);J=Ca(J);u=Hb(J,w,u,F);assert(!u);u=Ca(32);M[u+4>>2>>>0]=w;M[u+8>>2>>>0]=z;M[u+12>>2>>>0]=m;M[u+24>>2>>>0]=t;M[u+20>>2>>>0]=J;M[u+16>>2>>>0]=10===w?28:16;M[u+28>>2>>>0]=0;return u}var g=0,h=0,n=0,p=0,q=0,r=0;c&&(n=M[c>>2>>>0],p=M[c+4>>2>>>0],q=M[c+8>>2>>> +0],r=M[c+12>>2>>>0]);q&&!r&&(r=2===q?17:6);!q&&r&&(q=17===r?2:1);0===r&&(r=6);0===q&&(q=1);if(!a&&!b)return-2;if(n&-1088||0!==c&&M[c>>2>>>0]&2&&!a)return-1;if(n&32)return-2;if(0!==q&&1!==q&&2!==q)return-7;if(0!==p&&2!==p&&10!==p)return-6;if(b&&(b=H(b),h=parseInt(b,10),isNaN(h)))return n&1024?-2:-8;if(!a)return 0===p&&(p=2),0===(n&1)&&(2===p?g=ec(2130706433):g=[0,0,0,1]),a=f(p,q,r,null,g,h),M[d>>2>>>0]=a,0;a=H(a);g=Eb(a);if(null!==g)if(0===p||2===p)p=2;else if(10===p&&n&8)g=[0,0,ec(65535),g],p=10; +else return-2;else if(g=Fb(a),null!==g)if(0===p||10===p)p=10;else return-2;if(null!=g)return a=f(p,q,r,a,g,h),M[d>>2>>>0]=a,0;if(n&4)return-2;a=Lb(a);g=Eb(a);0===p?p=2:10===p&&(g=[0,0,ec(65535),g]);a=f(p,q,r,null,g,h);M[d>>2>>>0]=a;return 0},n:function(a,b,c,d,f,g,h){b=Pb(a,b);if(b.bb)return-6;a=b.port;var n=b.hb;b=!1;if(c&&d){var p;if(h&1||!(p=Kb[n]?Kb[n]:null)){if(h&8)return-2}else n=p;c=C(n,D,c,d);c+1>=d&&(b=!0)}f&&g&&(c=C(""+a,D,f,g),c+1>=g&&(b=!0));return b?-12:0},g:function(a){var b=Date.now(); +M[a>>2>>>0]=b/1E3|0;M[a+4>>2>>>0]=b%1E3*1E3|0;return 0},j:eb,Ca:fc,Ba:hc,e:ic,u:jc,x:kc,F:lc,w:mc,K:nc,J:oc,m:pc,p:qc,f:rc,za:sc,G:tc,L:uc,i:kb,y:function(a){fb();var b=new Date(M[a+20>>2>>>0]+1900,M[a+16>>2>>>0],M[a+12>>2>>>0],M[a+8>>2>>>0],M[a+4>>2>>>0],M[a>>2>>>0],0),c=M[a+32>>2>>>0],d=b.getTimezoneOffset(),f=new Date(b.getFullYear(),0,1),g=(new Date(b.getFullYear(),6,1)).getTimezoneOffset(),h=f.getTimezoneOffset(),n=Math.min(h,g);0>c?M[a+32>>2>>>0]=Number(g!=h&&n==d):0>2>>>0]=b.getDay();M[a+28>>2>>>0]=(b.getTime()-f.getTime())/864E5|0;M[a>>2>>>0]=b.getSeconds();M[a+4>>2>>>0]=b.getMinutes();M[a+8>>2>>>0]=b.getHours();M[a+12>>2>>>0]=b.getDate();M[a+16>>2>>>0]=b.getMonth();return b.getTime()/1E3|0},d:function(a){ra=a},r:function(){return 0},h:function(a,b,c,d){function f(m,t,u){for(m="number"===typeof m?m.toString():m||"";m.length +J?-1:0=h(u,m)?0>=h(t,m)?m.getFullYear()+1:m.getFullYear():m.getFullYear()-1}var q=M[d+40>>2>>>0];d={Wd:M[d>>2>>>0],Vd:M[d+4>>2>>>0],jc:M[d+8>>2>>>0],Zb:M[d+12>>2>>>0],Qb:M[d+16>>2>>>0],nb:M[d+20>>2>>>0],kc:M[d+24>>2>>>0],lc:M[d+28>>2>>>0],oe:M[d+32>>2>>>0],Ud:M[d+36>>2>>>0],Xd:q?H(q):""};c=H(c);q={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S", +"%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var r in q)c=c.replace(new RegExp(r,"g"),q[r]);var w="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),z="January February March April May June July August September October November December".split(" ");q={"%a":function(m){return w[m.kc].substring(0, +3)},"%A":function(m){return w[m.kc]},"%b":function(m){return z[m.Qb].substring(0,3)},"%B":function(m){return z[m.Qb]},"%C":function(m){return g((m.nb+1900)/100|0,2)},"%d":function(m){return g(m.Zb,2)},"%e":function(m){return f(m.Zb,2," ")},"%g":function(m){return p(m).toString().substring(2)},"%G":function(m){return p(m)},"%H":function(m){return g(m.jc,2)},"%I":function(m){m=m.jc;0==m?m=12:12m.jc?"AM":"PM"},"%S":function(m){return g(m.Wd,2)},"%t":function(){return"\t"},"%u":function(m){return m.kc||7},"%U":function(m){var t=new Date(m.nb+1900,0,1),u=0===t.getDay()?t:$b(t,7-t.getDay());m=new Date(m.nb+1900,m.Qb,m.Zb);return 0>h(u,m)?g(Math.ceil((31-u.getDate()+(Xb(Wb(m.getFullYear())?Yb:Zb,m.getMonth()-1)-31)+m.getDate())/7),2):0===h(u,t)?"01":"00"},"%V":function(m){var t=new Date(m.nb+ +1901,0,4),u=n(new Date(m.nb+1900,0,4));t=n(t);var F=$b(new Date(m.nb+1900,0,1),m.lc);return 0>h(F,u)?"53":0>=h(t,F)?"01":g(Math.ceil((u.getFullYear()h(u,m)?g(Math.ceil((31-u.getDate()+(Xb(Wb(m.getFullYear())?Yb:Zb,m.getMonth()-1)-31)+m.getDate())/7),2):0===h(u,t)?"01":"00"}, +"%y":function(m){return(m.nb+1900).toString().substring(2)},"%Y":function(m){return m.nb+1900},"%z":function(m){m=m.Ud;var t=0<=m;m=Math.abs(m)/60;return(t?"+":"-")+String("0000"+(m/60*100+m%60)).slice(-4)},"%Z":function(m){return m.Xd},"%%":function(){return"%"}};for(r in q)c.includes(r)&&(c=c.replace(new RegExp(r,"g"),q[r](d)));r=wb(c,!1);if(r.length>b)return 0;E.set(r,a>>>0);return r.length-1},k:function(a){var b=Date.now()/1E3|0;a&&(M[a>>2>>>0]=b);return b}}; +(function(){function a(f){e.asm=f.exports;ta=e.asm.Da;Ia();O=e.asm.Ia;Ka.unshift(e.asm.Ea);Ua()}function b(f){a(f.instance)}function c(f){return Ya().then(function(g){return WebAssembly.instantiate(g,d)}).then(f,function(g){k("failed to asynchronously prepare wasm: "+g);B(g)})}var d={a:vc};Ta();if(e.instantiateWasm)try{return e.instantiateWasm(d,a)}catch(f){return k("Module.instantiateWasm callback failed with error: "+f),!1}(function(){return sa||"function"!==typeof WebAssembly.instantiateStreaming|| +Va()||P.startsWith("file://")||"function"!==typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(b,function(g){k("wasm streaming compile failed: "+g);k("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ba);return{}})();e.___wasm_call_ctors=function(){return(e.___wasm_call_ctors=e.asm.Ea).apply(null,arguments)}; +var dc=e._free=function(){return(dc=e._free=e.asm.Fa).apply(null,arguments)},bc=e._memset=function(){return(bc=e._memset=e.asm.Ga).apply(null,arguments)},Ca=e._malloc=function(){return(Ca=e._malloc=e.asm.Ha).apply(null,arguments)},cb=e.___errno_location=function(){return(cb=e.___errno_location=e.asm.Ja).apply(null,arguments)},cc=e._memalign=function(){return(cc=e._memalign=e.asm.Ka).apply(null,arguments)},Ob=e._ntohs=function(){return(Ob=e._ntohs=e.asm.La).apply(null,arguments)},Gb=e._htons=function(){return(Gb= +e._htons=e.asm.Ma).apply(null,arguments)};e._main=function(){return(e._main=e.asm.Na).apply(null,arguments)}; +var ec=e._htonl=function(){return(ec=e._htonl=e.asm.Oa).apply(null,arguments)},jb=e.__get_tzname=function(){return(jb=e.__get_tzname=e.asm.Pa).apply(null,arguments)},ib=e.__get_daylight=function(){return(ib=e.__get_daylight=e.asm.Qa).apply(null,arguments)},hb=e.__get_timezone=function(){return(hb=e.__get_timezone=e.asm.Ra).apply(null,arguments)},G=e.stackSave=function(){return(G=e.stackSave=e.asm.Sa).apply(null,arguments)},I=e.stackRestore=function(){return(I=e.stackRestore=e.asm.Ta).apply(null,arguments)}, +xa=e.stackAlloc=function(){return(xa=e.stackAlloc=e.asm.Ua).apply(null,arguments)},Z=e._setThrew=function(){return(Z=e._setThrew=e.asm.Va).apply(null,arguments)},wc=e.dynCall_vijjjid=function(){return(wc=e.dynCall_vijjjid=e.asm.Wa).apply(null,arguments)},xc=e.dynCall_iiiijj=function(){return(xc=e.dynCall_iiiijj=e.asm.Xa).apply(null,arguments)},yc=e.dynCall_iij=function(){return(yc=e.dynCall_iij=e.asm.Ya).apply(null,arguments)};e._ff_h264_cabac_tables=2553548; +function ic(a,b,c){var d=G();try{return O.get(a)(b,c)}catch(f){I(d);if(f!==f+0&&"longjmp"!==f)throw f;Z(1,0)}}function pc(a,b){var c=G();try{O.get(a)(b)}catch(d){I(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}}function rc(a,b,c,d,f){var g=G();try{O.get(a)(b,c,d,f)}catch(h){I(g);if(h!==h+0&&"longjmp"!==h)throw h;Z(1,0)}}function qc(a,b,c){var d=G();try{O.get(a)(b,c)}catch(f){I(d);if(f!==f+0&&"longjmp"!==f)throw f;Z(1,0)}} +function kc(a,b,c,d,f){var g=G();try{return O.get(a)(b,c,d,f)}catch(h){I(g);if(h!==h+0&&"longjmp"!==h)throw h;Z(1,0)}}function mc(a,b,c,d,f,g,h,n,p){var q=G();try{return O.get(a)(b,c,d,f,g,h,n,p)}catch(r){I(q);if(r!==r+0&&"longjmp"!==r)throw r;Z(1,0)}}function fc(a){var b=G();try{return O.get(a)()}catch(c){I(b);if(c!==c+0&&"longjmp"!==c)throw c;Z(1,0)}}function hc(a,b){var c=G();try{return O.get(a)(b)}catch(d){I(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}} +function jc(a,b,c,d){var f=G();try{return O.get(a)(b,c,d)}catch(g){I(f);if(g!==g+0&&"longjmp"!==g)throw g;Z(1,0)}}function tc(a,b,c,d,f,g,h,n,p){var q=G();try{O.get(a)(b,c,d,f,g,h,n,p)}catch(r){I(q);if(r!==r+0&&"longjmp"!==r)throw r;Z(1,0)}}function lc(a,b,c,d,f,g){var h=G();try{return O.get(a)(b,c,d,f,g)}catch(n){I(h);if(n!==n+0&&"longjmp"!==n)throw n;Z(1,0)}}function sc(a,b,c,d,f,g,h){var n=G();try{O.get(a)(b,c,d,f,g,h)}catch(p){I(n);if(p!==p+0&&"longjmp"!==p)throw p;Z(1,0)}} +function uc(a,b,c,d,f,g,h,n,p,q){var r=G();try{wc(a,b,c,d,f,g,h,n,p,q)}catch(w){I(r);if(w!==w+0&&"longjmp"!==w)throw w;Z(1,0)}}function nc(a,b,c,d,f,g,h,n){var p=G();try{return xc(a,b,c,d,f,g,h,n)}catch(q){I(p);if(q!==q+0&&"longjmp"!==q)throw q;Z(1,0)}}function oc(a,b,c,d){var f=G();try{return yc(a,b,c,d)}catch(g){I(f);if(g!==g+0&&"longjmp"!==g)throw g;Z(1,0)}}e.ccall=wa; +e.cwrap=function(a,b,c,d){c=c||[];var f=c.every(function(g){return"number"===g});return"string"!==b&&f&&!d?va(a):function(){return wa(a,b,c,arguments,d)}}; +e.setValue=function(a,b,c){c=c||"i8";"*"===c.charAt(c.length-1)&&(c="i32");switch(c){case "i1":E[a>>0>>>0]=b;break;case "i8":E[a>>0>>>0]=b;break;case "i16":L[a>>1>>>0]=b;break;case "i32":M[a>>2>>>0]=b;break;case "i64":R=[b>>>0,(Q=b,1<=+Math.abs(Q)?0>>0:~~+Math.ceil((Q-+(~~Q>>>0))/4294967296)>>>0:0)];M[a>>2>>>0]=R[0];M[a+4>>2>>>0]=R[1];break;case "float":Ga[a>>2>>>0]=b;break;case "double":Ha[a>>3>>>0]=b;break;default:B("invalid type for setValue: "+ +c)}};e.writeAsciiToMemory=K;e.FS=T;var zc;function ca(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Sa=function Ac(){zc||Bc();zc||(Sa=Ac)}; +function Bc(a){function b(){if(!zc&&(zc=!0,e.calledRun=!0,!ua)){e.noFSInit||T.Tb.wc||T.Tb();T.Yc=!1;W.root=T.gb(W,{},null);Za(Ka);Za(La);aa(e);if(e.onRuntimeInitialized)e.onRuntimeInitialized();if(Cc){var c=a,d=e._main;c=c||[];var f=c.length+1,g=xa(4*(f+1));M[g>>>2]=Da(ia);for(var h=1;h>2)+h>>>0]=Da(c[h-1]);M[(g>>2)+f>>>0]=0;try{var n=d(f,g);da(n,!0)}catch(p){p instanceof ca||"unwind"==p||((c=p)&&"object"===typeof p&&p.stack&&(c=[p,p.stack]),k("exception thrown: "+c),ja(1,p))}finally{}}if(e.postRun)for("function"== +typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;)c=e.postRun.shift(),Ma.unshift(c);Za(Ma)}}a=a||ha;if(!(0>/*C_STRUCTS.pthread.threadExitCode*/2,(ex instanceof Module["ExitStatus"])?ex.status:-2);/*A custom entry specific to Emscripten denoting that the thread crashed.*/Atomics.store(Module["HEAPU32"],(threadInfoStruct+0)>>/*C_STRUCTS.pthread.threadStatus*/2,1);Module["_emscripten_futex_wake"](threadInfoStruct+0,/*C_STRUCTS.pthread.threadStatus*/2147483647);if(!(ex instanceof Module["ExitStatus"]))throw ex}}}else if(e.data.cmd==="cancel"){if(threadInfoStruct){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(threadInfoStruct){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){self={location:{href:__filename}};var onmessage=this.onmessage;var nodeWorkerThreads=require("worker_threads");global.Worker=nodeWorkerThreads.Worker;var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var nodeFS=require("fs");var nodeRead=function(filename){return nodeFS.readFileSync(filename,"utf8")};function globalEval(x){global.require=require;global.Module=Module;eval.call(null,x)}importScripts=function(f){globalEval(nodeRead(f))};postMessage=function(msg){parentPort.postMessage(msg)};if(typeof performance==="undefined"){performance={now:function(){return Date.now()}}}} diff --git a/public/manifest.json b/public/manifest.json index fd62a6939..601c59836 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,17 +3,17 @@ "name": "ente | encrypted photo storage", "icons": [ { - "src": "/images/ente-192.png", + "src": "/images/ente/192.png", "type": "image/png", "sizes": "192x192" }, { - "src": "/images/ente-256.png", + "src": "/images/ente/256.png", "type": "image/png", "sizes": "256x256" }, { - "src": "/images/ente-512.png", + "src": "/images/ente/512.png", "type": "image/png", "sizes": "512x512" } diff --git a/public/offline.html b/public/offline.html index 057084fd0..31f54dcec 100644 --- a/public/offline.html +++ b/public/offline.html @@ -49,11 +49,11 @@

seems like you are offline :(

please check your internet connection
- \ No newline at end of file + diff --git a/public/plus-sign.png b/public/plus-sign.png deleted file mode 100644 index 38e90b29c..000000000 Binary files a/public/plus-sign.png and /dev/null differ diff --git a/public/robots.txt b/public/robots.txt index 6f27bb66a..5e1daca27 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,2 +1,3 @@ User-agent: * +Allow: /.well-known/* Disallow: \ No newline at end of file diff --git a/public/share_icon.png b/public/share_icon.png deleted file mode 100644 index 97bd7f8f6..000000000 Binary files a/public/share_icon.png and /dev/null differ diff --git a/sentry.client.config.js b/sentry.client.config.js index 8d85c07d9..3eec2c8fc 100644 --- a/sentry.client.config.js +++ b/sentry.client.config.js @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/nextjs'; import { getSentryTunnelURL } from 'utils/common/apiUtil'; -import { getUserAnonymizedID } from 'utils/user'; +import { getSentryUserID } from 'utils/user'; import { getSentryDSN, getSentryENV, @@ -13,7 +13,7 @@ const SENTRY_ENV = getSentryENV(); const SENTRY_RELEASE = getSentryRelease(); const IS_ENABLED = getIsSentryEnabled(); -Sentry.setUser({ id: getUserAnonymizedID() }); +Sentry.setUser({ id: getSentryUserID() }); Sentry.init({ dsn: SENTRY_DSN, enabled: IS_ENABLED, @@ -22,6 +22,18 @@ Sentry.init({ attachStacktrace: true, autoSessionTracking: false, tunnel: getSentryTunnelURL(), + beforeSend(event) { + event.request = event.request || {}; + const currentURL = new URL(document.location.href); + currentURL.hash = ''; + event.request.url = currentURL; + return event; + }, + integrations: function (i) { + return i.filter(function (i) { + return i.name !== 'Breadcrumbs'; + }); + }, // ... // Note: if you want to override the automatic release value, do not set a // `release` value here - use the environment variable `SENTRY_RELEASE`, so diff --git a/src/components/AddToCollectionBtn.tsx b/src/components/AddToCollectionBtn.tsx index 07f0f0597..5316923f9 100644 --- a/src/components/AddToCollectionBtn.tsx +++ b/src/components/AddToCollectionBtn.tsx @@ -1,7 +1,7 @@ +import { styled } from '@mui/material'; import React from 'react'; -import styled from 'styled-components'; -const Wrapper = styled.button` +const Wrapper = styled('button')` border: none; background-color: #51cd7c; position: fixed; diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx new file mode 100644 index 000000000..773729509 --- /dev/null +++ b/src/components/Badge.tsx @@ -0,0 +1,10 @@ +import { Paper, styled } from '@mui/material'; +import { CSSProperties } from '@mui/styled-engine'; + +export const Badge = styled(Paper)(({ theme }) => ({ + padding: '2px 4px', + backgroundColor: theme.palette.glass.main, + color: theme.palette.glass.contrastText, + textTransform: 'uppercase', + ...(theme.typography.mini as CSSProperties), +})); diff --git a/src/components/ChangeEmail.tsx b/src/components/ChangeEmail.tsx index 0eb94a694..f577ca10c 100644 --- a/src/components/ChangeEmail.tsx +++ b/src/components/ChangeEmail.tsx @@ -1,53 +1,30 @@ import { Formik, FormikHelpers } from 'formik'; -import React, { useContext, useEffect, useRef, useState } from 'react'; -import { Button, Col, Form, FormControl } from 'react-bootstrap'; +import React, { useRef, useState } from 'react'; import * as Yup from 'yup'; import constants from 'utils/strings/constants'; import SubmitButton from 'components/SubmitButton'; import router from 'next/router'; -import { changeEmail, getOTTForEmailChange } from 'services/userService'; -import styled from 'styled-components'; -import { AppContext, FLASH_MESSAGE_TYPE } from 'pages/_app'; +import { changeEmail, sendOTTForEmailChange } from 'services/userService'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; import { PAGES } from 'constants/pages'; +import { Alert, TextField } from '@mui/material'; +import Container from './Container'; +import LinkButton from './pages/gallery/LinkButton'; +import FormPaperFooter from './Form/FormPaper/Footer'; +import { sleep } from 'utils/common'; interface formValues { email: string; ott?: string; } -const EmailRow = styled.div` - display: flex; - flex-wrap: wrap; - border: 1px solid grey; - margin-bottom: 19px; - align-items: center; - text-align: left; - color: #fff; -`; - -interface Props { - showMessage: (value: boolean) => void; - setEmail: (email: string) => void; -} -function ChangeEmailForm(props: Props) { +function ChangeEmailForm() { const [loading, setLoading] = useState(false); const [ottInputVisible, setShowOttInputVisibility] = useState(false); - const emailInputElement = useRef(null); const ottInputRef = useRef(null); - const appContext = useContext(AppContext); - - useEffect(() => { - setTimeout(() => { - emailInputElement.current?.focus(); - }, 250); - }, []); - - useEffect(() => { - if (!ottInputVisible) { - props.showMessage(false); - } - }, [ottInputVisible]); + const [email, setEmail] = useState(null); + const [showMessage, setShowMessage] = useState(false); + const [success, setSuccess] = useState(false); const requestOTT = async ( { email }: formValues, @@ -55,10 +32,10 @@ function ChangeEmailForm(props: Props) { ) => { try { setLoading(true); - await getOTTForEmailChange(email); - props.setEmail(email); + await sendOTTForEmailChange(email); + setEmail(email); setShowOttInputVisibility(true); - props.showMessage(true); + setShowMessage(true); setTimeout(() => { ottInputRef.current?.focus(); }, 250); @@ -76,17 +53,18 @@ function ChangeEmailForm(props: Props) { setLoading(true); await changeEmail(email, ott); setData(LS_KEYS.USER, { ...getData(LS_KEYS.USER), email }); - appContext.setDisappearingFlashMessage({ - message: constants.EMAIL_UDPATE_SUCCESSFUL, - type: FLASH_MESSAGE_TYPE.SUCCESS, - }); + setLoading(false); + setSuccess(true); + await sleep(1000); router.push(PAGES.GALLERY); } catch (e) { + setLoading(false); setFieldError('ott', `${constants.INCORRECT_CODE}`); } - setLoading(false); }; + const goToGallery = () => router.push(PAGES.GALLERY); + return ( initialValues={{ email: '' }} @@ -94,80 +72,80 @@ function ChangeEmailForm(props: Props) { email: Yup.string() .email(constants.EMAIL_ERROR) .required(constants.REQUIRED), + ott: + ottInputVisible && + Yup.string().required(constants.REQUIRED), })} validateOnChange={false} validateOnBlur={false} onSubmit={!ottInputVisible ? requestOTT : requestEmailChange}> - {({ values, errors, touched, handleChange, handleSubmit }) => ( -
- {!ottInputVisible ? ( - - ( + <> + {showMessage && ( + setShowMessage(false)}> + {constants.EMAIL_SENT({ email })} + + )} + + + - - {errors.email} - - - ) : ( - <> - - {values.email} - - - - - - - - {errors.ott} - - - - )} + )} + + + - -
- - + + {ottInputVisible && ( + + setShowOttInputVisibility(false) + }> + {constants.CHANGE_EMAIL}? + + )} + + {constants.GO_BACK} + + + )} ); diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx deleted file mode 100644 index ae9d21c72..000000000 --- a/src/components/CodeBlock.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import styled from 'styled-components'; -import { FreeFlowText, IconButton } from './Container'; -import CopyIcon from './icons/CopyIcon'; -import React, { useState } from 'react'; -import { Tooltip, OverlayTrigger } from 'react-bootstrap'; -import TickIcon from './icons/TickIcon'; -import EnteSpinner from './EnteSpinner'; - -const Wrapper = styled.div` - position: relative; - margin: 20px 0; -`; -const CopyButtonWrapper = styled(IconButton)` - position: absolute; - top: 0px; - right: 0px; - background: none !important; - margin: 10px; -`; - -export const CodeWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - background: #1a1919; - padding: 37px 40px 20px 20px; - color: white; - width: 100%; -`; - -type Iprops = React.PropsWithChildren<{ - code: string; -}>; -export const CodeBlock = (props: Iprops) => { - const [copied, setCopied] = useState(false); - - const copyToClipboardHelper = (text: string) => () => { - navigator.clipboard.writeText(text); - setCopied(true); - setTimeout(() => setCopied(false), 1000); - }; - - const RenderCopiedMessage = (props) => { - const { style, ...rest } = props; - return ( - - copied - - ); - }; - - return ( - - - {props.code ? ( - {props.code} - ) : ( - - )} - - {props.code && ( - - - {copied ? : } - - - )} - - ); -}; diff --git a/src/components/CodeBlock/CopyButton.tsx b/src/components/CodeBlock/CopyButton.tsx new file mode 100644 index 000000000..9686c0392 --- /dev/null +++ b/src/components/CodeBlock/CopyButton.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; +import { CopyButtonWrapper } from './styledComponents'; +import DoneIcon from '@mui/icons-material/Done'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import { Tooltip } from '@mui/material'; + +export default function CopyButton({ code, copied, copyToClipboardHelper }) { + return ( + + + {copied ? ( + + ) : ( + + )} + + + ); +} diff --git a/src/components/CodeBlock/index.tsx b/src/components/CodeBlock/index.tsx new file mode 100644 index 000000000..e3e7aff07 --- /dev/null +++ b/src/components/CodeBlock/index.tsx @@ -0,0 +1,47 @@ +import { FreeFlowText } from '../Container'; +import React, { useState } from 'react'; +import EnteSpinner from '../EnteSpinner'; +import { Wrapper, CodeWrapper } from './styledComponents'; +import CopyButton from './CopyButton'; +import { BoxProps } from '@mui/material'; + +type Iprops = React.PropsWithChildren<{ + code: string; + wordBreak?: 'normal' | 'break-all' | 'keep-all' | 'break-word'; +}>; + +export default function CodeBlock({ + code, + wordBreak, + ...props +}: BoxProps<'div', Iprops>) { + const [copied, setCopied] = useState(false); + + const copyToClipboardHelper = (text: string) => () => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 1000); + }; + + if (!code) { + return ( + + + + ); + } + return ( + + + + {code} + + + + + ); +} diff --git a/src/components/CodeBlock/styledComponents.tsx b/src/components/CodeBlock/styledComponents.tsx new file mode 100644 index 000000000..ff9a49f6f --- /dev/null +++ b/src/components/CodeBlock/styledComponents.tsx @@ -0,0 +1,20 @@ +import { IconButton } from '@mui/material'; +import { CenteredFlex } from 'components/Container'; +import { styled } from '@mui/material'; +export const Wrapper = styled(CenteredFlex)` + position: relative; + background: ${({ theme }) => theme.palette.accent.dark}; + border-radius: ${({ theme }) => theme.shape.borderRadius}px; + min-height: 80px; +`; +export const CopyButtonWrapper = styled(IconButton)` + position: absolute; + top: 0px; + right: 0px; + margin-top: ${({ theme }) => theme.spacing(1)}; +`; + +export const CodeWrapper = styled('div')` + padding: 16px 36px 16px 16px; + border-radius: ${({ theme }) => theme.shape.borderRadius}px; +`; diff --git a/src/components/CollectionShare.tsx b/src/components/CollectionShare.tsx deleted file mode 100644 index 0dc3315b8..000000000 --- a/src/components/CollectionShare.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import constants from 'utils/strings/constants'; -import { Formik, FormikHelpers } from 'formik'; -import * as Yup from 'yup'; -import Form from 'react-bootstrap/Form'; -import FormControl from 'react-bootstrap/FormControl'; -import { Button, Col, Table } from 'react-bootstrap'; -import { DeadCenter, GalleryContext } from 'pages/gallery'; -import { User } from 'types/user'; -import { - shareCollection, - unshareCollection, - createShareableURL, - deleteShareableURL, -} from 'services/collectionService'; -import { getData, LS_KEYS } from 'utils/storage/localStorage'; -import SubmitButton from './SubmitButton'; -import MessageDialog from './MessageDialog'; -import { Collection } from 'types/collection'; -import { appendCollectionKeyToShareURL } from 'utils/collection'; -import { FlexWrapper } from './Container'; -import { CodeBlock } from './CodeBlock'; -import { ButtonVariant, getVariantColor } from './pages/gallery/LinkButton'; -import { handleSharingErrors } from 'utils/error'; -import { sleep } from 'utils/common'; - -interface Props { - show: boolean; - onHide: () => void; - collection: Collection; - syncWithRemote: () => Promise; -} -interface formValues { - email: string; -} -interface ShareeProps { - sharee: User; - collectionUnshare: (sharee: User) => void; -} - -function CollectionShare(props: Props) { - const [loading, setLoading] = useState(false); - const galleryContext = useContext(GalleryContext); - const [sharableLinkError, setSharableLinkError] = useState(null); - const [publicShareUrl, setPublicShareUrl] = useState(null); - - useEffect(() => { - const main = async () => { - if (props.collection?.publicURLs?.[0]?.url) { - const t = await appendCollectionKeyToShareURL( - props.collection?.publicURLs?.[0]?.url, - props.collection.key - ); - setPublicShareUrl(t); - } else { - setPublicShareUrl(null); - } - }; - main(); - }, [props.collection]); - - const collectionShare = async ( - { email }: formValues, - { resetForm, setFieldError }: FormikHelpers - ) => { - try { - setLoading(true); - galleryContext.startLoading(); - const user: User = getData(LS_KEYS.USER); - if (email === user.email) { - setFieldError('email', constants.SHARE_WITH_SELF); - } else if ( - props.collection?.sharees?.find( - (value) => value.email === email - ) - ) { - setFieldError('email', constants.ALREADY_SHARED(email)); - } else { - await shareCollection(props.collection, email); - await sleep(2000); - await galleryContext.syncWithRemote(false, true); - resetForm(); - } - } catch (e) { - const errorMessage = handleSharingErrors(e); - setFieldError('email', errorMessage); - } finally { - setLoading(false); - galleryContext.finishLoading(); - } - }; - const collectionUnshare = async (sharee) => { - try { - galleryContext.startLoading(); - await unshareCollection(props.collection, sharee.email); - await sleep(2000); - await galleryContext.syncWithRemote(false, true); - } finally { - galleryContext.finishLoading(); - } - }; - - const createSharableURLHelper = async () => { - try { - galleryContext.startLoading(); - const publicURL = await createShareableURL(props.collection); - const sharableURL = await appendCollectionKeyToShareURL( - publicURL.url, - props.collection.key - ); - setPublicShareUrl(sharableURL); - galleryContext.syncWithRemote(false, true); - } catch (e) { - const errorMessage = handleSharingErrors(e); - setSharableLinkError(errorMessage); - } finally { - galleryContext.finishLoading(); - } - }; - - const disablePublicSharingHelper = async () => { - try { - galleryContext.startLoading(); - await deleteShareableURL(props.collection); - setPublicShareUrl(null); - galleryContext.syncWithRemote(false, true); - } catch (e) { - const errorMessage = handleSharingErrors(e); - setSharableLinkError(errorMessage); - } finally { - galleryContext.finishLoading(); - } - }; - - const disablePublicSharing = () => { - galleryContext.setDialogMessage({ - title: constants.DISABLE_PUBLIC_SHARING, - content: constants.DISABLE_PUBLIC_SHARING_MESSAGE, - close: { text: constants.CANCEL }, - proceed: { - text: constants.DISABLE, - action: disablePublicSharingHelper, - variant: ButtonVariant.danger, - }, - }); - }; - - const handleCollectionPublicSharing = () => { - setSharableLinkError(null); - if (publicShareUrl) { - disablePublicSharing(); - } else { - createSharableURLHelper(); - } - }; - - const ShareeRow = ({ sharee, collectionUnshare }: ShareeProps) => ( - - {sharee.email} - - - - - ); - - if (!props.collection) { - return <>; - } - return ( - - -
- {constants.SHARE_WITH_PEOPLE} -
-

- - initialValues={{ email: '' }} - validationSchema={Yup.object().shape({ - email: Yup.string() - .email(constants.EMAIL_ERROR) - .required(constants.REQUIRED), - })} - validateOnChange={false} - validateOnBlur={false} - onSubmit={collectionShare}> - {({ - values, - errors, - touched, - handleChange, - handleSubmit, - }) => ( -

- - - - - {errors.email} - - - - - - -
- )} - - {props.collection.sharees?.length > 0 && ( - <> -

{constants.SHAREES}

- - - - {props.collection.sharees?.map((sharee) => ( - - ))} - -
- - )} -
-
- - - {constants.PUBLIC_SHARING} - - - - {sharableLinkError && ( - - {sharableLinkError} - - )} -
- {publicShareUrl ? ( -
- -
- ) : ( -
- )} - - - ); -} -export default CollectionShare; diff --git a/src/components/Collections/AllCollections/CollectionSort/index.tsx b/src/components/Collections/AllCollections/CollectionSort/index.tsx new file mode 100644 index 000000000..2f7152761 --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/index.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { COLLECTION_SORT_BY } from 'constants/collection'; +import SortIcon from '@mui/icons-material/Sort'; +import CollectionSortOptions from './options'; +import OverflowMenu from 'components/OverflowMenu/menu'; + +export interface CollectionSortProps { + setCollectionSortBy: (sortBy: COLLECTION_SORT_BY) => void; + activeSortBy: COLLECTION_SORT_BY; + nestedInDialog?: boolean; + disableBG?: boolean; +} + +export default function CollectionSort(props: CollectionSortProps) { + return ( + } + menuPaperProps={{ + sx: { + backgroundColor: (theme) => + props.nestedInDialog && + theme.palette.background.overPaper, + }, + }} + triggerButtonProps={{ + sx: { + background: (theme) => + !props.disableBG && theme.palette.fill.dark, + }, + }}> + + + ); +} diff --git a/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx b/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx new file mode 100644 index 000000000..5488857fc --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/optionCreator.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { COLLECTION_SORT_BY } from 'constants/collection'; +import TickIcon from '@mui/icons-material/Done'; +import { CollectionSortProps } from '.'; +import { OverflowMenuOption } from 'components/OverflowMenu/option'; +import { SvgIcon } from '@mui/material'; + +const SortByOptionCreator = + ({ setCollectionSortBy, activeSortBy }: CollectionSortProps) => + (props: { sortBy: COLLECTION_SORT_BY; children: any }) => { + const handleClick = () => { + setCollectionSortBy(props.sortBy); + }; + + return ( + : + }> + {props.children} + + ); + }; + +export default SortByOptionCreator; diff --git a/src/components/Collections/AllCollections/CollectionSort/options.tsx b/src/components/Collections/AllCollections/CollectionSort/options.tsx new file mode 100644 index 000000000..27d0a8b43 --- /dev/null +++ b/src/components/Collections/AllCollections/CollectionSort/options.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { COLLECTION_SORT_BY } from 'constants/collection'; +import constants from 'utils/strings/constants'; +import SortByOptionCreator from './optionCreator'; +import { CollectionSortProps } from '.'; + +export default function CollectionSortOptions(props: CollectionSortProps) { + const SortByOption = SortByOptionCreator(props); + + return ( + <> + + {constants.SORT_BY_NAME} + + + {constants.SORT_BY_CREATION_TIME_DESCENDING} + + + {constants.SORT_BY_CREATION_TIME_ASCENDING} + + + {constants.SORT_BY_UPDATION_TIME_DESCENDING} + + + ); +} diff --git a/src/components/Collections/AllCollections/collectionCard.tsx b/src/components/Collections/AllCollections/collectionCard.tsx new file mode 100644 index 000000000..2c4ae51c8 --- /dev/null +++ b/src/components/Collections/AllCollections/collectionCard.tsx @@ -0,0 +1,30 @@ +import { Typography } from '@mui/material'; +import constants from 'utils/strings/constants'; +import React from 'react'; +import CollectionCard from '../CollectionCard'; +import { CollectionSummary } from 'types/collection'; +import { AllCollectionTile, AllCollectionTileText } from '../styledComponents'; + +interface Iprops { + collectionSummary: CollectionSummary; + onCollectionClick: (collectionID: number) => void; +} + +export default function AllCollectionCard({ + onCollectionClick, + collectionSummary, +}: Iprops) { + return ( + onCollectionClick(collectionSummary.id)}> + + {collectionSummary.name} + + {constants.PHOTO_COUNT(collectionSummary.fileCount)} + + + + ); +} diff --git a/src/components/Collections/AllCollections/content.tsx b/src/components/Collections/AllCollections/content.tsx new file mode 100644 index 000000000..038b866f7 --- /dev/null +++ b/src/components/Collections/AllCollections/content.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { DialogContent } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import AllCollectionCard from './collectionCard'; +import { CollectionSummary } from 'types/collection'; + +interface Iprops { + collectionSummaries: CollectionSummary[]; + onCollectionClick: (id?: number) => void; +} +export default function AllCollectionContent({ + collectionSummaries, + onCollectionClick, +}: Iprops) { + return ( + + + {collectionSummaries.map((collectionSummary) => ( + + ))} + + + ); +} diff --git a/src/components/Collections/AllCollections/dialog.tsx b/src/components/Collections/AllCollections/dialog.tsx new file mode 100644 index 000000000..ccd69e235 --- /dev/null +++ b/src/components/Collections/AllCollections/dialog.tsx @@ -0,0 +1,41 @@ +import { Dialog, Slide, styled } from '@mui/material'; +import React from 'react'; +import PropTypes from 'prop-types'; + +export const AllCollectionDialog = styled(Dialog)<{ + position: 'flex-start' | 'center' | 'flex-end'; +}>(({ theme, position }) => ({ + '& .MuiDialog-container': { + justifyContent: position, + }, + '& .MuiPaper-root': { + maxWidth: '494px', + }, + '& .MuiDialogTitle-root': { + padding: theme.spacing(2), + paddingRight: theme.spacing(1), + }, + '& .MuiDialogContent-root': { + padding: theme.spacing(2), + }, + [theme.breakpoints.down(559)]: { + '& .MuiPaper-root': { + width: '324px', + }, + '& .MuiDialogContent-root': { + padding: 6, + }, + }, +})); + +AllCollectionDialog.propTypes = { + children: PropTypes.node, + onClose: PropTypes.func.isRequired, +}; + +export const Transition = (direction: 'left' | 'right' | 'up') => + React.forwardRef( + (props: { children: React.ReactElement }, ref) => { + return ; + } + ); diff --git a/src/components/Collections/AllCollections/header.tsx b/src/components/Collections/AllCollections/header.tsx new file mode 100644 index 000000000..ae62102b4 --- /dev/null +++ b/src/components/Collections/AllCollections/header.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Box, DialogTitle, Stack, Typography } from '@mui/material'; +import { + FlexWrapper, + FluidContainer, + IconButtonWithBG, +} from 'components/Container'; +import CollectionSort from 'components/Collections/AllCollections/CollectionSort'; +import constants from 'utils/strings/constants'; +import Close from '@mui/icons-material/Close'; + +export default function AllCollectionsHeader({ + onClose, + collectionCount, + collectionSortBy, + setCollectionSortBy, +}) { + return ( + + + + + + {constants.ALL_ALBUMS} + + + {`${collectionCount} ${constants.ALBUMS}`} + + + + + + + + + + + + ); +} diff --git a/src/components/Collections/AllCollections/index.tsx b/src/components/Collections/AllCollections/index.tsx new file mode 100644 index 000000000..b6b7316ae --- /dev/null +++ b/src/components/Collections/AllCollections/index.tsx @@ -0,0 +1,60 @@ +import React, { useContext } from 'react'; +import Divider from '@mui/material/Divider'; +import { COLLECTION_SORT_BY } from 'constants/collection'; +import { + Transition, + AllCollectionDialog, +} from 'components/Collections/AllCollections/dialog'; +import AllCollectionsHeader from './header'; +import { CollectionSummary } from 'types/collection'; +import AllCollectionContent from './content'; +import { AppContext } from 'pages/_app'; + +interface Iprops { + open: boolean; + onClose: () => void; + collectionSummaries: CollectionSummary[]; + setActiveCollection: (id?: number) => void; + collectionSortBy: COLLECTION_SORT_BY; + setCollectionSortBy: (v: COLLECTION_SORT_BY) => void; +} + +const LeftSlideTransition = Transition('up'); + +export default function AllCollections(props: Iprops) { + const { + collectionSummaries, + open, + onClose, + setActiveCollection, + collectionSortBy, + setCollectionSortBy, + } = props; + const { isMobile } = useContext(AppContext); + + const onCollectionClick = (collectionID: number) => { + setActiveCollection(collectionID); + onClose(); + }; + + return ( + + + + + + ); +} diff --git a/src/components/Collections/CollectionCard.tsx b/src/components/Collections/CollectionCard.tsx new file mode 100644 index 000000000..ff545be9e --- /dev/null +++ b/src/components/Collections/CollectionCard.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { GalleryContext } from 'pages/gallery'; +import { useState, useContext, useEffect } from 'react'; +import downloadManager from 'services/downloadManager'; +import { EnteFile } from 'types/file'; + +export default function CollectionCard(props: { + children?: any; + latestFile: EnteFile; + onClick: () => void; + collectionTile: any; +}) { + const { + latestFile: file, + onClick, + children, + collectionTile: CustomCollectionTile, + } = props; + + const [coverImageURL, setCoverImageURL] = useState(null); + const galleryContext = useContext(GalleryContext); + useEffect(() => { + const main = async () => { + if (!file) { + return; + } + if (!galleryContext.thumbs.has(file.id)) { + const url = await downloadManager.getThumbnail(file); + galleryContext.thumbs.set(file.id, url); + } + setCoverImageURL(galleryContext.thumbs.get(file.id)); + }; + main(); + }, [file]); + + return ( + + {coverImageURL && } + {children} + + ); +} diff --git a/src/components/Collections/CollectionInfo.tsx b/src/components/Collections/CollectionInfo.tsx new file mode 100644 index 000000000..bb316e17e --- /dev/null +++ b/src/components/Collections/CollectionInfo.tsx @@ -0,0 +1,23 @@ +import { Box, Typography } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import React from 'react'; +import constants from 'utils/strings/constants'; +interface Iprops { + name: string; + fileCount: number; + endIcon?: React.ReactNode; +} + +export function CollectionInfo({ name, fileCount, endIcon }: Iprops) { + return ( +
+ + {name} + {endIcon && {endIcon}} + + + {constants.PHOTO_COUNT(fileCount)} + +
+ ); +} diff --git a/src/components/Collections/CollectionInfoWithOptions.tsx b/src/components/Collections/CollectionInfoWithOptions.tsx new file mode 100644 index 000000000..e7c85047c --- /dev/null +++ b/src/components/Collections/CollectionInfoWithOptions.tsx @@ -0,0 +1,70 @@ +import { CollectionInfo } from './CollectionInfo'; +import React from 'react'; +import { Collection, CollectionSummary } from 'types/collection'; +import CollectionOptions from 'components/Collections/CollectionOptions'; +import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer'; +import { SpaceBetweenFlex } from 'components/Container'; +import { CollectionInfoBarWrapper } from './styledComponents'; +import { shouldShowOptions } from 'utils/collection'; +import { CollectionSummaryType } from 'constants/collection'; +import Favorite from '@mui/icons-material/FavoriteRounded'; +import VisibilityOff from '@mui/icons-material/VisibilityOff'; +import Delete from '@mui/icons-material/Delete'; + +interface Iprops { + activeCollection: Collection; + collectionSummary: CollectionSummary; + setCollectionNamerAttributes: SetCollectionNamerAttributes; + showCollectionShareModal: () => void; + redirectToAll: () => void; +} + +interface Iprops { + collectionSummary: CollectionSummary; + setCollectionNamerAttributes: SetCollectionNamerAttributes; + activeCollection: Collection; + activeCollectionID: number; + showCollectionShareModal: () => void; + redirectToAll: () => void; +} +export default function CollectionInfoWithOptions({ + collectionSummary, + ...props +}: Iprops) { + if (!collectionSummary) { + return <>; + } + + const { name, type, fileCount } = collectionSummary; + + const EndIcon = ({ type }: { type: CollectionSummaryType }) => { + switch (type) { + case CollectionSummaryType.favorites: + return ; + case CollectionSummaryType.archived: + case CollectionSummaryType.archive: + return ; + case CollectionSummaryType.trash: + return ; + default: + return <>; + } + }; + return ( + + + } + /> + {shouldShowOptions(type) && ( + + )} + + + ); +} diff --git a/src/components/Collections/CollectionListBar/CollectionCard.tsx b/src/components/Collections/CollectionListBar/CollectionCard.tsx new file mode 100644 index 000000000..c5bb00df4 --- /dev/null +++ b/src/components/Collections/CollectionListBar/CollectionCard.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { EnteFile } from 'types/file'; +import { + ActiveIndicator, + CollectionBarTile, + CollectionBarTileIcon, + CollectionBarTileText, +} from '../styledComponents'; +import CollectionCard from '../CollectionCard'; +import TruncateText from 'components/TruncateText'; +import { Box } from '@mui/material'; +import { CollectionSummaryType } from 'constants/collection'; +import Favorite from '@mui/icons-material/FavoriteRounded'; +import VisibilityOff from '@mui/icons-material/VisibilityOff'; + +interface Iprops { + active: boolean; + latestFile: EnteFile; + collectionName: string; + collectionType: CollectionSummaryType; + onClick: () => void; +} + +const CollectionListBarCard = React.forwardRef((props: Iprops, ref: any) => { + const { active, collectionName, collectionType, ...others } = props; + + return ( + + + + + + {active && } + + ); +}); + +export default CollectionListBarCard; + +function CollectionCardText({ collectionName }) { + return ( + + + + ); +} + +function CollectionCardIcon({ collectionType }) { + return ( + + {collectionType === CollectionSummaryType.favorites && } + {collectionType === CollectionSummaryType.archived && ( + + )} + + ); +} diff --git a/src/components/Collections/CollectionListBar/ScrollButton.tsx b/src/components/Collections/CollectionListBar/ScrollButton.tsx new file mode 100644 index 000000000..3bdac2135 --- /dev/null +++ b/src/components/Collections/CollectionListBar/ScrollButton.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import NavigateNextIcon from '@mui/icons-material/NavigateNext'; +import { SCROLL_DIRECTION } from 'hooks/useComponentScroll'; +import { css, styled } from '@mui/material'; + +const Wrapper = styled('button')<{ direction: SCROLL_DIRECTION }>` + position: absolute; + z-index: 2; + top: 7px; + height: 50px; + width: 50px; + border: none; + padding: 0; + margin: 0; + + border-radius: 50%; + background-color: ${({ theme }) => theme.palette.background.paper}; + color: ${({ theme }) => theme.palette.primary.main}; + + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT + ? css` + left: 0; + text-align: right; + transform: translate(-50%, 0%); + ` + : css` + right: 0; + text-align: left; + transform: translate(50%, 0%); + `} + + & > svg { + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT && + 'transform:rotate(180deg);'} + border-radius: 50%; + height: 30px; + width: 30px; + } +`; + +const ScrollButton = ({ scrollDirection, ...rest }) => ( + + + +); +export default ScrollButton; diff --git a/src/components/Collections/CollectionListBar/index.tsx b/src/components/Collections/CollectionListBar/index.tsx new file mode 100644 index 000000000..0d601692c --- /dev/null +++ b/src/components/Collections/CollectionListBar/index.tsx @@ -0,0 +1,125 @@ +import ScrollButton from 'components/Collections/CollectionListBar/ScrollButton'; +import React, { useContext, useEffect } from 'react'; +import constants from 'utils/strings/constants'; +import { ALL_SECTION, COLLECTION_SORT_BY } from 'constants/collection'; +import { Box, IconButton, Typography } from '@mui/material'; +import { + CollectionListBarWrapper, + ScrollContainer, + CollectionListWrapper, +} from 'components/Collections/styledComponents'; +import CollectionListBarCard from 'components/Collections/CollectionListBar/CollectionCard'; +import useComponentScroll, { SCROLL_DIRECTION } from 'hooks/useComponentScroll'; +import useWindowSize from 'hooks/useWindowSize'; +import { IconButtonWithBG, SpaceBetweenFlex } from 'components/Container'; +import ExpandMore from '@mui/icons-material/ExpandMore'; +import { AppContext } from 'pages/_app'; +import { CollectionSummary } from 'types/collection'; +import CollectionSort from '../AllCollections/CollectionSort'; + +interface IProps { + activeCollection?: number; + setActiveCollection: (id?: number) => void; + collectionSummaries: CollectionSummary[]; + showAllCollections: () => void; + collectionSortBy: COLLECTION_SORT_BY; + setCollectionSortBy: (v: COLLECTION_SORT_BY) => void; +} + +export default function CollectionListBar(props: IProps) { + const { + activeCollection, + setActiveCollection, + collectionSummaries, + showAllCollections, + } = props; + + const appContext = useContext(AppContext); + + const windowSize = useWindowSize(); + + const { componentRef, scrollComponent, onFarLeft, onFarRight } = + useComponentScroll({ + dependencies: [windowSize, collectionSummaries], + }); + + const collectionChipsRef = collectionSummaries.reduce( + (refMap, collectionSummary) => { + refMap[collectionSummary.id] = React.createRef(); + return refMap; + }, + {} + ); + + useEffect(() => { + collectionChipsRef[activeCollection]?.current.scrollIntoView(); + }, [activeCollection]); + + const clickHandler = (collectionID?: number) => () => { + setActiveCollection(collectionID ?? ALL_SECTION); + }; + + return ( + + + {constants.ALBUMS} + {appContext.isMobile && ( + + + + + + + )} + + + + {!onFarLeft && ( + + )} + + {collectionSummaries.map((item) => ( + + ))} + + {!onFarRight && ( + + )} + + {!appContext.isMobile && ( + + + + + + + )} + + + ); +} diff --git a/src/components/Collections/CollectionNamer.tsx b/src/components/Collections/CollectionNamer.tsx new file mode 100644 index 000000000..cd2f71743 --- /dev/null +++ b/src/components/Collections/CollectionNamer.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; +import SingleInputForm, { + SingleInputFormProps, +} from 'components/SingleInputForm'; +import DialogBoxBase from 'components/DialogBox/base'; +import { DialogContent, DialogTitle } from '@mui/material'; + +export interface CollectionNamerAttributes { + callback: (name: string) => void; + title: string; + autoFilledName: string; + buttonText: string; +} + +export type SetCollectionNamerAttributes = React.Dispatch< + React.SetStateAction +>; + +interface Props { + show: boolean; + onHide: () => void; + attributes: CollectionNamerAttributes; +} + +export default function CollectionNamer({ attributes, ...props }: Props) { + if (!attributes) { + return <>; + } + const onSubmit: SingleInputFormProps['callback'] = async ( + albumName, + setFieldError + ) => { + try { + attributes.callback(albumName); + props.onHide(); + } catch (e) { + setFieldError(constants.UNKNOWN_ERROR); + } + }; + + return ( + + {attributes.title} + + + + + ); +} diff --git a/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx b/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx new file mode 100644 index 000000000..9d6c4f3c4 --- /dev/null +++ b/src/components/Collections/CollectionOptions/AlbumCollectionOption.tsx @@ -0,0 +1,76 @@ +import { OverflowMenuOption } from 'components/OverflowMenu/option'; +import React from 'react'; + +import EditIcon from '@mui/icons-material/Edit'; +import IosShareIcon from '@mui/icons-material/IosShare'; +import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined'; +import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; +import VisibilityOnOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; +import constants from 'utils/strings/constants'; +import { CollectionActions } from '.'; + +interface Iprops { + IsArchived: boolean; + handleCollectionAction: ( + action: CollectionActions, + loader?: boolean + ) => (...args: any[]) => Promise; +} + +export function AlbumCollectionOption({ + IsArchived, + handleCollectionAction, +}: Iprops) { + return ( + <> + }> + {constants.SHARE} + + }> + {constants.DOWNLOAD} + + }> + {constants.RENAME} + + {IsArchived ? ( + }> + {constants.UNARCHIVE} + + ) : ( + }> + {constants.ARCHIVE} + + )} + } + onClick={handleCollectionAction( + CollectionActions.CONFIRM_DELETE, + false + )}> + {constants.DELETE} + + + ); +} diff --git a/src/components/Collections/CollectionOptions/TrashCollectionOption.tsx b/src/components/Collections/CollectionOptions/TrashCollectionOption.tsx new file mode 100644 index 000000000..dde9d8fd5 --- /dev/null +++ b/src/components/Collections/CollectionOptions/TrashCollectionOption.tsx @@ -0,0 +1,27 @@ +import { OverflowMenuOption } from 'components/OverflowMenu/option'; +import React from 'react'; + +import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; +import constants from 'utils/strings/constants'; +import { CollectionActions } from '.'; + +interface Iprops { + handleCollectionAction: ( + action: CollectionActions, + loader?: boolean + ) => (...args: any[]) => Promise; +} + +export function TrashCollectionOption({ handleCollectionAction }: Iprops) { + return ( + } + onClick={handleCollectionAction( + CollectionActions.CONFIRM_EMPTY_TRASH, + false + )}> + {constants.EMPTY_TRASH} + + ); +} diff --git a/src/components/Collections/CollectionOptions/index.tsx b/src/components/Collections/CollectionOptions/index.tsx new file mode 100644 index 000000000..e89bc5ead --- /dev/null +++ b/src/components/Collections/CollectionOptions/index.tsx @@ -0,0 +1,226 @@ +import { AlbumCollectionOption } from './AlbumCollectionOption'; +import React, { useContext } from 'react'; +import * as CollectionAPI from 'services/collectionService'; +import * as TrashService from 'services/trashService'; +import { + changeCollectionVisibility, + downloadAllCollectionFiles, +} from 'utils/collection'; +import constants from 'utils/strings/constants'; +import { SetCollectionNamerAttributes } from '../CollectionNamer'; +import { Collection } from 'types/collection'; +import { IsArchived } from 'utils/magicMetadata'; +import { GalleryContext } from 'pages/gallery'; +import { logError } from 'utils/sentry'; +import { VISIBILITY_STATE } from 'types/magicMetadata'; +import { AppContext } from 'pages/_app'; +import OverflowMenu from 'components/OverflowMenu/menu'; +import { CollectionSummaryType } from 'constants/collection'; +import { TrashCollectionOption } from './TrashCollectionOption'; +import MoreHoriz from '@mui/icons-material/MoreHoriz'; + +interface CollectionOptionsProps { + setCollectionNamerAttributes: SetCollectionNamerAttributes; + activeCollection: Collection; + collectionSummaryType: CollectionSummaryType; + showCollectionShareModal: () => void; + redirectToAll: () => void; +} + +export enum CollectionActions { + SHOW_RENAME_DIALOG, + RENAME, + CONFIRM_DOWNLOAD, + DOWNLOAD, + ARCHIVE, + UNARCHIVE, + CONFIRM_DELETE, + DELETE, + SHOW_SHARE_DIALOG, + CONFIRM_EMPTY_TRASH, + EMPTY_TRASH, +} + +const CollectionOptions = (props: CollectionOptionsProps) => { + const { + activeCollection, + collectionSummaryType, + redirectToAll, + setCollectionNamerAttributes, + showCollectionShareModal, + } = props; + + const { startLoading, finishLoading, setDialogMessage } = + useContext(AppContext); + const { syncWithRemote } = useContext(GalleryContext); + + const handleCollectionAction = ( + action: CollectionActions, + loader = true + ) => { + let callback; + switch (action) { + case CollectionActions.SHOW_RENAME_DIALOG: + callback = showRenameCollectionModal; + break; + case CollectionActions.RENAME: + callback = renameCollection; + break; + case CollectionActions.CONFIRM_DOWNLOAD: + callback = confirmDownloadCollection; + break; + case CollectionActions.DOWNLOAD: + callback = downloadCollection; + break; + case CollectionActions.ARCHIVE: + callback = archiveCollection; + break; + case CollectionActions.UNARCHIVE: + callback = unArchiveCollection; + break; + case CollectionActions.CONFIRM_DELETE: + callback = confirmDeleteCollection; + break; + case CollectionActions.DELETE: + callback = deleteCollection; + break; + case CollectionActions.SHOW_SHARE_DIALOG: + callback = showCollectionShareModal; + break; + case CollectionActions.CONFIRM_EMPTY_TRASH: + callback = confirmEmptyTrash; + break; + case CollectionActions.EMPTY_TRASH: + callback = emptyTrash; + break; + default: + logError( + Error('invalid collection action '), + 'handleCollectionAction failed' + ); + { + action; + } + } + return async (...args) => { + try { + loader && startLoading(); + await callback(...args); + } catch (e) { + setDialogMessage({ + title: constants.ERROR, + content: constants.UNKNOWN_ERROR, + close: { variant: 'danger' }, + }); + } finally { + syncWithRemote(false, true); + loader && finishLoading(); + } + }; + }; + + const renameCollection = (newName: string) => { + if (activeCollection.name !== newName) { + CollectionAPI.renameCollection(activeCollection, newName); + } + }; + + const deleteCollection = async () => { + await CollectionAPI.deleteCollection(activeCollection.id); + redirectToAll(); + }; + + const archiveCollection = () => { + changeCollectionVisibility(activeCollection, VISIBILITY_STATE.ARCHIVED); + }; + + const unArchiveCollection = () => { + changeCollectionVisibility(activeCollection, VISIBILITY_STATE.VISIBLE); + }; + + const downloadCollection = () => { + downloadAllCollectionFiles(activeCollection.id); + }; + + const emptyTrash = async () => { + await TrashService.emptyTrash(); + await TrashService.clearLocalTrash(); + redirectToAll(); + }; + + const showRenameCollectionModal = () => { + setCollectionNamerAttributes({ + title: constants.RENAME_COLLECTION, + buttonText: constants.RENAME, + autoFilledName: activeCollection.name, + callback: handleCollectionAction(CollectionActions.RENAME), + }); + }; + + const confirmDeleteCollection = () => { + setDialogMessage({ + title: constants.DELETE_COLLECTION_TITLE, + content: constants.DELETE_COLLECTION_MESSAGE, + proceed: { + text: constants.DELETE_COLLECTION, + action: handleCollectionAction(CollectionActions.DELETE), + variant: 'danger', + }, + close: { + text: constants.CANCEL, + }, + }); + }; + + const confirmDownloadCollection = () => { + setDialogMessage({ + title: constants.CONFIRM_DOWNLOAD_COLLECTION, + content: constants.DOWNLOAD_COLLECTION_MESSAGE(), + proceed: { + text: constants.DOWNLOAD, + action: handleCollectionAction(CollectionActions.DOWNLOAD), + variant: 'accent', + }, + close: { + text: constants.CANCEL, + }, + }); + }; + + const confirmEmptyTrash = () => + setDialogMessage({ + title: constants.EMPTY_TRASH_TITLE, + content: constants.EMPTY_TRASH_MESSAGE, + + proceed: { + action: handleCollectionAction(CollectionActions.EMPTY_TRASH), + text: constants.EMPTY_TRASH, + variant: 'danger', + }, + close: { text: constants.CANCEL }, + }); + + return ( + } + triggerButtonProps={{ + sx: { + background: (theme) => theme.palette.fill.dark, + }, + }}> + {collectionSummaryType === CollectionSummaryType.trash ? ( + + ) : ( + + )} + + ); +}; + +export default CollectionOptions; diff --git a/src/components/Collections/CollectionSelector/AddCollectionButton.tsx b/src/components/Collections/CollectionSelector/AddCollectionButton.tsx new file mode 100644 index 000000000..4a3b77c93 --- /dev/null +++ b/src/components/Collections/CollectionSelector/AddCollectionButton.tsx @@ -0,0 +1,34 @@ +import CollectionCard from 'components/Collections/CollectionCard'; +import { + AllCollectionTile, + AllCollectionTileText, +} from 'components/Collections/styledComponents'; +import React from 'react'; +import { styled } from '@mui/material'; +import constants from 'utils/strings/constants'; +import { CenteredFlex, Overlay } from 'components/Container'; + +const ImageContainer = styled(Overlay)` + display: flex; + font-size: 42px; +`; + +interface Iprops { + showNextModal: () => void; +} + +export default function AddCollectionButton({ showNextModal }: Iprops) { + return ( + showNextModal()} + latestFile={null}> + + {constants.CREATE_COLLECTION} + + + + + + + ); +} diff --git a/src/components/Collections/CollectionSelector/CollectionCard.tsx b/src/components/Collections/CollectionSelector/CollectionCard.tsx new file mode 100644 index 000000000..31b301e50 --- /dev/null +++ b/src/components/Collections/CollectionSelector/CollectionCard.tsx @@ -0,0 +1,26 @@ +import { Typography } from '@mui/material'; +import React from 'react'; +import CollectionCard from '../CollectionCard'; +import { CollectionSummary } from 'types/collection'; +import { AllCollectionTile, AllCollectionTileText } from '../styledComponents'; + +interface Iprops { + collectionSummary: CollectionSummary; + onCollectionClick: (collectionID: number) => void; +} + +export default function CollectionSelectorCard({ + onCollectionClick, + collectionSummary, +}: Iprops) { + return ( + onCollectionClick(collectionSummary.id)}> + + {collectionSummary.name} + + + ); +} diff --git a/src/components/Collections/CollectionSelector/index.tsx b/src/components/Collections/CollectionSelector/index.tsx new file mode 100644 index 000000000..e929d8bcc --- /dev/null +++ b/src/components/Collections/CollectionSelector/index.tsx @@ -0,0 +1,93 @@ +import React, { useContext, useEffect, useMemo } from 'react'; +import { Collection, CollectionSummaries } from 'types/collection'; +import DialogTitleWithCloseButton from 'components/DialogBox/TitleWithCloseButton'; +import { isUploadAllowedCollection } from 'utils/collection'; +import { AppContext } from 'pages/_app'; +import { AllCollectionDialog } from 'components/Collections/AllCollections/dialog'; +import { DialogContent } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import CollectionSelectorCard from './CollectionCard'; +import AddCollectionButton from './AddCollectionButton'; + +export interface CollectionSelectorAttributes { + callback: (collection: Collection) => void; + showNextModal: () => void; + title: string; + fromCollection?: number; +} + +interface Props { + open: boolean; + onClose: (closeBtnClick?: boolean) => void; + attributes: CollectionSelectorAttributes; + collections: Collection[]; + collectionSummaries: CollectionSummaries; +} +function CollectionSelector({ + attributes, + collectionSummaries, + collections, + ...props +}: Props) { + const appContext = useContext(AppContext); + const collectionToShow = useMemo(() => { + const personalCollectionsOtherThanFrom = [ + ...collectionSummaries.values(), + ]?.filter( + ({ type, id }) => + id !== attributes?.fromCollection && + isUploadAllowedCollection(type) + ); + return personalCollectionsOtherThanFrom; + }, [collectionSummaries, attributes]); + + useEffect(() => { + if (!attributes || !props.open) { + return; + } + if (collectionToShow.length === 0) { + props.onClose(); + attributes.showNextModal(); + } + }, [collectionToShow, attributes, props.open]); + + if (!attributes) { + return <>; + } + + const handleCollectionClick = (collectionID: number) => { + const collection = collections.find((c) => c.id === collectionID); + attributes.callback(collection); + props.onClose(); + }; + + const onCloseButtonClick = () => props.onClose(true); + + return ( + + + {attributes.title} + + + + + {collectionToShow.map((collectionSummary) => ( + + ))} + + + + ); +} + +export default CollectionSelector; diff --git a/src/components/Collections/CollectionShare/container.tsx b/src/components/Collections/CollectionShare/container.tsx new file mode 100644 index 000000000..9e704a7dd --- /dev/null +++ b/src/components/Collections/CollectionShare/container.tsx @@ -0,0 +1,25 @@ +import { Dialog, styled } from '@mui/material'; +import PropTypes from 'prop-types'; + +export const CollectionShareContainer = styled(Dialog)(({ theme }) => ({ + '& .MuiDialog-container': { + justifyContent: 'flex-end', + }, + '& .MuiPaper-root': { + width: '414px', + }, + '& .MuiDialog-paperFullScreen': { + maxWidth: '100%', + }, + '& .MuiDialogTitle-root': { + padding: theme.spacing(4, 3, 3, 4), + }, + '& .MuiDialogContent-root': { + padding: theme.spacing(3, 4), + }, +})); + +CollectionShareContainer.propTypes = { + children: PropTypes.node, + onClose: PropTypes.func.isRequired, +}; diff --git a/src/components/Collections/CollectionShare/emailShare.tsx b/src/components/Collections/CollectionShare/emailShare.tsx new file mode 100644 index 000000000..c40fcdcf2 --- /dev/null +++ b/src/components/Collections/CollectionShare/emailShare.tsx @@ -0,0 +1,53 @@ +import SingleInputForm, { + SingleInputFormProps, +} from 'components/SingleInputForm'; +import { GalleryContext } from 'pages/gallery'; +import React, { useContext } from 'react'; +import { shareCollection } from 'services/collectionService'; +import { User } from 'types/user'; +import { handleSharingErrors } from 'utils/error'; +import { getData, LS_KEYS } from 'utils/storage/localStorage'; +import constants from 'utils/strings/constants'; +import { CollectionShareSharees } from './sharees'; + +export default function EmailShare({ collection }) { + const galleryContext = useContext(GalleryContext); + + const collectionShare: SingleInputFormProps['callback'] = async ( + email, + setFieldError + ) => { + try { + const user: User = getData(LS_KEYS.USER); + if (email === user.email) { + setFieldError(constants.SHARE_WITH_SELF); + } else if ( + collection?.sharees?.find((value) => value.email === email) + ) { + setFieldError(constants.ALREADY_SHARED(email)); + } else { + await shareCollection(collection, email); + await galleryContext.syncWithRemote(false, true); + } + } catch (e) { + const errorMessage = handleSharingErrors(e); + setFieldError(errorMessage); + } + }; + return ( + <> + + + + ); +} diff --git a/src/components/Collections/CollectionShare/index.tsx b/src/components/Collections/CollectionShare/index.tsx new file mode 100644 index 000000000..a60f0e9f4 --- /dev/null +++ b/src/components/Collections/CollectionShare/index.tsx @@ -0,0 +1,49 @@ +import EmailShare from './emailShare'; +import React, { useContext } from 'react'; +import constants from 'utils/strings/constants'; +import { Collection } from 'types/collection'; +import DialogTitleWithCloseButton, { + dialogCloseHandler, +} from 'components/DialogBox/TitleWithCloseButton'; +import DialogContent from '@mui/material/DialogContent'; +import { Divider } from '@mui/material'; + +import { CollectionShareContainer } from './container'; +import PublicShare from './publicShare'; +import { AppContext } from 'pages/_app'; + +interface Props { + open: boolean; + onClose: () => void; + collection: Collection; +} + +function CollectionShare(props: Props) { + const { isMobile } = useContext(AppContext); + const handleClose = dialogCloseHandler({ + onClose: props.onClose, + }); + + if (!props.collection) { + return <>; + } + + return ( + <> + + + {constants.SHARE_COLLECTION} + + + + + + + + + ); +} +export default CollectionShare; diff --git a/src/components/Collections/CollectionShare/publicShare/control.tsx b/src/components/Collections/CollectionShare/publicShare/control.tsx new file mode 100644 index 000000000..bb744d72f --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/control.tsx @@ -0,0 +1,102 @@ +import { Box, Typography } from '@mui/material'; +import { FlexWrapper } from 'components/Container'; +import { ButtonVariant } from 'components/pages/gallery/LinkButton'; +import { AppContext } from 'pages/_app'; +import React, { useContext, useState } from 'react'; +import { + createShareableURL, + deleteShareableURL, +} from 'services/collectionService'; +import { Collection, PublicURL } from 'types/collection'; +import { handleSharingErrors } from 'utils/error'; +import constants from 'utils/strings/constants'; +import PublicShareSwitch from './switch'; +interface Iprops { + collection: Collection; + publicShareActive: boolean; + setPublicShareProp: (value: PublicURL) => void; +} + +export default function PublicShareControl({ + collection, + publicShareActive, + setPublicShareProp, +}: Iprops) { + const appContext = useContext(AppContext); + + const [sharableLinkError, setSharableLinkError] = useState(null); + + const createSharableURLHelper = async () => { + try { + appContext.startLoading(); + const publicURL = await createShareableURL(collection); + setPublicShareProp(publicURL); + } catch (e) { + const errorMessage = handleSharingErrors(e); + setSharableLinkError(errorMessage); + } finally { + appContext.finishLoading(); + } + }; + + const disablePublicSharing = async () => { + try { + appContext.startLoading(); + await deleteShareableURL(collection); + setPublicShareProp(null); + } catch (e) { + const errorMessage = handleSharingErrors(e); + setSharableLinkError(errorMessage); + } finally { + appContext.finishLoading(); + } + }; + + const confirmDisablePublicSharing = () => { + appContext.setDialogMessage({ + title: constants.DISABLE_PUBLIC_SHARING, + content: constants.DISABLE_PUBLIC_SHARING_MESSAGE, + close: { text: constants.CANCEL }, + proceed: { + text: constants.DISABLE, + action: disablePublicSharing, + variant: ButtonVariant.danger, + }, + }); + }; + + const handleCollectionPublicSharing = () => { + setSharableLinkError(null); + if (publicShareActive) { + confirmDisablePublicSharing(); + } else { + createSharableURLHelper(); + } + }; + return ( + + + {constants.PUBLIC_SHARING} + + + + {sharableLinkError && ( + theme.palette.danger.main, + mt: 0.5, + }}> + {sharableLinkError} + + )} + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/index.tsx b/src/components/Collections/CollectionShare/publicShare/index.tsx new file mode 100644 index 000000000..db103fb2c --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/index.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState } from 'react'; +import { Collection, PublicURL } from 'types/collection'; +import { appendCollectionKeyToShareURL } from 'utils/collection'; +import PublicShareControl from './control'; +import PublicShareLink from './link'; +import PublicShareManage from './manage'; + +export default function PublicShare({ + collection, +}: { + collection: Collection; +}) { + const [publicShareUrl, setPublicShareUrl] = useState(null); + const [publicShareProp, setPublicShareProp] = useState(null); + + useEffect(() => { + if (collection.publicURLs?.length) { + setPublicShareProp(collection.publicURLs[0]); + } + }, [collection]); + + useEffect(() => { + if (publicShareProp) { + const url = appendCollectionKeyToShareURL( + publicShareProp.url, + collection.key + ); + setPublicShareUrl(url); + } else { + setPublicShareUrl(null); + } + }, [publicShareProp]); + + return ( + <> + + {publicShareProp && ( + <> + + + + + )} + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/link.tsx b/src/components/Collections/CollectionShare/publicShare/link.tsx new file mode 100644 index 000000000..c5cadf36b --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/link.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import CodeBlock from 'components/CodeBlock'; +import React from 'react'; + +export default function PublicShareLink({ publicShareUrl }) { + return ( + + + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx b/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx new file mode 100644 index 000000000..113683fb8 --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/manage/deviceLimit.tsx @@ -0,0 +1,40 @@ +import { Box, Typography } from '@mui/material'; +import React from 'react'; +import Select from 'react-select'; +import { DropdownStyle } from 'styles/dropdown'; +import { getDeviceLimitOptions } from 'utils/collection'; +import constants from 'utils/strings/constants'; +import { OptionWithDivider } from './selectComponents/OptionWithDivider'; + +export function ManageDeviceLimit({ + publicShareProp, + collection, + updatePublicShareURLHelper, +}) { + const updateDeviceLimit = async (newLimit: number) => { + return updatePublicShareURLHelper({ + collectionID: collection.id, + deviceLimit: newLimit, + }); + }; + + return ( + + {constants.LINK_DEVICE_LIMIT} + { + updateDeviceExpiry(e.value); + }} + styles={linkExpiryStyle} + /> + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx b/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx new file mode 100644 index 000000000..21334f20a --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/manage/linkPassword.tsx @@ -0,0 +1,49 @@ +import { Box, Typography } from '@mui/material'; +import { ButtonVariant } from 'components/pages/gallery/LinkButton'; +import { AppContext } from 'pages/_app'; +import React, { useContext } from 'react'; +import constants from 'utils/strings/constants'; +import PublicShareSwitch from '../switch'; +export function ManageLinkPassword({ + collection, + publicShareProp, + updatePublicShareURLHelper, + setChangePasswordView, +}) { + const appContext = useContext(AppContext); + + const handlePasswordChangeSetting = async () => { + if (publicShareProp.passwordEnabled) { + await confirmDisablePublicUrlPassword(); + } else { + setChangePasswordView(true); + } + }; + + const confirmDisablePublicUrlPassword = async () => { + appContext.setDialogMessage({ + title: constants.DISABLE_PASSWORD, + content: constants.DISABLE_PASSWORD_MESSAGE, + close: { text: constants.CANCEL }, + proceed: { + text: constants.DISABLE, + action: () => + updatePublicShareURLHelper({ + collectionID: collection.id, + disablePassword: true, + }), + variant: ButtonVariant.danger, + }, + }); + }; + + return ( + + {constants.LINK_PASSWORD_LOCK} + + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/LabelWithDivider.tsx b/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/LabelWithDivider.tsx new file mode 100644 index 000000000..09b3facaa --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/LabelWithDivider.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Box, Typography, Divider } from '@mui/material'; + +export function LabelWithDivider({ data }) { + return ( + <> + + {data.label} + + + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/OptionWithDivider.tsx b/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/OptionWithDivider.tsx new file mode 100644 index 000000000..eed09d4f2 --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/manage/selectComponents/OptionWithDivider.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { LabelWithDivider } from './LabelWithDivider'; +import { components } from 'react-select'; + +const { Option } = components; + +export const OptionWithDivider = (props) => ( + +); diff --git a/src/components/Collections/CollectionShare/publicShare/setPassword.tsx b/src/components/Collections/CollectionShare/publicShare/setPassword.tsx new file mode 100644 index 000000000..b1bfd840f --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/setPassword.tsx @@ -0,0 +1,66 @@ +import { Dialog, Stack, Typography } from '@mui/material'; +import SingleInputForm, { + SingleInputFormProps, +} from 'components/SingleInputForm'; +import React from 'react'; +import CryptoWorker from 'utils/crypto'; +import constants from 'utils/strings/constants'; + +export function PublicLinkSetPassword({ + open, + onClose, + collection, + publicShareProp, + updatePublicShareURLHelper, + setChangePasswordView, +}) { + const savePassword: SingleInputFormProps['callback'] = async ( + passphrase, + setFieldError + ) => { + if (passphrase && passphrase.trim().length >= 1) { + await enablePublicUrlPassword(passphrase); + setChangePasswordView(false); + publicShareProp.passwordEnabled = true; + } else { + setFieldError('can not be empty'); + } + }; + + const enablePublicUrlPassword = async (password: string) => { + const cryptoWorker = await new CryptoWorker(); + const kekSalt: string = await cryptoWorker.generateSaltToDeriveKey(); + const kek = await cryptoWorker.deriveInteractiveKey(password, kekSalt); + + return updatePublicShareURLHelper({ + collectionID: collection.id, + passHash: kek.key, + nonce: kekSalt, + opsLimit: kek.opsLimit, + memLimit: kek.memLimit, + }); + }; + return ( + + + + {constants.PASSWORD_LOCK} + + + + + ); +} diff --git a/src/components/Collections/CollectionShare/publicShare/switch.tsx b/src/components/Collections/CollectionShare/publicShare/switch.tsx new file mode 100644 index 000000000..1f4daa2bb --- /dev/null +++ b/src/components/Collections/CollectionShare/publicShare/switch.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { SwitchProps, Switch } from '@mui/material'; +import { styled } from '@mui/material'; +const PublicShareSwitch = styled((props: SwitchProps) => ( + +))(({ theme }) => ({ + width: 40, + height: 24, + padding: 0, + '& .MuiSwitch-switchBase': { + padding: 0, + margin: 2, + transitionDuration: '300ms', + '&.Mui-checked': { + transform: 'translateX(16px)', + color: '#fff', + '& + .MuiSwitch-track': { + backgroundColor: + theme.palette.mode === 'dark' ? '#2ECA45' : '#65C466', + opacity: 1, + border: 0, + }, + '&.Mui-disabled + .MuiSwitch-track': { + opacity: 0.5, + }, + }, + '&.Mui-focusVisible .MuiSwitch-thumb': { + color: '#33cf4d', + border: '6px solid #fff', + }, + '&.Mui-disabled .MuiSwitch-thumb': { + color: + theme.palette.mode === 'light' + ? theme.palette.grey[100] + : theme.palette.grey[600], + }, + '&.Mui-disabled + .MuiSwitch-track': { + opacity: theme.palette.mode === 'light' ? 0.7 : 0.3, + }, + }, + '& .MuiSwitch-thumb': { + boxSizing: 'border-box', + width: 20, + height: 20, + }, + '& .MuiSwitch-track': { + borderRadius: 22 / 2, + backgroundColor: theme.palette.mode === 'light' ? '#E9E9EA' : '#39393D', + opacity: 1, + transition: theme.transitions.create(['background-color'], { + duration: 500, + }), + }, +})); + +export default PublicShareSwitch; diff --git a/src/components/Collections/CollectionShare/sharees/index.tsx b/src/components/Collections/CollectionShare/sharees/index.tsx new file mode 100644 index 000000000..39daec804 --- /dev/null +++ b/src/components/Collections/CollectionShare/sharees/index.tsx @@ -0,0 +1,46 @@ +import { Box, Typography } from '@mui/material'; +import { GalleryContext } from 'pages/gallery'; +import { AppContext } from 'pages/_app'; +import React, { useContext } from 'react'; +import { unshareCollection } from 'services/collectionService'; +import { Collection } from 'types/collection'; +import constants from 'utils/strings/constants'; +import ShareeRow from './row'; + +interface Iprops { + collection: Collection; +} + +export function CollectionShareSharees({ collection }: Iprops) { + const appContext = useContext(AppContext); + const galleryContext = useContext(GalleryContext); + + const collectionUnshare = async (sharee) => { + try { + appContext.startLoading(); + await unshareCollection(collection, sharee.email); + await galleryContext.syncWithRemote(false, true); + } finally { + appContext.finishLoading(); + } + }; + + if (!collection.sharees?.length) { + return <>; + } + + return ( + + + {constants.SHAREES} + + {collection.sharees?.map((sharee) => ( + + ))} + + ); +} diff --git a/src/components/Collections/CollectionShare/sharees/row.tsx b/src/components/Collections/CollectionShare/sharees/row.tsx new file mode 100644 index 000000000..4f6fbcd03 --- /dev/null +++ b/src/components/Collections/CollectionShare/sharees/row.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { SpaceBetweenFlex } from 'components/Container'; +import { User } from 'types/user'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import OverflowMenu from 'components/OverflowMenu/menu'; + +import NotInterestedIcon from '@mui/icons-material/NotInterested'; +import constants from 'utils/strings/constants'; +import { OverflowMenuOption } from 'components/OverflowMenu/option'; + +interface IProps { + sharee: User; + collectionUnshare: (sharee: User) => void; +} +const ShareeRow = ({ sharee, collectionUnshare }: IProps) => { + const handleClick = () => collectionUnshare(sharee); + return ( + + {sharee.email} + + theme.palette.background.overPaper, + }, + }} + ariaControls={`email-share-${sharee.email}`} + triggerButtonIcon={}> + }> + {constants.REMOVE} + + + + ); +}; + +export default ShareeRow; diff --git a/src/components/Collections/CollectionShare/styledComponents.tsx b/src/components/Collections/CollectionShare/styledComponents.tsx new file mode 100644 index 000000000..014f35570 --- /dev/null +++ b/src/components/Collections/CollectionShare/styledComponents.tsx @@ -0,0 +1,13 @@ +import { styled } from '@mui/material'; +export const ManageSectionLabel = styled('summary')( + ({ theme }) => ` + text-align: center; + margin-bottom:${theme.spacing(1)}; +` +); + +export const ManageSectionOptions = styled('section')( + ({ theme }) => ` + margin-bottom:${theme.spacing(4)}; +` +); diff --git a/src/components/Collections/index.tsx b/src/components/Collections/index.tsx new file mode 100644 index 000000000..06d16798d --- /dev/null +++ b/src/components/Collections/index.tsx @@ -0,0 +1,140 @@ +import { Collection, CollectionSummaries } from 'types/collection'; +import CollectionListBar from 'components/Collections/CollectionListBar'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import AllCollections from 'components/Collections/AllCollections'; +import CollectionInfoWithOptions from 'components/Collections/CollectionInfoWithOptions'; +import { ALL_SECTION, COLLECTION_SORT_BY } from 'constants/collection'; +import CollectionShare from 'components/Collections/CollectionShare'; +import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer'; +import { ITEM_TYPE, TimeStampListItem } from 'components/PhotoList'; +import { + hasNonEmptyCollections, + isSystemCollection, + shouldBeShownOnCollectionBar, +} from 'utils/collection'; +import { useLocalState } from 'hooks/useLocalState'; +import { sortCollectionSummaries } from 'services/collectionService'; +import { LS_KEYS } from 'utils/storage/localStorage'; + +interface Iprops { + collections: Collection[]; + activeCollectionID?: number; + setActiveCollectionID: (id?: number) => void; + isInSearchMode: boolean; + collectionSummaries: CollectionSummaries; + setCollectionNamerAttributes: SetCollectionNamerAttributes; + setPhotoListHeader: (value: TimeStampListItem) => void; +} + +export default function Collections(props: Iprops) { + const { + collections, + isInSearchMode, + activeCollectionID, + setActiveCollectionID, + collectionSummaries, + setCollectionNamerAttributes, + setPhotoListHeader, + } = props; + + const [allCollectionView, setAllCollectionView] = useState(false); + const [collectionShareModalView, setCollectionShareModalView] = + useState(false); + + const [collectionSortBy, setCollectionSortBy] = + useLocalState( + LS_KEYS.COLLECTION_SORT_BY, + COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING + ); + const collectionsMap = useRef>(new Map()); + const activeCollection = useRef(null); + + const shouldBeHidden = + isInSearchMode || hasNonEmptyCollections(collectionSummaries); + + useEffect(() => { + collectionsMap.current = new Map( + props.collections.map((collection) => [collection.id, collection]) + ); + }, [collections]); + + useEffect(() => { + activeCollection.current = + collectionsMap.current.get(activeCollectionID); + }, [activeCollectionID, collections]); + + const sortedCollectionSummaries = useMemo( + () => + sortCollectionSummaries( + [...collectionSummaries.values()], + collectionSortBy + ), + [collectionSortBy, collectionSummaries] + ); + + useEffect( + () => + !shouldBeHidden && + setPhotoListHeader({ + item: ( + setActiveCollectionID(ALL_SECTION)} + showCollectionShareModal={() => + setCollectionShareModalView(true) + } + /> + ), + itemType: ITEM_TYPE.OTHER, + height: 68, + }), + [collectionSummaries, activeCollectionID, shouldBeHidden] + ); + + if (shouldBeHidden) { + return <>; + } + + const closeAllCollections = () => setAllCollectionView(false); + const openAllCollections = () => setAllCollectionView(true); + const closeCollectionShare = () => setCollectionShareModalView(false); + + return ( + <> + + shouldBeShownOnCollectionBar(x.type) + )} + showAllCollections={openAllCollections} + setCollectionSortBy={setCollectionSortBy} + collectionSortBy={collectionSortBy} + /> + + !isSystemCollection(x.type) + )} + setActiveCollection={setActiveCollectionID} + setCollectionSortBy={setCollectionSortBy} + collectionSortBy={collectionSortBy} + /> + + + + ); +} diff --git a/src/components/Collections/styledComponents.ts b/src/components/Collections/styledComponents.ts new file mode 100644 index 000000000..fefafa710 --- /dev/null +++ b/src/components/Collections/styledComponents.ts @@ -0,0 +1,95 @@ +import { Box } from '@mui/material'; +import { styled } from '@mui/material'; +import { Overlay } from 'components/Container'; +import { SpecialPadding } from 'styles/SpecialPadding'; +export const CollectionListWrapper = styled(Box)` + position: relative; + overflow: hidden; + height: 86px; + width: 100%; +`; + +export const CollectionListBarWrapper = styled(Box)` + ${SpecialPadding} + margin-bottom: 16px; + border-bottom: 1px solid ${({ theme }) => theme.palette.divider}; +`; + +export const CollectionInfoBarWrapper = styled(Box)` + width: 100%; + margin-bottom: 12px; +`; + +export const ScrollContainer = styled('div')` + width: 100%; + height: 120px; + overflow: auto; + scroll-behavior: smooth; + display: flex; + gap: 4px; +`; + +export const CollectionTile = styled('div')` + display: flex; + position: relative; + border-radius: 4px; + overflow: hidden; + user-select: none; + cursor: pointer; + & > img { + object-fit: cover; + width: 100%; + height: 100%; + pointer-events: none; + } +`; + +export const ActiveIndicator = styled('div')` + height: 3px; + background-color: ${({ theme }) => theme.palette.primary.main}; + margin-top: 18px; + border-radius: 2px; +`; + +export const CollectionBarTile = styled(CollectionTile)` + width: 90px; + height: 64px; +`; + +export const AllCollectionTile = styled(CollectionTile)` + width: 150px; + height: 150px; +`; + +export const ResultPreviewTile = styled(CollectionTile)` + width: 48px; + height: 48px; +`; + +export const CollectionBarTileText = styled(Overlay)` + padding: 4px; + background: linear-gradient( + 0deg, + rgba(0, 0, 0, 0.1) 0%, + rgba(0, 0, 0, 0.5) 86.46% + ); +`; + +export const CollectionBarTileIcon = styled(Overlay)` + padding: 4px; + display: flex; + justify-content: flex-end; + align-items: flex-end; + & > .MuiSvgIcon-root { + font-size: 20px; + } +`; + +export const AllCollectionTileText = styled(Overlay)` + padding: 8px; + background: linear-gradient( + 0deg, + rgba(0, 0, 0, 0.1) 0%, + rgba(0, 0, 0, 0.5) 86.46% + ); +`; diff --git a/src/components/Container.ts b/src/components/Container.ts index b9d207fcb..76844f93b 100644 --- a/src/components/Container.ts +++ b/src/components/Container.ts @@ -1,69 +1,75 @@ -import styled from 'styled-components'; +import { Box, IconButton } from '@mui/material'; +import { styled } from '@mui/material'; -const Container = styled.div` +const VerticallyCentered = styled(Box)` flex: 1; display: flex; align-items: center; justify-content: center; flex-direction: column; + text-align: center; overflow: auto; - padding: 10px; `; -export default Container; +export default VerticallyCentered; -export const DisclaimerContainer = styled.div` +export const DisclaimerContainer = styled('div')` margin: 16px 0; color: rgb(158, 150, 137); font-size: 14px; `; -export const IconButton = styled.button` - background: none; - border: none; - border-radius: 50%; - padding: 5px; - color: inherit; - margin: 0 10px; - display: inline-flex; - align-items: center; - justify-content: center; - - &:focus, - &:hover { - background-color: rgba(255, 255, 255, 0.2); - } -`; - -export const Row = styled.div` +export const Row = styled('div')` + min-height: 32px; display: flex; align-items: center; - margin-bottom: 20px; + margin-bottom: ${({ theme }) => theme.spacing(2)}; flex: 1; `; -export const Label = styled.div<{ width?: string }>` +export const Label = styled('div')<{ width?: string }>` width: ${(props) => props.width ?? '70%'}; + color: ${(props) => props.theme.palette.text.secondary}; `; -export const Value = styled.div<{ width?: string }>` +export const Value = styled('div')<{ width?: string }>` display: flex; justify-content: flex-start; align-items: center; width: ${(props) => props.width ?? '30%'}; - text-align: center; - color: #ddd; `; -export const FlexWrapper = styled.div` - width: 100%; +export const FlexWrapper = styled(Box)` display: flex; - text-align: center; - justify-content: center; + width: 100%; + align-items: center; `; -export const FreeFlowText = styled.div` - word-wrap: break-word; - overflow-wrap: break-word; +export const FreeFlowText = styled('div')` + word-break: break-word; min-width: 30%; text-align: left; `; + +export const SpaceBetweenFlex = styled(FlexWrapper)` + justify-content: space-between; +`; + +export const CenteredFlex = styled(FlexWrapper)` + justify-content: center; +`; + +export const FluidContainer = styled(FlexWrapper)` + flex: 1; +`; + +export const Overlay = styled(Box)` + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; +`; + +export const IconButtonWithBG = styled(IconButton)(({ theme }) => ({ + backgroundColor: theme.palette.fill.dark, +})); diff --git a/src/components/DeleteBtn.tsx b/src/components/DeleteBtn.tsx index a7d2cd6cb..df4511cdd 100644 --- a/src/components/DeleteBtn.tsx +++ b/src/components/DeleteBtn.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import styled from 'styled-components'; +import { styled } from '@mui/material'; import constants from 'utils/strings/constants'; -import { IconWithMessage } from './pages/gallery/SelectedFileOptions'; +import { IconWithMessage } from './IconWithMessage'; -const Wrapper = styled.button` +const Wrapper = styled('button')` border: none; background-color: #ff6666; position: fixed; diff --git a/src/components/DialogBox/TitleWithCloseButton.tsx b/src/components/DialogBox/TitleWithCloseButton.tsx new file mode 100644 index 000000000..f78902b7a --- /dev/null +++ b/src/components/DialogBox/TitleWithCloseButton.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { + DialogProps, + DialogTitle, + IconButton, + Typography, +} from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { SpaceBetweenFlex } from 'components/Container'; + +const DialogTitleWithCloseButton = (props) => { + const { children, onClose, ...other } = props; + + return ( + + + + {children} + + {onClose && ( + + + + )} + + + ); +}; + +export default DialogTitleWithCloseButton; + +export const dialogCloseHandler = + ({ + staticBackdrop, + nonClosable, + onClose, + }: { + staticBackdrop?: boolean; + nonClosable?: boolean; + onClose: () => void; + }): DialogProps['onClose'] => + (_, reason) => { + if (nonClosable) { + // no-op + } else if (staticBackdrop && reason === 'backdropClick') { + // no-op + } else { + onClose(); + } + }; diff --git a/src/components/DialogBox/base.tsx b/src/components/DialogBox/base.tsx new file mode 100644 index 000000000..6db198c75 --- /dev/null +++ b/src/components/DialogBox/base.tsx @@ -0,0 +1,23 @@ +import { Dialog, styled } from '@mui/material'; + +const DialogBoxBase = styled(Dialog)(({ theme }) => ({ + '& .MuiDialog-paper': { + padding: theme.spacing(1, 1.5), + maxWidth: '346px', + }, + '& .MuiDialogTitle-root': { + padding: theme.spacing(2), + paddingBottom: theme.spacing(1), + }, + '& .MuiDialogContent-root': { + padding: theme.spacing(2), + }, + '.MuiDialogTitle-root + .MuiDialogContent-root': { + paddingTop: 0, + }, + '.MuiDialogTitle-root + .MuiDialogActions-root': { + paddingTop: theme.spacing(3), + }, +})); + +export default DialogBoxBase; diff --git a/src/components/DialogBox/index.tsx b/src/components/DialogBox/index.tsx new file mode 100644 index 000000000..5f70304c6 --- /dev/null +++ b/src/components/DialogBox/index.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import constants from 'utils/strings/constants'; +import { + Breakpoint, + Button, + DialogActions, + DialogContent, + DialogProps, + Typography, +} from '@mui/material'; +import DialogTitleWithCloseButton, { + dialogCloseHandler, +} from './TitleWithCloseButton'; +import DialogBoxBase from './base'; +import { DialogBoxAttributes } from 'types/dialogBox'; + +type IProps = React.PropsWithChildren< + Omit & { + onClose: () => void; + attributes: DialogBoxAttributes; + size?: Breakpoint; + titleCloseButton?: boolean; + } +>; + +export default function DialogBox({ + attributes, + children, + open, + size, + onClose, + titleCloseButton, + ...props +}: IProps) { + if (!attributes) { + return <>; + } + + const handleClose = dialogCloseHandler({ + staticBackdrop: attributes.staticBackdrop, + nonClosable: attributes.nonClosable, + onClose: onClose, + }); + + return ( + + {attributes.title && ( + + {attributes.title} + + )} + {(children || attributes?.content) && ( + + {children || ( + + {attributes.content} + + )} + + )} + {(attributes.close || attributes.proceed) && ( + + <> + {attributes.close && ( + + )} + {attributes.proceed && ( + + )} + + + )} + + ); +} diff --git a/src/components/EmptyScreen.tsx b/src/components/EmptyScreen.tsx new file mode 100644 index 000000000..1d0e328ef --- /dev/null +++ b/src/components/EmptyScreen.tsx @@ -0,0 +1,47 @@ +import React, { useContext } from 'react'; +import { Button, styled, Typography } from '@mui/material'; +import constants from 'utils/strings/constants'; +import { DeduplicateContext } from 'pages/deduplicate'; +import VerticallyCentered from './Container'; + +const Wrapper = styled(VerticallyCentered)` + & > svg { + filter: drop-shadow(3px 3px 5px rgba(45, 194, 98, 0.5)); + } +`; + +export default function EmptyScreen({ openUploader }) { + const deduplicateContext = useContext(DeduplicateContext); + return ( + + {deduplicateContext.isOnDeduplicatePage ? ( +
+ {constants.NO_DUPLICATES_FOUND} +
+ ) : ( + <> + + + {constants.UPLOAD_FIRST_PHOTO_DESCRIPTION()} + + + + + )} +
+ ); +} diff --git a/src/components/EnteCard.tsx b/src/components/EnteCard.tsx deleted file mode 100644 index 3e1a2638d..000000000 --- a/src/components/EnteCard.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import { Card } from 'react-bootstrap'; - -type Size = 'sm' | 'md' | 'lg'; - -const EnteCard = ({ - size, - children, - style, -}: { - size: Size; - children?: any; - style?: any; -}) => { - let minWidth: string; - let padding: string; - switch (size) { - case 'sm': - minWidth = '320px'; - padding = '0px'; - break; - case 'md': - minWidth = '460px'; - padding = '10px'; - break; - - default: - minWidth = '480px'; - padding = '10px'; - break; - } - return ( - - {children} - - ); -}; - -export default EnteCard; diff --git a/src/components/EnteDateTimePicker.tsx b/src/components/EnteDateTimePicker.tsx index 164417fd9..72c8e7597 100644 --- a/src/components/EnteDateTimePicker.tsx +++ b/src/components/EnteDateTimePicker.tsx @@ -1,50 +1,76 @@ -import React from 'react'; +import React, { useState } from 'react'; -import DatePicker from 'react-datepicker'; -import 'react-datepicker/dist/react-datepicker.css'; import { MIN_EDITED_CREATION_TIME, MAX_EDITED_CREATION_TIME, - ALL_TIME, } from 'constants/file'; - -const isSameDay = (first, second) => - first.getFullYear() === second.getFullYear() && - first.getMonth() === second.getMonth() && - first.getDate() === second.getDate(); +import { TextField } from '@mui/material'; +import { + LocalizationProvider, + MobileDateTimePicker, +} from '@mui/x-date-pickers'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; interface Props { - loading?: boolean; - isInEditMode: boolean; - pickedTime: Date; - handleChange: (date: Date) => void; + initialValue?: Date; + disabled?: boolean; + label?: string; + onSubmit: (date: Date) => void; + onClose?: () => void; } const EnteDateTimePicker = ({ - loading, - isInEditMode, - pickedTime, - handleChange, -}: Props) => ( - -); + initialValue, + disabled, + onSubmit, + onClose, +}: Props) => { + const [open, setOpen] = useState(true); + const [value, setValue] = useState(initialValue ?? new Date()); + + const handleClose = () => { + setOpen(false); + onClose?.(); + }; + return ( + + setOpen(true)} + maxDateTime={MAX_EDITED_CREATION_TIME} + minDateTime={MIN_EDITED_CREATION_TIME} + disabled={disabled} + onAccept={onSubmit} + DialogProps={{ + sx: { + zIndex: '1502', + '.MuiPickersToolbar-penIconButton': { + display: 'none', + }, + '.MuiDialog-paper': { width: '320px' }, + '.MuiClockPicker-root': { + position: 'relative', + minHeight: '292px', + }, + '.PrivatePickersSlideTransition-root': { + minHeight: '200px', + }, + }, + }} + renderInput={(params) => ( + + )} + /> + + ); +}; export default EnteDateTimePicker; diff --git a/src/components/EnteLogo.tsx b/src/components/EnteLogo.tsx new file mode 100644 index 000000000..04ced841b --- /dev/null +++ b/src/components/EnteLogo.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { styled } from '@mui/material'; + +const LogoImage = styled('img')` + margin: 3px 0; +`; + +export function EnteLogo(props) { + return ( + + ); +} diff --git a/src/components/EnteSpinner.tsx b/src/components/EnteSpinner.tsx index 054a6c62f..344801326 100644 --- a/src/components/EnteSpinner.tsx +++ b/src/components/EnteSpinner.tsx @@ -1,20 +1,6 @@ import React from 'react'; -import { Spinner } from 'react-bootstrap'; +import CircularProgress from '@mui/material/CircularProgress'; export default function EnteSpinner(props) { - const { style, ...others } = props ?? {}; - return ( - - ); + return ; } diff --git a/src/components/ExportFinished.tsx b/src/components/ExportFinished.tsx index 563286512..07701b9f2 100644 --- a/src/components/ExportFinished.tsx +++ b/src/components/ExportFinished.tsx @@ -1,19 +1,15 @@ +import { Button, DialogActions, DialogContent, Stack } from '@mui/material'; import React from 'react'; -import { Button } from 'react-bootstrap'; import { ExportStats } from 'types/export'; -import { formatDateTime } from 'utils/file'; +import { formatDateTime } from 'utils/time'; import constants from 'utils/strings/constants'; -import { Label, Row, Value } from './Container'; +import { FlexWrapper, Label, Value } from './Container'; import { ComfySpan } from './ExportInProgress'; interface Props { - show: boolean; onHide: () => void; - exportFolder: string; - exportSize: string; lastExportTime: number; exportStats: ExportStats; - updateExportFolder: (newFolder: string) => void; exportFiles: () => void; retryFailed: () => void; } @@ -22,70 +18,58 @@ export default function ExportFinished(props: Props) { const totalFiles = props.exportStats.failed + props.exportStats.success; return ( <> -
- - - - {formatDateTime(props.lastExportTime)} - - - - - - - {props.exportStats.success} / {totalFiles} - - - - {props.exportStats.failed > 0 && ( - - - )} -
-
- -
+ + {props.exportStats.failed > 0 && ( + + + + + {props.exportStats.failed} / {totalFiles} + + + + )} + + + {props.exportStats.failed !== 0 ? ( ) : ( )} -
+ + ); } diff --git a/src/components/ExportInProgress.tsx b/src/components/ExportInProgress.tsx index 6f508a545..c27632418 100644 --- a/src/components/ExportInProgress.tsx +++ b/src/components/ExportInProgress.tsx @@ -1,20 +1,23 @@ import React from 'react'; -import { Button, ProgressBar } from 'react-bootstrap'; import { ExportProgress } from 'types/export'; -import styled from 'styled-components'; +import { + Box, + Button, + DialogActions, + DialogContent, + styled, +} from '@mui/material'; import constants from 'utils/strings/constants'; import { ExportStage } from 'constants/export'; +import VerticallyCentered, { FlexWrapper } from './Container'; +import { ProgressBar } from 'react-bootstrap'; -export const ComfySpan = styled.span` +export const ComfySpan = styled('span')` word-spacing: 1rem; color: #ddd; `; interface Props { - show: boolean; - onHide: () => void; - exportFolder: string; - exportSize: string; exportStage: ExportStage; exportProgress: ExportProgress; resumeExport: () => void; @@ -25,66 +28,59 @@ interface Props { export default function ExportInProgress(props: Props) { return ( <> -
-
- - {' '} - {props.exportProgress.current} /{' '} - {props.exportProgress.total}{' '} - {' '} - - {' '} - files exported{' '} - {props.exportStage === ExportStage.PAUSED && `(paused)`} - -
-
- -
-
- {props.exportStage === ExportStage.PAUSED ? ( - - ) : ( - - )} -
+ + + + + {' '} + {props.exportProgress.current} /{' '} + {props.exportProgress.total}{' '} + {' '} + + {' '} + files exported{' '} + {props.exportStage === ExportStage.PAUSED && + `(paused)`} + + + + + + + + + {props.exportStage === ExportStage.PAUSED ? ( -
-
+ ) : ( + + )} + + ); } diff --git a/src/components/ExportInit.tsx b/src/components/ExportInit.tsx index 29a45ffc0..3c8757c45 100644 --- a/src/components/ExportInit.tsx +++ b/src/components/ExportInit.tsx @@ -1,35 +1,18 @@ -import { DeadCenter } from 'pages/gallery'; +import { Button, DialogActions, DialogContent } from '@mui/material'; import React from 'react'; -import { Button } from 'react-bootstrap'; import constants from 'utils/strings/constants'; interface Props { - show: boolean; - onHide: () => void; - updateExportFolder: (newFolder: string) => void; - exportFolder: string; startExport: () => void; - exportSize: string; - selectExportDirectory: () => void; } -export default function ExportInit(props: Props) { +export default function ExportInit({ startExport }: Props) { return ( - <> - - - - + + ); } diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index 17f1c790f..4f0e96da5 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -1,42 +1,43 @@ import isElectron from 'is-electron'; -import React, { useEffect, useState } from 'react'; -import { Button } from 'react-bootstrap'; +import React, { useEffect, useMemo, useState } from 'react'; import exportService from 'services/exportService'; import { ExportProgress, ExportStats } from 'types/export'; import { getLocalFiles } from 'services/fileService'; import { User } from 'types/user'; -import styled from 'styled-components'; +import { + Button, + Dialog, + DialogContent, + Divider, + Stack, + styled, + Tooltip, +} from '@mui/material'; import { sleep } from 'utils/common'; import { getExportRecordFileUID } from 'utils/export'; import { logError } from 'utils/sentry'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; import constants from 'utils/strings/constants'; -import { Label, Row, Value } from './Container'; +import { FlexWrapper, Label, Value } from './Container'; import ExportFinished from './ExportFinished'; import ExportInit from './ExportInit'; import ExportInProgress from './ExportInProgress'; -import FolderIcon from './icons/FolderIcon'; -import InProgressIcon from './icons/InProgressIcon'; -import MessageDialog from './MessageDialog'; +import FolderIcon from '@mui/icons-material/Folder'; import { ExportStage, ExportType } from 'constants/export'; +import EnteSpinner from './EnteSpinner'; +import DialogTitleWithCloseButton from './DialogBox/TitleWithCloseButton'; +import MoreHoriz from '@mui/icons-material/MoreHoriz'; +import OverflowMenu from './OverflowMenu/menu'; +import { OverflowMenuOption } from './OverflowMenu/option'; +import { convertBytesToHumanReadable } from 'utils/file/size'; +import { CustomError } from 'utils/error'; +import { getLocalUserDetails } from 'utils/user'; -const FolderIconWrapper = styled.div` - width: 15%; - margin-left: 10px; - cursor: pointer; - padding: 3px; - border: 1px solid #444; - border-radius: 15%; - &:hover { - background-color: #444; - } -`; - -const ExportFolderPathContainer = styled.span` +const ExportFolderPathContainer = styled('span')` white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - width: 200px; + width: 100%; /* Beginning of string */ direction: rtl; @@ -46,9 +47,9 @@ const ExportFolderPathContainer = styled.span` interface Props { show: boolean; onHide: () => void; - usage: string; } export default function ExportModal(props: Props) { + const userDetails = useMemo(() => getLocalUserDetails(), []); const [exportStage, setExportStage] = useState(ExportStage.INIT); const [exportFolder, setExportFolder] = useState(''); const [exportSize, setExportSize] = useState(''); @@ -146,8 +147,8 @@ export default function ExportModal(props: Props) { }, [props.show]); useEffect(() => { - setExportSize(props.usage); - }, [props.usage]); + setExportSize(convertBytesToHumanReadable(userDetails?.usage)); + }, [userDetails]); // ============= // STATE UPDATERS @@ -179,11 +180,7 @@ export default function ExportModal(props: Props) { const preExportRun = async () => { const exportFolder = getData(LS_KEYS.EXPORT)?.folder; if (!exportFolder) { - const folderSelected = await selectExportDirectory(); - if (!folderSelected) { - // no-op as select folder aborted - return; - } + await selectExportDirectory(); } updateExportStage(ExportStage.INPROGRESS); await sleep(100); @@ -193,98 +190,121 @@ export default function ExportModal(props: Props) { updateExportStage(ExportStage.FINISHED); await sleep(100); updateExportTime(Date.now()); - syncExportStatsWithReport(); + syncExportStatsWithRecord(); } }; - const startExport = async () => { - await preExportRun(); - updateExportProgress({ current: 0, total: 0 }); - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.NEW - ); - await postExportRun(exportResult); - }; - - const stopExport = async () => { - exportService.stopRunningExport(); - postExportRun(); - }; - - const pauseExport = () => { - updateExportStage(ExportStage.PAUSED); - exportService.pauseRunningExport(); - postExportRun({ paused: true }); - }; - - const resumeExport = async () => { - const exportRecord = await exportService.getExportRecord(); - await preExportRun(); - - const pausedStageProgress = exportRecord.progress; - setExportProgress(pausedStageProgress); - - const updateExportStatsWithOffset = (progress: ExportProgress) => - updateExportProgress({ - current: pausedStageProgress.current + progress.current, - total: pausedStageProgress.current + progress.total, - }); - const exportResult = await exportService.exportFiles( - updateExportStatsWithOffset, - ExportType.PENDING - ); - - await postExportRun(exportResult); - }; - - const retryFailedExport = async () => { - await preExportRun(); - updateExportProgress({ current: 0, total: exportStats.failed }); - - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.RETRY_FAILED - ); - await postExportRun(exportResult); - }; - - const syncExportStatsWithReport = async () => { - const exportRecord = await exportService.getExportRecord(); - const failed = exportRecord?.failedFiles?.length ?? 0; - const success = exportRecord?.exportedFiles?.length ?? 0; - setExportStats({ failed, success }); - }; const selectExportDirectory = async () => { const newFolder = await exportService.selectExportDirectory(); if (newFolder) { updateExportFolder(newFolder); - return true; } else { - return false; + throw Error(CustomError.REQUEST_CANCELLED); } }; - const ExportDynamicState = () => { + const syncExportStatsWithRecord = async () => { + const exportRecord = await exportService.getExportRecord(); + const failed = exportRecord?.failedFiles?.length ?? 0; + const success = exportRecord?.exportedFiles?.length ?? 0; + setExportStats({ failed, success }); + }; + + // ============= + // UI functions + // ============= + + const startExport = async () => { + try { + await preExportRun(); + updateExportProgress({ current: 0, total: 0 }); + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.NEW + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'startExport failed'); + } + } + }; + + const stopExport = async () => { + try { + exportService.stopRunningExport(); + postExportRun(); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'stopExport failed'); + } + } + }; + + const pauseExport = () => { + try { + updateExportStage(ExportStage.PAUSED); + exportService.pauseRunningExport(); + postExportRun({ paused: true }); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'pauseExport failed'); + } + } + }; + + const resumeExport = async () => { + try { + const exportRecord = await exportService.getExportRecord(); + await preExportRun(); + + const pausedStageProgress = exportRecord.progress; + setExportProgress(pausedStageProgress); + + const updateExportStatsWithOffset = (progress: ExportProgress) => + updateExportProgress({ + current: pausedStageProgress.current + progress.current, + total: pausedStageProgress.current + progress.total, + }); + const exportResult = await exportService.exportFiles( + updateExportStatsWithOffset, + ExportType.PENDING + ); + + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'resumeExport failed'); + } + } + }; + + const retryFailedExport = async () => { + try { + await preExportRun(); + updateExportProgress({ current: 0, total: exportStats.failed }); + + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.RETRY_FAILED + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'retryFailedExport failed'); + } + } + }; + + const ExportDynamicContent = () => { switch (exportStage) { case ExportStage.INIT: - return ( - - ); + return ; + case ExportStage.INPROGRESS: case ExportStage.PAUSED: return ( -
- - - - {!exportFolder ? ( - - ) : ( - <> - - {exportFolder} - - {(exportStage === ExportStage.FINISHED || - exportStage === ExportStage.INIT) && ( - - - - )} - - )} - - - - - - {exportSize ? `${exportSize}` : } - - -
- - + + + {constants.EXPORT_DATA} + + + + + + + + + + + ); +} + +function ExportDirectory({ exportFolder, selectExportDirectory, exportStage }) { + return ( + + + + {!exportFolder ? ( + + ) : ( + <> + + + {exportFolder} + + + {(exportStage === ExportStage.FINISHED || + exportStage === ExportStage.INIT) && ( + + )} + + )} + + + ); +} + +function ExportSize({ exportSize }) { + return ( + + + + {exportSize ? `${exportSize}` : } + + + ); +} + +function ExportDirectoryOption({ selectExportDirectory }) { + const handleClick = () => { + try { + selectExportDirectory(); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'startExport failed'); + } + } + }; + return ( + }> + }> + {constants.CHANGE_FOLDER} + + ); } diff --git a/src/components/FavButton.tsx b/src/components/FavButton.tsx deleted file mode 100644 index 32a988e8b..000000000 --- a/src/components/FavButton.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -const HeartUI = styled.button<{ - isClick: boolean; - size: number; -}>` - width: ${(props) => props.size}px; - height: ${(props) => props.size}px; - float: right; - background: url('/fav-button.png') no-repeat; - cursor: pointer; - background-size: cover; - border: none; - ${({ isClick, size }) => - isClick && - `background-position: -${ - 28 * size - }px;transition: background 1s steps(28);`} -`; - -export default function FavButton({ isClick, onClick, size }) { - return ; -} diff --git a/src/components/FileList.tsx b/src/components/FileList.tsx new file mode 100644 index 000000000..00269d7d0 --- /dev/null +++ b/src/components/FileList.tsx @@ -0,0 +1,37 @@ +import { Box, Tooltip } from '@mui/material'; +import React from 'react'; +import { FixedSizeList as List } from 'react-window'; + +interface Iprops { + fileList: any[]; +} + +export default function FileList(props: Iprops) { + const Row = ({ index, style }) => ( + +
{props.fileList[index]}
+
+ ); + + return ( + + + {Row} + + + ); +} diff --git a/src/components/FixCreationTime/index.tsx b/src/components/FixCreationTime/index.tsx index c65fec4b6..52d7c695c 100644 --- a/src/components/FixCreationTime/index.tsx +++ b/src/components/FixCreationTime/index.tsx @@ -1,5 +1,5 @@ import constants from 'utils/strings/constants'; -import MessageDialog from '../MessageDialog'; +import DialogBox from '../DialogBox'; import React, { useContext, useEffect, useState } from 'react'; import { updateCreationTimeWithExif } from 'services/updateCreationTimeWithExif'; import { GalleryContext } from 'pages/gallery'; @@ -93,15 +93,14 @@ export default function FixCreationTime(props: Props) { }; return ( -
-
+ ); } diff --git a/src/components/FixCreationTime/options.tsx b/src/components/FixCreationTime/options.tsx index 673260aef..3415c3887 100644 --- a/src/components/FixCreationTime/options.tsx +++ b/src/components/FixCreationTime/options.tsx @@ -69,9 +69,7 @@ export default function FixCreationTimeOptions({ handleChange, values }) { {Number(values.option) === FIX_OPTIONS.CUSTOM_TIME && ( + onSubmit={(x: Date) => handleChange('customTime')(x.toUTCString()) } /> diff --git a/src/components/FixLargeThumbnail.tsx b/src/components/FixLargeThumbnail.tsx index 9d574901e..8dfd0a2df 100644 --- a/src/components/FixLargeThumbnail.tsx +++ b/src/components/FixLargeThumbnail.tsx @@ -1,5 +1,5 @@ import constants from 'utils/strings/constants'; -import MessageDialog from './MessageDialog'; +import DialogBox from './DialogBox'; import React, { useEffect, useState } from 'react'; import { ProgressBar, Button } from 'react-bootstrap'; import { ComfySpan } from './ExportInProgress'; @@ -136,12 +136,11 @@ export default function FixLargeThumbnails(props: Props) { setData(LS_KEYS.THUMBNAIL_FIX_STATE, { state: fixState }); }; return ( -
-
+ ); } diff --git a/src/components/Form/FormContainer.tsx b/src/components/Form/FormContainer.tsx new file mode 100644 index 000000000..74eada32f --- /dev/null +++ b/src/components/Form/FormContainer.tsx @@ -0,0 +1,5 @@ +import VerticallyCentered from 'components/Container'; + +const FormContainer = VerticallyCentered; + +export default FormContainer; diff --git a/src/components/Form/FormPaper/Footer.tsx b/src/components/Form/FormPaper/Footer.tsx new file mode 100644 index 000000000..f49f31901 --- /dev/null +++ b/src/components/Form/FormPaper/Footer.tsx @@ -0,0 +1,22 @@ +import React, { FC } from 'react'; +import { BoxProps, Divider } from '@mui/material'; +import Container from 'components/Container'; + +const FormPaperFooter: FC = ({ sx, style, ...props }) => { + return ( + <> + + + {props.children} + + + ); +}; + +export default FormPaperFooter; diff --git a/src/components/Form/FormPaper/Title.tsx b/src/components/Form/FormPaper/Title.tsx new file mode 100644 index 000000000..3d19b2a96 --- /dev/null +++ b/src/components/Form/FormPaper/Title.tsx @@ -0,0 +1,12 @@ +import React, { FC } from 'react'; +import { Typography, TypographyProps } from '@mui/material'; + +const FormPaperTitle: FC = ({ sx, ...props }) => { + return ( + + {props.children} + + ); +}; + +export default FormPaperTitle; diff --git a/src/components/Form/FormPaper/index.tsx b/src/components/Form/FormPaper/index.tsx new file mode 100644 index 000000000..32f2ad21a --- /dev/null +++ b/src/components/Form/FormPaper/index.tsx @@ -0,0 +1,9 @@ +import { Paper, styled } from '@mui/material'; + +const FormPaper = styled(Paper)(({ theme }) => ({ + padding: theme.spacing(4, 2), + maxWidth: '360px', + width: '100%', + textAlign: 'left', +})); +export default FormPaper; diff --git a/src/components/Form/ShowHidePassword.tsx b/src/components/Form/ShowHidePassword.tsx new file mode 100644 index 000000000..92752913b --- /dev/null +++ b/src/components/Form/ShowHidePassword.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { IconButton, InputAdornment } from '@mui/material'; +import VisibilityIcon from '@mui/icons-material/Visibility'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; + +interface Iprops { + showPassword: boolean; + handleClickShowPassword: () => void; + handleMouseDownPassword: ( + event: React.MouseEvent + ) => void; +} +const ShowHidePassword = ({ + showPassword, + handleClickShowPassword, + handleMouseDownPassword, +}: Iprops) => ( + + + {showPassword ? : } + + +); + +export default ShowHidePassword; diff --git a/src/components/FullScreenDropZone.tsx b/src/components/FullScreenDropZone.tsx index be43537f8..41ad96fb1 100644 --- a/src/components/FullScreenDropZone.tsx +++ b/src/components/FullScreenDropZone.tsx @@ -1,20 +1,20 @@ import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; +import { styled } from '@mui/material'; import constants from 'utils/strings/constants'; -import CloseIcon from './icons/CloseIcon'; +import CloseIcon from '@mui/icons-material/Close'; -const CloseButtonWrapper = styled.div` +const CloseButtonWrapper = styled('div')` position: absolute; top: 10px; right: 10px; cursor: pointer; `; -const DropDiv = styled.div` +const DropDiv = styled('div')` flex: 1; display: flex; flex-direction: column; `; -const Overlay = styled.div` +const Overlay = styled('div')` border-width: 8px; left: 0; top: 0; @@ -37,8 +37,7 @@ const Overlay = styled.div` `; type Props = React.PropsWithChildren<{ - getRootProps: any; - getInputProps: any; + getDragAndDropRootProps: any; }>; export default function FullScreenDropZone(props: Props) { @@ -55,10 +54,9 @@ export default function FullScreenDropZone(props: Props) { }, []); return ( - {isDragActive && ( diff --git a/src/components/IconWithMessage.tsx b/src/components/IconWithMessage.tsx new file mode 100644 index 000000000..0f8ea7d58 --- /dev/null +++ b/src/components/IconWithMessage.tsx @@ -0,0 +1,19 @@ +import { OverlayTrigger, Tooltip } from 'react-bootstrap'; +import React from 'react'; + +interface IconWithMessageProps { + children?: any; + message: string; +} + +export const IconWithMessage = (props: IconWithMessageProps) => ( + + {props.message} + + }> + {props.children} + +); diff --git a/src/components/IncognitoWarning.tsx b/src/components/IncognitoWarning.tsx deleted file mode 100644 index f6e449247..000000000 --- a/src/components/IncognitoWarning.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import constants from 'utils/strings/constants'; -import MessageDialog from './MessageDialog'; - -export default function IncognitoWarning() { - return ( - null} - attributes={{ - title: constants.LOCAL_STORAGE_NOT_ACCESSIBLE, - staticBackdrop: true, - nonClosable: true, - }}> -
{constants.LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE}
-
- ); -} diff --git a/src/components/LivePhotoBtn.tsx b/src/components/LivePhotoBtn.tsx new file mode 100644 index 000000000..bb1976db9 --- /dev/null +++ b/src/components/LivePhotoBtn.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +export const livePhotoBtnHTML = ( + + + + +); diff --git a/src/components/LoadingOverlay.tsx b/src/components/LoadingOverlay.tsx index 7eedd1750..3d75a1848 100644 --- a/src/components/LoadingOverlay.tsx +++ b/src/components/LoadingOverlay.tsx @@ -1,6 +1,5 @@ -import styled from 'styled-components'; - -export const LoadingOverlay = styled.div` +import { styled } from '@mui/material'; +export const LoadingOverlay = styled('div')` left: 0; top: 0; outline: none; diff --git a/src/components/Login.tsx b/src/components/Login.tsx index 1309d2b97..1298de221 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -1,21 +1,14 @@ -import Card from 'react-bootstrap/Card'; -import Form from 'react-bootstrap/Form'; -import FormControl from 'react-bootstrap/FormControl'; import constants from 'utils/strings/constants'; -import { Formik, FormikHelpers } from 'formik'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect } from 'react'; import { useRouter } from 'next/router'; -import * as Yup from 'yup'; -import { getOtt } from 'services/userService'; +import { sendOtt } from 'services/userService'; import { setData, LS_KEYS, getData } from 'utils/storage/localStorage'; -import SubmitButton from 'components/SubmitButton'; -import Button from 'react-bootstrap/Button'; -import LogoImg from './LogoImg'; import { PAGES } from 'constants/pages'; - -interface formValues { - email: string; -} +import FormPaperTitle from './Form/FormPaper/Title'; +import FormPaperFooter from './Form/FormPaper/Footer'; +import LinkButton from './pages/gallery/LinkButton'; +import SingleInputForm, { SingleInputFormProps } from './SingleInputForm'; +import { Input } from '@mui/material'; interface LoginProps { signUp: () => void; @@ -23,8 +16,6 @@ interface LoginProps { export default function Login(props: LoginProps) { const router = useRouter(); - const [waiting, setWaiting] = useState(false); - const [loading, setLoading] = useState(true); useEffect(() => { const main = async () => { @@ -33,82 +24,40 @@ export default function Login(props: LoginProps) { if (user?.email) { await router.push(PAGES.VERIFY); } - setLoading(false); }; main(); }, []); - const loginUser = async ( - { email }: formValues, - { setFieldError }: FormikHelpers + const loginUser: SingleInputFormProps['callback'] = async ( + email, + setFieldError ) => { try { - setWaiting(true); - await getOtt(email); + await sendOtt(email); setData(LS_KEYS.USER, { email }); router.push(PAGES.VERIFY); } catch (e) { - setFieldError('email', `${constants.UNKNOWN_ERROR} ${e.message}`); + setFieldError(`${constants.UNKNOWN_ERROR} ${e.message}`); } - setWaiting(false); }; - const inputElement = useRef(null); - useEffect(() => { - setTimeout(() => { - inputElement.current?.focus(); - }, 250); - }, []); return ( <> - - - {constants.LOGIN} - - - initialValues={{ email: '' }} - validationSchema={Yup.object().shape({ - email: Yup.string() - .email(constants.EMAIL_ERROR) - .required(constants.REQUIRED), - })} - validateOnChange={false} - validateOnBlur={false} - onSubmit={loginUser}> - {({ values, errors, touched, handleChange, handleSubmit }) => ( -
- - - - {errors.email} - - - -
- - - )} - + {constants.LOGIN} +