[
  {
    "path": ".gitattributes",
    "content": "dist/article/article.js text eol=lf\ndist/article/mercury.web.js text eol=lf"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [\"yang991178\"] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # \"fluent-reader\"\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom:\n    [\n        \"https://www.paypal.me/yang991178\",\n        \"https://hyliu.me/fluent-reader/imgs/alipay.jpg\",\n    ]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Platform (please complete the following information):**\n - OS: [e.g. Windows 10 2004]\n - Version [e.g. 0.6.1]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/release-linux.yml",
    "content": "name: CI/CD Release Linux\n\non:\n    release:\n        types:\n            - published\n\njobs:\n    release-linux:\n        runs-on: ubuntu-latest\n\n        steps:\n            - uses: actions/checkout@v2\n\n            - name: Build and package the app\n              run: |\n                  npm install\n                  npm run build\n                  npm run package-linux\n\n            - name: Get app version\n              id: package-version\n              uses: martinbeentjes/npm-get-version-action@master\n\n            - name: Get release\n              id: get_release\n              uses: bruceadams/get-release@v1.2.0\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n            - name: Upload AppImage to release assets\n              uses: actions/upload-release-asset@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  upload_url: ${{ steps.get_release.outputs.upload_url }}\n                  asset_path: ./bin/linux/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}.AppImage\n                  asset_name: Fluent.Reader.${{ steps.package-version.outputs.current-version }}.AppImage\n                  asset_content_type: application/octet-stream\n"
  },
  {
    "path": ".github/workflows/release-main.yml",
    "content": "name: CI/CD Release\n\non:\n    push:\n        tags:\n            - \"v*\"\n\njobs:\n    release:\n        runs-on: windows-latest\n\n        steps:\n            - uses: actions/checkout@v2\n\n            - name: Build and package the app\n              run: |\n                  npm install\n                  npm run build\n                  npm run package-win-ci\n\n            - name: Get app version\n              id: package-version\n              run: |\n                  PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]')\n                  echo ::set-output name=current-version::$PACKAGE_VERSION\n              shell: bash\n\n            - name: Create release\n              id: create_release\n              uses: actions/create-release@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  tag_name: ${{ github.ref }}\n                  release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }}\n                  draft: true\n                  prerelease: false\n\n            - name: Upload x64 exe to release assets\n              uses: actions/upload-release-asset@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  upload_url: ${{ steps.create_release.outputs.upload_url }}\n                  asset_path: ./bin/win32/x64/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe\n                  asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x64.exe\n                  asset_content_type: application/vnd.microsoft.portable-executable\n\n            - name: Upload x86 exe to release assets\n              uses: actions/upload-release-asset@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  upload_url: ${{ steps.create_release.outputs.upload_url }}\n                  asset_path: ./bin/win32/ia32/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe\n                  asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x86.exe\n                  asset_content_type: application/vnd.microsoft.portable-executable\n\n            - name: Upload x64 zip to release assets\n              uses: actions/upload-release-asset@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  upload_url: ${{ steps.create_release.outputs.upload_url }}\n                  asset_path: ./bin/win32/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}-win.zip\n                  asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x64.zip\n                  asset_content_type: application/zip\n\n            - name: Upload x86 zip to release assets\n              uses: actions/upload-release-asset@v1\n              env:\n                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n              with:\n                  upload_url: ${{ steps.create_release.outputs.upload_url }}\n                  asset_path: ./bin/win32/ia32/Fluent Reader-${{ steps.package-version.outputs.current-version }}-ia32-win.zip\n                  asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x86.zip\n                  asset_content_type: application/zip\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ndist/*.js\ndist/*.js.map\ndist/*.html\ndist/*.LICENSE.txt\nbin/*\n.DS_Store\n*.provisionprofile\n*.lock"
  },
  {
    "path": ".prettierignore",
    "content": "node_modules\ndist/**/*.js\ndist/**/*.js.map\nbin/*\n.DS_Store\n*.provisionprofile\n*.lock\n\n*.html\n*.md\n*.json\n!src/**/*.json\n"
  },
  {
    "path": ".prettierrc.yml",
    "content": "tabWidth: 4\nsemi: false\njsxBracketSameLine: true\narrowParens: \"avoid\"\nquoteProps: \"consistent\"\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n      {\n        \"name\": \"Debug Main Process\",\n        \"type\": \"node\",\n        \"request\": \"launch\",\n        \"cwd\": \"${workspaceRoot}\",\n        \"runtimeExecutable\": \"${workspaceRoot}/node_modules/.bin/electron\",\n        \"windows\": {\n          \"runtimeExecutable\": \"${workspaceRoot}/node_modules/.bin/electron.cmd\"\n        },\n        \"program\": \"${workspaceRoot}/dist/electron.js\",\n        \"args\" : [\".\"],\n        \"outputCapture\": \"std\",\n        \"sourceMaps\": true\n      }\n    ]\n  }"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2020, Haoyuan Liu\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img width=\"120\" height=\"120\" src=\"https://github.com/yang991178/fluent-reader/raw/master/build/icon.png\">\n</p>\n<h3 align=\"center\">Fluent Reader</h3>\n<p align=\"center\">A modern desktop RSS reader</p>\n<p align=\"center\">\n  <img src=\"https://img.shields.io/github/v/release/yang991178/fluent-reader?label=version\" />\n  <img src=\"https://img.shields.io/github/downloads/yang991178/fluent-reader/total\" />\n  <img src=\"https://github.com/yang991178/fluent-reader/workflows/CI%2FCD%20Release/badge.svg\" />\n</p>\n<hr />\n\n## Download\n\nFor Windows 10 users, the recommended way of installation is through [Microsoft Store](https://www.microsoft.com/store/apps/9P71FC94LRH8?cid=github). \nThis enables auto-update and experimental ARM64 support. \nmacOS users can also get Fluent Reader from the [Mac App Store](https://apps.apple.com/app/id1520907427).\n\nIf you are using Linux or an older version of Windows, you can [get Fluent Reader from GitHub releases](https://github.com/yang991178/fluent-reader/releases).\n\n### Mobile App\n\nThe repo of the mobile version of this app [can be found here](https://github.com/yang991178/fluent-reader-lite).\n\n## Features\n\n<p align=\"center\">\n  <img src=\"https://github.com/yang991178/fluent-reader/raw/master/docs/imgs/screenshot.jpg\">\n</p>\n\n- A modern UI inspired by Fluent Design System with full dark mode support.\n- Read locally or sync with self-hosted services compatible with Fever or Google Reader API.\n- Sync with RSS Services including Inoreader, Feedbin, The Old Reader, BazQux Reader, and more.\n- Importing or exporting OPML files, full application data backup & restoration.\n- Read the full content with the built-in article view or load webpages by default.\n- Search for articles with regular expressions or filter by read status.\n- Organize your subscriptions with folder-like groupings.\n- Single-key [keyboard shortcuts](https://github.com/yang991178/fluent-reader/wiki/Support#keyboard-shortcuts).\n- Hide, mark as read, or star articles automatically as they arrive with regular expression rules.\n- Fetch articles in the background and send push notifications.\n\nSupport for other RSS services are [under fundraising](https://github.com/yang991178/fluent-reader/issues/23). \n\n## Development\n\n### Contribute\n\nHelp make Fluent Reader better by reporting bugs or opening feature requests through [GitHub issues](https://github.com/yang991178/fluent-reader/issues). \n\nYou can also help internationalize the app by providing [translations into additional languages](https://github.com/yang991178/fluent-reader/tree/master/src/scripts/i18n). \nRefer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization. \n\nIf you enjoy using this app, consider supporting its development by donating through [GitHub Sponsors](https://github.com/sponsors/yang991178), [Paypal](https://www.paypal.me/yang991178), or [Alipay](https://hyliu.me/fluent-reader/imgs/alipay.jpg).\n\n### Build from source\n```bash\n# Install dependencies\nnpm install\n\n# Compile ts & dependencies\nnpm run build\n\n# Start the application\nnpm run electron\n\n# Generate certificate for signature\nelectron-builder create-self-signed-cert\n# Package the app for Windows\nnpm run package-win\n\n```\n\n### Developed with\n\n- [Electron](https://github.com/electron/electron)\n- [React](https://github.com/facebook/react)\n- [Redux](https://github.com/reduxjs/redux)\n- [Fluent UI](https://github.com/microsoft/fluentui)\n- [Lovefield](https://github.com/google/lovefield)\n- [Mercury Parser](https://github.com/postlight/mercury-parser)\n\n### License\n\nBSD\n"
  },
  {
    "path": "build/entitlements.mas.inherit.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">  \n<plist version=\"1.0\"> \n  <dict>  \n    <key>com.apple.security.app-sandbox</key><true/>  \n    <key>com.apple.security.inherit</key><true/>\n    <key>com.apple.security.cs.allow-jit</key><true/>\n    <key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>\n  </dict> \n</plist>  "
  },
  {
    "path": "build/entitlements.mas.loginhelper.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n    <dict>\n        <key>com.apple.security.app-sandbox</key><true/>\n    </dict>\n</plist>"
  },
  {
    "path": "build/entitlements.mas.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">  \n<plist version=\"1.0\"> \n  <dict>  \n    <key>com.apple.security.app-sandbox</key><true/>\n    <key>com.apple.security.application-groups</key>  \n    <array> \n      <string>EM8VE646TZ.DevHYLiu.FluentReader</string>  \n    </array>  \n    <!-- Put any entitlements your app requires here. Below is a example --> \n    <key>com.apple.security.network.client</key><true/>\n    <key>com.apple.security.files.user-selected.read-write</key><true/>\n    <key>com.apple.security.files.user-selected.read-only</key><true/>\n    <key>com.apple.security.cs.allow-jit</key><true/>\n    <key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>\n    <key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>\n  </dict> \n</plist>  "
  },
  {
    "path": "build/resignAndPackage.sh",
    "content": "# Name of your app.\nAPP=\"Fluent Reader\"\n# Your Certificate name.\nCERT=\"Jieyu Yan (EM8VE646TZ)\"\n# The path of your app to sign.\nAPP_PATH=\"bin/darwin/universal/mas-universal/Fluent Reader.app\"\n# The path to the location you want to put the signed package.\nRESULT_PATH=\"bin/$APP-mac_store.pkg\"\n# The name of certificates you requested.\nAPP_KEY=\"Apple Distribution: $CERT\"\nINSTALLER_KEY=\"3rd Party Mac Developer Installer: $CERT\"\n# The path of your plist files.\nPARENT_PLIST=\"build/entitlements.mas.plist\"\nCHILD_PLIST=\"build/entitlements.mas.inherit.plist\"\nLOGINHELPER_PLIST=\"build/entitlements.mas.loginhelper.plist\"\nFRAMEWORKS_PATH=\"$APP_PATH/Contents/Frameworks\"\n\n# Build universal binary for font-list\n# FONTLIST_PATH=\"node_modules/font-list/libs/darwin/fontlist.m\"\n# clang -arch arm64 -arch x86_64 \"$FONTLIST_PATH\" -fmodules -o \"dist/fontlist\"\n# Build the MAS app\nCSC_IDENTITY_AUTO_DISCOVERY=false npx electron-builder -c electron-builder-mas.yml --mac mas:universal\n# Add ElectronTeamID to Info.plist\nsed -i '' -e 's/<\\/dict>/<key>ElectronTeamID<\\/key><string>EM8VE646TZ<\\/string><\\/dict>/g' \"bin/darwin/universal/mas-universal/Fluent Reader.app/Contents/Info.plist\"\n\nprintf \"......................\\nresignAndPackage start\\n\\n\"\ncodesign --deep --force --verify --verbose=4 --timestamp --options runtime --entitlements \"$CHILD_PLIST\" -s \"$APP_KEY\" \"$APP_PATH/Contents/Resources/app.asar.unpacked/dist/fontlist\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libffmpeg.dylib\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/Electron Framework.framework\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper.app/\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (GPU).app/Contents/MacOS/$APP Helper (GPU)\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (GPU).app/\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (Renderer).app/Contents/MacOS/$APP Helper (Renderer)\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (Renderer).app/\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (Plugin).app/Contents/MacOS/$APP Helper (Plugin)\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$FRAMEWORKS_PATH/$APP Helper (Plugin).app/\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$LOGINHELPER_PLIST\" \"$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$LOGINHELPER_PLIST\" \"$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$CHILD_PLIST\" \"$APP_PATH/Contents/MacOS/$APP\"\ncodesign -s \"$APP_KEY\" -f --entitlements \"$PARENT_PLIST\" \"$APP_PATH\"\nproductbuild --component \"$APP_PATH\" /Applications --sign \"$INSTALLER_KEY\" \"$RESULT_PATH\"\n\nprintf \"\\nresignAndPackage end\\n......................\\n\"\n"
  },
  {
    "path": "dist/article/article.css",
    "content": "@import \"../styles/scroll.css\";\n\nhtml,\nbody {\n    margin: 0;\n    font-family: \"Segoe UI\", \"Source Han Sans Regular\", sans-serif;\n}\nbody {\n    padding: 12px 96px 32px;\n    overflow: hidden scroll;\n}\nbody.rtl {\n    direction: rtl;\n}\nbody.vertical {\n    padding: 32px;\n    padding-right: 96px;\n    writing-mode: vertical-rl;\n    overflow: scroll hidden;\n}\n\n:root {\n    --gray: #484644;\n    --primary: #0078d4;\n    --primary-alt: #004578;\n}\n@media (prefers-color-scheme: dark) {\n    :root {\n        color: #f8f8f8;\n        --gray: #a19f9d;\n        --primary: #4ba0e1;\n        --primary-alt: #65aee6;\n    }\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nb,\nstrong {\n    font-weight: 600;\n}\na {\n    color: var(--primary);\n    text-decoration: none;\n}\na:hover,\na:active {\n    color: var(--primary-alt);\n    text-decoration: underline;\n}\n\n@keyframes fadeIn {\n    0% {\n        opacity: 0;\n        transform: translateY(10px);\n    }\n    100% {\n        opacity: 1;\n        transform: translateY(0);\n    }\n}\n#main {\n    max-width: 700px;\n    margin: 0 auto;\n    display: none;\n}\nbody.vertical #main {\n    max-width: unset;\n    max-height: 700px;\n    margin: auto 0;\n}\n#main.show {\n    display: block;\n    animation-name: fadeIn;\n    animation-duration: 0.367s;\n    animation-timing-function: cubic-bezier(0.1, 0.9, 0.2, 1);\n    animation-fill-mode: both;\n}\n\n#main > p.title {\n    font-size: 1.25rem;\n    line-height: 1.75rem;\n    font-weight: 600;\n    margin-block-end: 0;\n}\n#main > p.date {\n    color: var(--gray);\n    font-size: 0.875rem;\n}\n\narticle {\n    line-height: 1.6;\n}\nbody.vertical article {\n    line-height: 1.5;\n}\nbody.vertical article p {\n    text-indent: 2rem;\n}\narticle * {\n    max-width: 100%;\n}\narticle img {\n    height: auto;\n}\nbody.vertical article img {\n    max-height: 75%;\n}\narticle figure {\n    margin: 16px 0;\n    text-align: center;\n}\narticle figure figcaption {\n    font-size: 0.875rem;\n    color: var(--gray);\n    -webkit-user-modify: read-only;\n}\narticle iframe {\n    width: 100%;\n}\narticle code {\n    font-family: Monaco, Consolas, monospace;\n    font-size: 0.875rem;\n    line-height: 1;\n}\narticle pre {\n    word-break: normal;\n    overflow-wrap: normal;\n    white-space: pre-wrap;\n}\narticle blockquote {\n    border-left: 2px solid var(--gray);\n    margin: 1em 0;\n    padding: 0 40px;\n}\n"
  },
  {
    "path": "dist/article/article.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"Content-Security-Policy\"\n        content=\"default-src 'none'; script-src-elem 'sha256-sLDWrq1tUAO8IyyqmUckFqxbXYfZ2/3TEUmtxH8Unf0=' 'sha256-iOdZeo0zvgcSuiH/7/dXCOHo7s0cn2XtsidqVOcHBjo='; img-src http: https: data:; style-src 'self' 'unsafe-inline'; frame-src http: https:; media-src http: https:; connect-src https: http:\">\n    <title>Article</title>\n    <link rel=\"stylesheet\" href=\"article.css\" />\n    <script integrity=\"sha256-sLDWrq1tUAO8IyyqmUckFqxbXYfZ2/3TEUmtxH8Unf0=\" src=\"mercury.web.js\"></script>\n</head>\n<body>\n    <div id=\"main\"></div>\n    <script integrity=\"sha256-iOdZeo0zvgcSuiH/7/dXCOHo7s0cn2XtsidqVOcHBjo=\" src=\"article.js\"></script>\n    <!-- Run \"cat article.js | openssl dgst -sha256 -binary | openssl enc -base64 -A\" for hash -->\n</body>\n</html>"
  },
  {
    "path": "dist/article/article.js",
    "content": "function get(name) {\n    if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(location.search))\n        return decodeURIComponent(name[1]);\n}\nlet dir = get(\"d\")\nif (dir === \"1\") {\n    document.body.classList.add(\"rtl\")\n} else if (dir === \"2\") {\n    document.body.classList.add(\"vertical\")\n    document.body.addEventListener(\"wheel\", (evt) => {\n        document.scrollingElement.scrollLeft -= evt.deltaY;\n    });\n}\nasync function getArticle(url) {\n    let article = get(\"a\")\n    if (get(\"m\") === \"1\") {\n        return (await Mercury.parse(url, {html: article})).content || \"\"\n    } else {\n        return article\n    }\n}\ndocument.documentElement.style.fontSize = get(\"s\") + \"px\"\nlet font = get(\"f\")\nif (font) document.body.style.fontFamily = `\"${font}\"`\nlet url = get(\"u\")\ngetArticle(url).then(article => {\n    let domParser = new DOMParser()\n    let dom = domParser.parseFromString(get(\"h\"), \"text/html\")\n    dom.getElementsByTagName(\"article\")[0].innerHTML = article\n    let baseEl = dom.createElement('base')\n    baseEl.setAttribute('href', url.split(\"/\").slice(0, 3).join(\"/\"))\n    dom.head.append(baseEl)\n    for (let s of dom.getElementsByTagName(\"script\")) {\n        s.parentNode.removeChild(s)\n    }\n    for (let e of dom.querySelectorAll(\"*[src]\")) {\n        e.src = e.src\n    }\n    for (let e of dom.querySelectorAll(\"*[href]\")) {\n        e.href = e.href\n    }\n    let main = document.getElementById(\"main\")\n    main.innerHTML = dom.body.innerHTML\n    main.classList.add(\"show\")\n})\n"
  },
  {
    "path": "dist/article/mercury.web.js",
    "content": "var Mercury=function(){\"use strict\";function $n(){throw new Error(\"Dynamic requires are not currently supported by rollup-plugin-commonjs\")}function e(e,t){return e(t={exports:{}},t.exports),t.exports}var t=e(function(O){!function(e){var u,t=Object.prototype,c=t.hasOwnProperty,n=\"function\"==typeof Symbol?Symbol:{},a=n.iterator||\"@@iterator\",r=n.asyncIterator||\"@@asyncIterator\",i=n.toStringTag||\"@@toStringTag\",o=e.regeneratorRuntime;if(o)O.exports=o;else{(o=e.regeneratorRuntime=O.exports).wrap=y;var f=\"suspendedStart\",h=\"suspendedYield\",d=\"executing\",p=\"completed\",m={},s={};s[a]=function(){return this};var l=Object.getPrototypeOf,g=l&&l(l(C([])));g&&g!==t&&c.call(g,a)&&(s=g);var v=A.prototype=b.prototype=Object.create(s);w.prototype=v.constructor=A,A.constructor=w,A[i]=w.displayName=\"GeneratorFunction\",o.isGeneratorFunction=function(e){var t=\"function\"==typeof e&&e.constructor;return!!t&&(t===w||\"GeneratorFunction\"===(t.displayName||t.name))},o.mark=function(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,A):(e.__proto__=A,i in e||(e[i]=\"GeneratorFunction\")),e.prototype=Object.create(v),e},o.awrap=function(e){return{__await:e}},x(k.prototype),k.prototype[r]=function(){return this},o.AsyncIterator=k,o.async=function(e,t,n,r){var a=new k(y(e,t,n,r));return o.isGeneratorFunction(t)?a:a.next().then(function(e){return e.done?e.value:a.next()})},x(v),v[i]=\"Generator\",v[a]=function(){return this},v.toString=function(){return\"[object Generator]\"},o.keys=function(n){var r=[];for(var e in n)r.push(e);return r.reverse(),function e(){for(;r.length;){var t=r.pop();if(t in n)return e.value=t,e.done=!1,e}return e.done=!0,e}},o.values=C,T.prototype={constructor:T,reset:function(e){if(this.prev=0,this.next=0,this.sent=this._sent=u,this.done=!1,this.delegate=null,this.method=\"next\",this.arg=u,this.tryEntries.forEach(M),!e)for(var t in this)\"t\"===t.charAt(0)&&c.call(this,t)&&!isNaN(+t.slice(1))&&(this[t]=u)},stop:function(){this.done=!0;var e=this.tryEntries[0].completion;if(\"throw\"===e.type)throw e.arg;return this.rval},dispatchException:function(n){if(this.done)throw n;var r=this;function e(e,t){return i.type=\"throw\",i.arg=n,r.next=e,t&&(r.method=\"next\",r.arg=u),!!t}for(var t=this.tryEntries.length-1;0<=t;--t){var a=this.tryEntries[t],i=a.completion;if(\"root\"===a.tryLoc)return e(\"end\");if(a.tryLoc<=this.prev){var o=c.call(a,\"catchLoc\"),s=c.call(a,\"finallyLoc\");if(o&&s){if(this.prev<a.catchLoc)return e(a.catchLoc,!0);if(this.prev<a.finallyLoc)return e(a.finallyLoc)}else if(o){if(this.prev<a.catchLoc)return e(a.catchLoc,!0)}else{if(!s)throw new Error(\"try statement without catch or finally\");if(this.prev<a.finallyLoc)return e(a.finallyLoc)}}}},abrupt:function(e,t){for(var n=this.tryEntries.length-1;0<=n;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&c.call(r,\"finallyLoc\")&&this.prev<r.finallyLoc){var a=r;break}}a&&(\"break\"===e||\"continue\"===e)&&a.tryLoc<=t&&t<=a.finallyLoc&&(a=null);var i=a?a.completion:{};return i.type=e,i.arg=t,a?(this.method=\"next\",this.next=a.finallyLoc,m):this.complete(i)},complete:function(e,t){if(\"throw\"===e.type)throw e.arg;return\"break\"===e.type||\"continue\"===e.type?this.next=e.arg:\"return\"===e.type?(this.rval=this.arg=e.arg,this.method=\"return\",this.next=\"end\"):\"normal\"===e.type&&t&&(this.next=t),m},finish:function(e){for(var t=this.tryEntries.length-1;0<=t;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),M(n),m}},catch:function(e){for(var t=this.tryEntries.length-1;0<=t;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var r=n.completion;if(\"throw\"===r.type){var a=r.arg;M(n)}return a}}throw new Error(\"illegal catch attempt\")},delegateYield:function(e,t,n){return this.delegate={iterator:C(e),resultName:t,nextLoc:n},\"next\"===this.method&&(this.arg=u),m}}}function y(e,t,n,r){var i,o,s,u,a=t&&t.prototype instanceof b?t:b,c=Object.create(a.prototype),l=new T(r||[]);return c._invoke=(i=e,o=n,s=l,u=f,function(e,t){if(u===d)throw new Error(\"Generator is already running\");if(u===p){if(\"throw\"===e)throw t;return D()}for(s.method=e,s.arg=t;;){var n=s.delegate;if(n){var r=E(n,s);if(r){if(r===m)continue;return r}}if(\"next\"===s.method)s.sent=s._sent=s.arg;else if(\"throw\"===s.method){if(u===f)throw u=p,s.arg;s.dispatchException(s.arg)}else\"return\"===s.method&&s.abrupt(\"return\",s.arg);u=d;var a=_(i,o,s);if(\"normal\"===a.type){if(u=s.done?p:h,a.arg===m)continue;return{value:a.arg,done:s.done}}\"throw\"===a.type&&(u=p,s.method=\"throw\",s.arg=a.arg)}}),c}function _(e,t,n){try{return{type:\"normal\",arg:e.call(t,n)}}catch(e){return{type:\"throw\",arg:e}}}function b(){}function w(){}function A(){}function x(e){[\"next\",\"throw\",\"return\"].forEach(function(t){e[t]=function(e){return this._invoke(t,e)}})}function k(u){var t;this._invoke=function(n,r){function e(){return new Promise(function(e,t){!function t(e,n,r,a){var i=_(u[e],u,n);if(\"throw\"!==i.type){var o=i.arg,s=o.value;return s&&\"object\"==typeof s&&c.call(s,\"__await\")?Promise.resolve(s.__await).then(function(e){t(\"next\",e,r,a)},function(e){t(\"throw\",e,r,a)}):Promise.resolve(s).then(function(e){o.value=e,r(o)},function(e){return t(\"throw\",e,r,a)})}a(i.arg)}(n,r,e,t)})}return t=t?t.then(e,e):e()}}function E(e,t){var n=e.iterator[t.method];if(n===u){if(t.delegate=null,\"throw\"===t.method){if(e.iterator.return&&(t.method=\"return\",t.arg=u,E(e,t),\"throw\"===t.method))return m;t.method=\"throw\",t.arg=new TypeError(\"The iterator does not provide a 'throw' method\")}return m}var r=_(n,e.iterator,t.arg);if(\"throw\"===r.type)return t.method=\"throw\",t.arg=r.arg,t.delegate=null,m;var a=r.arg;return a?a.done?(t[e.resultName]=a.value,t.next=e.nextLoc,\"return\"!==t.method&&(t.method=\"next\",t.arg=u),t.delegate=null,m):a:(t.method=\"throw\",t.arg=new TypeError(\"iterator result is not an object\"),t.delegate=null,m)}function S(e){var t={tryLoc:e[0]};1 in e&&(t.catchLoc=e[1]),2 in e&&(t.finallyLoc=e[2],t.afterLoc=e[3]),this.tryEntries.push(t)}function M(e){var t=e.completion||{};t.type=\"normal\",delete t.arg,e.completion=t}function T(e){this.tryEntries=[{tryLoc:\"root\"}],e.forEach(S,this),this.reset(!0)}function C(t){if(t){var e=t[a];if(e)return e.call(t);if(\"function\"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,r=function e(){for(;++n<t.length;)if(c.call(t,n))return e.value=t[n],e.done=!1,e;return e.value=u,e.done=!0,e};return r.next=r}}return{next:D}}function D(){return{value:u,done:!0}}}(function(){return this||\"object\"==typeof self&&self}()||Function(\"return this\")())}),n=function(){return this||\"object\"==typeof self&&self}()||Function(\"return this\")(),r=n.regeneratorRuntime&&0<=Object.getOwnPropertyNames(n).indexOf(\"regeneratorRuntime\"),a=r&&n.regeneratorRuntime;n.regeneratorRuntime=void 0;var i=t;if(r)n.regeneratorRuntime=a;else try{delete n.regeneratorRuntime}catch(e){n.regeneratorRuntime=void 0}var S=i,o={}.toString,s=function(e){return o.call(e).slice(8,-1)},h=Object(\"z\").propertyIsEnumerable(0)?Object:function(e){return\"String\"==s(e)?e.split(\"\"):Object(e)},u=function(e){if(null==e)throw TypeError(\"Can't call method on  \"+e);return e},c=function(e){return h(u(e))},d={f:{}.propertyIsEnumerable},A=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},l=function(e){return\"object\"==typeof e?null!==e:\"function\"==typeof e},f=function(e,t){if(!l(e))return e;var n,r;if(t&&\"function\"==typeof(n=e.toString)&&!l(r=n.call(e)))return r;if(\"function\"==typeof(n=e.valueOf)&&!l(r=n.call(e)))return r;if(!t&&\"function\"==typeof(n=e.toString)&&!l(r=n.call(e)))return r;throw TypeError(\"Can't convert object to primitive value\")},p={}.hasOwnProperty,m=function(e,t){return p.call(e,t)},g=function(e){try{return!!e()}catch(e){return!0}},v=!g(function(){return 7!=Object.defineProperty({},\"a\",{get:function(){return 7}}).a}),y=e(function(e){var t=e.exports=\"undefined\"!=typeof window&&window.Math==Math?window:\"undefined\"!=typeof self&&self.Math==Math?self:Function(\"return this\")();\"number\"==typeof __g&&(__g=t)}),_=y.document,b=l(_)&&l(_.createElement),w=function(e){return b?_.createElement(e):{}},x=!v&&!g(function(){return 7!=Object.defineProperty(w(\"div\"),\"a\",{get:function(){return 7}}).a}),k=Object.getOwnPropertyDescriptor,E={f:v?k:function(e,t){if(e=c(e),t=f(t,!0),x)try{return k(e,t)}catch(e){}if(m(e,t))return A(!d.f.call(e,t),e[t])}},M=e(function(e){var t=e.exports={version:\"2.6.2\"};\"number\"==typeof __e&&(__e=t)}),T=(M.version,function(e){if(\"function\"!=typeof e)throw TypeError(e+\" is not a function!\");return e}),C=function(r,a,e){if(T(r),void 0===a)return r;switch(e){case 1:return function(e){return r.call(a,e)};case 2:return function(e,t){return r.call(a,e,t)};case 3:return function(e,t,n){return r.call(a,e,t,n)}}return function(){return r.apply(a,arguments)}},D=function(e){if(!l(e))throw TypeError(e+\" is not an object!\");return e},O=Object.defineProperty,j={f:v?Object.defineProperty:function(e,t,n){if(D(e),t=f(t,!0),D(n),x)try{return O(e,t,n)}catch(e){}if(\"get\"in n||\"set\"in n)throw TypeError(\"Accessors not supported!\");return\"value\"in n&&(e[t]=n.value),e}},N=v?function(e,t,n){return j.f(e,t,A(1,n))}:function(e,t,n){return e[t]=n,e},z=\"prototype\",P=function(e,t,n){var r,a,i,o=e&P.F,s=e&P.G,u=e&P.S,c=e&P.P,l=e&P.B,f=e&P.W,h=s?M:M[t]||(M[t]={}),d=h[z],p=s?y:u?y[t]:(y[t]||{})[z];for(r in s&&(n=t),n)(a=!o&&p&&void 0!==p[r])&&m(h,r)||(i=a?p[r]:n[r],h[r]=s&&\"function\"!=typeof p[r]?n[r]:l&&a?C(i,y):f&&p[r]==i?function(r){var e=function(e,t,n){if(this instanceof r){switch(arguments.length){case 0:return new r;case 1:return new r(e);case 2:return new r(e,t)}return new r(e,t,n)}return r.apply(this,arguments)};return e[z]=r[z],e}(i):c&&\"function\"==typeof i?C(Function.call,i):i,c&&((h.virtual||(h.virtual={}))[r]=i,e&P.R&&d&&!d[r]&&N(d,r,i)))};P.F=1,P.G=2,P.S=4,P.P=8,P.B=16,P.W=32,P.U=64,P.R=128;var L=P,R=function(e,t){var n=(M.Object||{})[e]||Object[e],r={};r[e]=t(n),L(L.S+L.F*g(function(){n(1)}),\"Object\",r)},Y=E.f;R(\"getOwnPropertyDescriptor\",function(){return function(e,t){return Y(c(e),t)}});var W,q=M.Object,I=function(e,t){return q.getOwnPropertyDescriptor(e,t)},H=N,F=0,B=Math.random(),G=function(e){return\"Symbol(\".concat(void 0===e?\"\":e,\")_\",(++F+B).toString(36))},U=e(function(e){var n=G(\"meta\"),t=j.f,r=0,a=Object.isExtensible||function(){return!0},i=!g(function(){return a(Object.preventExtensions({}))}),o=function(e){t(e,n,{value:{i:\"O\"+ ++r,w:{}}})},s=e.exports={KEY:n,NEED:!1,fastKey:function(e,t){if(!l(e))return\"symbol\"==typeof e?e:(\"string\"==typeof e?\"S\":\"P\")+e;if(!m(e,n)){if(!a(e))return\"F\";if(!t)return\"E\";o(e)}return e[n].i},getWeak:function(e,t){if(!m(e,n)){if(!a(e))return!0;if(!t)return!1;o(e)}return e[n].w},onFreeze:function(e){return i&&s.NEED&&a(e)&&!m(e,n)&&o(e),e}}}),$=(U.KEY,U.NEED,U.fastKey,U.getWeak,U.onFreeze,e(function(e){var t=\"__core-js_shared__\",n=y[t]||(y[t]={});(e.exports=function(e,t){return n[e]||(n[e]=void 0!==t?t:{})})(\"versions\",[]).push({version:M.version,mode:\"pure\",copyright:\"© 2019 Denis Pushkarev (zloirock.ru)\"})})),V=e(function(e){var t=$(\"wks\"),n=y.Symbol,r=\"function\"==typeof n;(e.exports=function(e){return t[e]||(t[e]=r&&n[e]||(r?n:G)(\"Symbol.\"+e))}).store=t}),J=j.f,K=V(\"toStringTag\"),X=function(e,t,n){e&&!m(e=n?e:e.prototype,K)&&J(e,K,{configurable:!0,value:t})},Z={f:V},Q=j.f,ee=function(e){var t=M.Symbol||(M.Symbol={});\"_\"==e.charAt(0)||e in t||Q(t,e,{value:Z.f(e)})},te=Math.ceil,ne=Math.floor,re=function(e){return isNaN(e=+e)?0:(0<e?ne:te)(e)},ae=Math.min,ie=function(e){return 0<e?ae(re(e),9007199254740991):0},oe=Math.max,se=Math.min,ue=$(\"keys\"),ce=function(e){return ue[e]||(ue[e]=G(e))},le=(W=!1,function(e,t,n){var r,a,i,o=c(e),s=ie(o.length),u=(a=s,(r=re(r=n))<0?oe(r+a,0):se(r,a));if(W&&t!=t){for(;u<s;)if((i=o[u++])!=i)return!0}else for(;u<s;u++)if((W||u in o)&&o[u]===t)return W||u||0;return!W&&-1}),fe=ce(\"IE_PROTO\"),he=function(e,t){var n,r=c(e),a=0,i=[];for(n in r)n!=fe&&m(r,n)&&i.push(n);for(;t.length>a;)m(r,n=t[a++])&&(~le(i,n)||i.push(n));return i},de=\"constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf\".split(\",\"),pe=Object.keys||function(e){return he(e,de)},me={f:Object.getOwnPropertySymbols},ge=Array.isArray||function(e){return\"Array\"==s(e)},ve=v?Object.defineProperties:function(e,t){D(e);for(var n,r=pe(t),a=r.length,i=0;i<a;)j.f(e,n=r[i++],t[n]);return e},ye=y.document,_e=ye&&ye.documentElement,be=ce(\"IE_PROTO\"),we=function(){},Ae=\"prototype\",xe=function(){var e,t=w(\"iframe\"),n=de.length;for(t.style.display=\"none\",_e.appendChild(t),t.src=\"javascript:\",(e=t.contentWindow.document).open(),e.write(\"<script>document.F=Object<\\/script>\"),e.close(),xe=e.F;n--;)delete xe[Ae][de[n]];return xe()},ke=Object.create||function(e,t){var n;return null!==e?(we[Ae]=D(e),n=new we,we[Ae]=null,n[be]=e):n=xe(),void 0===t?n:ve(n,t)},Ee=de.concat(\"length\",\"prototype\"),Se={f:Object.getOwnPropertyNames||function(e){return he(e,Ee)}},Me=Se.f,Te={}.toString,Ce=\"object\"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],De={f:function(e){return Ce&&\"[object Window]\"==Te.call(e)?function(e){try{return Me(e)}catch(e){return Ce.slice()}}(e):Me(c(e))}},Oe=U.KEY,je=E.f,Ne=j.f,ze=De.f,Pe=y.Symbol,Le=y.JSON,Re=Le&&Le.stringify,Ye=\"prototype\",We=V(\"_hidden\"),qe=V(\"toPrimitive\"),Ie={}.propertyIsEnumerable,He=$(\"symbol-registry\"),Fe=$(\"symbols\"),Be=$(\"op-symbols\"),Ge=Object[Ye],Ue=\"function\"==typeof Pe,$e=y.QObject,Ve=!$e||!$e[Ye]||!$e[Ye].findChild,Je=v&&g(function(){return 7!=ke(Ne({},\"a\",{get:function(){return Ne(this,\"a\",{value:7}).a}})).a})?function(e,t,n){var r=je(Ge,t);r&&delete Ge[t],Ne(e,t,n),r&&e!==Ge&&Ne(Ge,t,r)}:Ne,Ke=function(e){var t=Fe[e]=ke(Pe[Ye]);return t._k=e,t},Xe=Ue&&\"symbol\"==typeof Pe.iterator?function(e){return\"symbol\"==typeof e}:function(e){return e instanceof Pe},Ze=function(e,t,n){return e===Ge&&Ze(Be,t,n),D(e),t=f(t,!0),D(n),m(Fe,t)?(n.enumerable?(m(e,We)&&e[We][t]&&(e[We][t]=!1),n=ke(n,{enumerable:A(0,!1)})):(m(e,We)||Ne(e,We,A(1,{})),e[We][t]=!0),Je(e,t,n)):Ne(e,t,n)},Qe=function(e,t){D(e);for(var n,r=function(e){var t=pe(e),n=me.f;if(n)for(var r,a=n(e),i=d.f,o=0;a.length>o;)i.call(e,r=a[o++])&&t.push(r);return t}(t=c(t)),a=0,i=r.length;a<i;)Ze(e,n=r[a++],t[n]);return e},et=function(e){var t=Ie.call(this,e=f(e,!0));return!(this===Ge&&m(Fe,e)&&!m(Be,e))&&(!(t||!m(this,e)||!m(Fe,e)||m(this,We)&&this[We][e])||t)},tt=function(e,t){if(e=c(e),t=f(t,!0),e!==Ge||!m(Fe,t)||m(Be,t)){var n=je(e,t);return!n||!m(Fe,t)||m(e,We)&&e[We][t]||(n.enumerable=!0),n}},nt=function(e){for(var t,n=ze(c(e)),r=[],a=0;n.length>a;)m(Fe,t=n[a++])||t==We||t==Oe||r.push(t);return r},rt=function(e){for(var t,n=e===Ge,r=ze(n?Be:c(e)),a=[],i=0;r.length>i;)!m(Fe,t=r[i++])||n&&!m(Ge,t)||a.push(Fe[t]);return a};Ue||(H((Pe=function(){if(this instanceof Pe)throw TypeError(\"Symbol is not a constructor!\");var t=G(0<arguments.length?arguments[0]:void 0),n=function(e){this===Ge&&n.call(Be,e),m(this,We)&&m(this[We],t)&&(this[We][t]=!1),Je(this,t,A(1,e))};return v&&Ve&&Je(Ge,t,{configurable:!0,set:n}),Ke(t)})[Ye],\"toString\",function(){return this._k}),E.f=tt,j.f=Ze,Se.f=De.f=nt,d.f=et,me.f=rt,Z.f=function(e){return Ke(V(e))}),L(L.G+L.W+L.F*!Ue,{Symbol:Pe});for(var at=\"hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables\".split(\",\"),it=0;at.length>it;)V(at[it++]);for(var ot=pe(V.store),st=0;ot.length>st;)ee(ot[st++]);L(L.S+L.F*!Ue,\"Symbol\",{for:function(e){return m(He,e+=\"\")?He[e]:He[e]=Pe(e)},keyFor:function(e){if(!Xe(e))throw TypeError(e+\" is not a symbol!\");for(var t in He)if(He[t]===e)return t},useSetter:function(){Ve=!0},useSimple:function(){Ve=!1}}),L(L.S+L.F*!Ue,\"Object\",{create:function(e,t){return void 0===t?ke(e):Qe(ke(e),t)},defineProperty:Ze,defineProperties:Qe,getOwnPropertyDescriptor:tt,getOwnPropertyNames:nt,getOwnPropertySymbols:rt}),Le&&L(L.S+L.F*(!Ue||g(function(){var e=Pe();return\"[null]\"!=Re([e])||\"{}\"!=Re({a:e})||\"{}\"!=Re(Object(e))})),\"JSON\",{stringify:function(e){for(var t,n,r=[e],a=1;arguments.length>a;)r.push(arguments[a++]);if(n=t=r[1],(l(t)||void 0!==e)&&!Xe(e))return ge(t)||(t=function(e,t){if(\"function\"==typeof n&&(t=n.call(this,e,t)),!Xe(t))return t}),r[1]=t,Re.apply(Le,r)}}),Pe[Ye][qe]||N(Pe[Ye],qe,Pe[Ye].valueOf),X(Pe,\"Symbol\"),X(Math,\"Math\",!0),X(y.JSON,\"JSON\",!0);var ut=M.Object.getOwnPropertySymbols,ct=function(e){return Object(u(e))};R(\"keys\",function(){return function(e){return pe(ct(e))}});var lt=M.Object.keys;L(L.S+L.F*!v,\"Object\",{defineProperty:j.f});var ft=M.Object,ht=function(e,t,n){return ft.defineProperty(e,t,n)};var dt=function(e,t,n){return t in e?ht(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e};var pt=function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},r=lt(n);\"function\"==typeof ut&&(r=r.concat(ut(n).filter(function(e){return I(n,e).enumerable}))),r.forEach(function(e){dt(t,e,n[e])})}return t};var mt=function(e,t){if(null==e)return{};var n,r,a={},i=lt(e);for(r=0;r<i.length;r++)n=i[r],0<=t.indexOf(n)||(a[n]=e[n]);return a};var gt=function(e,t){if(null==e)return{};var n,r,a=mt(e,t);if(ut){var i=ut(e);for(r=0;r<i.length;r++)n=i[r],0<=t.indexOf(n)||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a},vt={},yt={};N(yt,V(\"iterator\"),function(){return this});var _t,bt=ce(\"IE_PROTO\"),wt=Object.prototype,At=Object.getPrototypeOf||function(e){return e=ct(e),m(e,bt)?e[bt]:\"function\"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?wt:null},xt=V(\"iterator\"),kt=!([].keys&&\"next\"in[].keys()),Et=\"values\",St=function(){return this},Mt=function(e,t,n,r,a,i,o){var s,u,c;u=t,c=r,(s=n).prototype=ke(yt,{next:A(1,c)}),X(s,u+\" Iterator\");var l,f,h,d=function(e){if(!kt&&e in v)return v[e];switch(e){case\"keys\":case Et:return function(){return new n(this,e)}}return function(){return new n(this,e)}},p=t+\" Iterator\",m=a==Et,g=!1,v=e.prototype,y=v[xt]||v[\"@@iterator\"]||a&&v[a],_=y||d(a),b=a?m?d(\"entries\"):_:void 0,w=\"Array\"==t&&v.entries||y;if(w&&(h=At(w.call(new e)))!==Object.prototype&&h.next&&X(h,p,!0),m&&y&&y.name!==Et&&(g=!0,_=function(){return y.call(this)}),o&&(kt||g||!v[xt])&&N(v,xt,_),vt[t]=_,vt[p]=St,a)if(l={values:m?_:d(Et),keys:i?_:d(\"keys\"),entries:b},o)for(f in l)f in v||H(v,f,l[f]);else L(L.P+L.F*(kt||g),t,l);return l},Tt=(_t=!0,function(e,t){var n,r,a=String(u(e)),i=re(t),o=a.length;return i<0||o<=i?_t?\"\":void 0:(n=a.charCodeAt(i))<55296||56319<n||i+1===o||(r=a.charCodeAt(i+1))<56320||57343<r?_t?a.charAt(i):n:_t?a.slice(i,i+2):r-56320+(n-55296<<10)+65536});Mt(String,\"String\",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=Tt(t,n),this._i+=e.length,{value:e,done:!1})});var Ct=function(e,t){return{value:t,done:!!e}};Mt(Array,\"Array\",function(e,t){this._t=c(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,n=this._i++;return!e||n>=e.length?(this._t=void 0,Ct(1)):Ct(0,\"keys\"==t?n:\"values\"==t?e[n]:[n,e[n]])},\"values\");vt.Arguments=vt.Array;for(var Dt=V(\"toStringTag\"),Ot=\"CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList\".split(\",\"),jt=0;jt<Ot.length;jt++){var Nt=Ot[jt],zt=y[Nt],Pt=zt&&zt.prototype;Pt&&!Pt[Dt]&&N(Pt,Dt,Nt),vt[Nt]=vt.Array}var Lt,Rt,Yt,Wt=V(\"toStringTag\"),qt=\"Arguments\"==s(function(){return arguments}()),It=function(e){var t,n,r;return void 0===e?\"Undefined\":null===e?\"Null\":\"string\"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),Wt))?n:qt?s(t):\"Object\"==(r=s(t))&&\"function\"==typeof t.callee?\"Arguments\":r},Ht=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+\": incorrect invocation!\");return e},Ft=function(t,e,n,r){try{return r?e(D(n)[0],n[1]):e(n)}catch(e){var a=t.return;throw void 0!==a&&D(a.call(t)),e}},Bt=V(\"iterator\"),Gt=Array.prototype,Ut=function(e){return void 0!==e&&(vt.Array===e||Gt[Bt]===e)},$t=V(\"iterator\"),Vt=M.getIteratorMethod=function(e){if(null!=e)return e[$t]||e[\"@@iterator\"]||vt[It(e)]},Jt=e(function(e){var h={},d={},t=e.exports=function(e,t,n,r,a){var i,o,s,u,c=a?function(){return e}:Vt(e),l=C(n,r,t?2:1),f=0;if(\"function\"!=typeof c)throw TypeError(e+\" is not iterable!\");if(Ut(c)){for(i=ie(e.length);f<i;f++)if((u=t?l(D(o=e[f])[0],o[1]):l(e[f]))===h||u===d)return u}else for(s=c.call(e);!(o=s.next()).done;)if((u=Ft(s,l,o.value,t))===h||u===d)return u};t.BREAK=h,t.RETURN=d}),Kt=V(\"species\"),Xt=function(e,t){var n,r=D(e).constructor;return void 0===r||null==(n=D(r)[Kt])?t:T(n)},Zt=y.process,Qt=y.setImmediate,en=y.clearImmediate,tn=y.MessageChannel,nn=y.Dispatch,rn=0,an={},on=\"onreadystatechange\",sn=function(){var e=+this;if(an.hasOwnProperty(e)){var t=an[e];delete an[e],t()}},un=function(e){sn.call(e.data)};Qt&&en||(Qt=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return an[++rn]=function(){!function(e,t,n){var r=void 0===n;switch(t.length){case 0:return r?e():e.call(n);case 1:return r?e(t[0]):e.call(n,t[0]);case 2:return r?e(t[0],t[1]):e.call(n,t[0],t[1]);case 3:return r?e(t[0],t[1],t[2]):e.call(n,t[0],t[1],t[2]);case 4:return r?e(t[0],t[1],t[2],t[3]):e.call(n,t[0],t[1],t[2],t[3])}e.apply(n,t)}(\"function\"==typeof e?e:Function(e),t)},Lt(rn),rn},en=function(e){delete an[e]},\"process\"==s(Zt)?Lt=function(e){Zt.nextTick(C(sn,e,1))}:nn&&nn.now?Lt=function(e){nn.now(C(sn,e,1))}:tn?(Yt=(Rt=new tn).port2,Rt.port1.onmessage=un,Lt=C(Yt.postMessage,Yt,1)):y.addEventListener&&\"function\"==typeof postMessage&&!y.importScripts?(Lt=function(e){y.postMessage(e+\"\",\"*\")},y.addEventListener(\"message\",un,!1)):Lt=on in w(\"script\")?function(e){_e.appendChild(w(\"script\"))[on]=function(){_e.removeChild(this),sn.call(e)}}:function(e){setTimeout(C(sn,e,1),0)});var cn={set:Qt,clear:en},ln=cn.set,fn=y.MutationObserver||y.WebKitMutationObserver,hn=y.process,dn=y.Promise,pn=\"process\"==s(hn);function mn(e){var n,r;this.promise=new e(function(e,t){if(void 0!==n||void 0!==r)throw TypeError(\"Bad Promise constructor\");n=e,r=t}),this.resolve=T(n),this.reject=T(r)}var gn={f:function(e){return new mn(e)}},vn=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}},yn=y.navigator,_n=yn&&yn.userAgent||\"\",bn=function(e,t){if(D(e),l(t)&&t.constructor===e)return t;var n=gn.f(e);return(0,n.resolve)(t),n.promise},wn=function(e,t,n){for(var r in t)n&&e[r]?e[r]=t[r]:N(e,r,t[r]);return e},An=V(\"species\"),xn=function(e){var t=\"function\"==typeof M[e]?M[e]:y[e];v&&t&&!t[An]&&j.f(t,An,{configurable:!0,get:function(){return this}})},kn=V(\"iterator\"),En=!1;try{[7][kn]().return=function(){En=!0}}catch(e){}var Sn,Mn,Tn,Cn,Dn=function(e,t){if(!t&&!En)return!1;var n=!1;try{var r=[7],a=r[kn]();a.next=function(){return{done:n=!0}},r[kn]=function(){return a},e(r)}catch(e){}return n},On=cn.set,jn=function(){var n,r,a,e=function(){var e,t;for(pn&&(e=hn.domain)&&e.exit();n;){t=n.fn,n=n.next;try{t()}catch(e){throw n?a():r=void 0,e}}r=void 0,e&&e.enter()};if(pn)a=function(){hn.nextTick(e)};else if(!fn||y.navigator&&y.navigator.standalone)if(dn&&dn.resolve){var t=dn.resolve(void 0);a=function(){t.then(e)}}else a=function(){ln.call(y,e)};else{var i=!0,o=document.createTextNode(\"\");new fn(e).observe(o,{characterData:!0}),a=function(){o.data=i=!i}}return function(e){var t={fn:e,next:void 0};r&&(r.next=t),n||(n=t,a()),r=t}}(),Nn=\"Promise\",zn=y.TypeError,Pn=y.process,Ln=Pn&&Pn.versions,Rn=Ln&&Ln.v8||\"\",Yn=y[Nn],Wn=\"process\"==It(Pn),qn=function(){},In=Mn=gn.f,Hn=!!function(){try{var e=Yn.resolve(1),t=(e.constructor={})[V(\"species\")]=function(e){e(qn,qn)};return(Wn||\"function\"==typeof PromiseRejectionEvent)&&e.then(qn)instanceof t&&0!==Rn.indexOf(\"6.6\")&&-1===_n.indexOf(\"Chrome/66\")}catch(e){}}(),Fn=function(e){var t;return!(!l(e)||\"function\"!=typeof(t=e.then))&&t},Bn=function(l,n){if(!l._n){l._n=!0;var r=l._c;jn(function(){for(var u=l._v,c=1==l._s,e=0,t=function(e){var t,n,r,a=c?e.ok:e.fail,i=e.resolve,o=e.reject,s=e.domain;try{a?(c||(2==l._h&&Vn(l),l._h=1),!0===a?t=u:(s&&s.enter(),t=a(u),s&&(s.exit(),r=!0)),t===e.promise?o(zn(\"Promise-chain cycle\")):(n=Fn(t))?n.call(t,i,o):i(t)):o(u)}catch(e){s&&!r&&s.exit(),o(e)}};r.length>e;)t(r[e++]);l._c=[],l._n=!1,n&&!l._h&&Gn(l)})}},Gn=function(i){On.call(y,function(){var e,t,n,r=i._v,a=Un(i);if(a&&(e=vn(function(){Wn?Pn.emit(\"unhandledRejection\",r,i):(t=y.onunhandledrejection)?t({promise:i,reason:r}):(n=y.console)&&n.error&&n.error(\"Unhandled promise rejection\",r)}),i._h=Wn||Un(i)?2:1),i._a=void 0,a&&e.e)throw e.v})},Un=function(e){return 1!==e._h&&0===(e._a||e._c).length},Vn=function(t){On.call(y,function(){var e;Wn?Pn.emit(\"rejectionHandled\",t):(e=y.onrejectionhandled)&&e({promise:t,reason:t._v})})},Jn=function(e){var t=this;t._d||(t._d=!0,(t=t._w||t)._v=e,t._s=2,t._a||(t._a=t._c.slice()),Bn(t,!0))},Kn=function(e){var n,r=this;if(!r._d){r._d=!0,r=r._w||r;try{if(r===e)throw zn(\"Promise can't be resolved itself\");(n=Fn(e))?jn(function(){var t={_w:r,_d:!1};try{n.call(e,C(Kn,t,1),C(Jn,t,1))}catch(e){Jn.call(t,e)}}):(r._v=e,r._s=1,Bn(r,!1))}catch(e){Jn.call({_w:r,_d:!1},e)}}};Hn||(Yn=function(e){Ht(this,Yn,Nn,\"_h\"),T(e),Sn.call(this);try{e(C(Kn,this,1),C(Jn,this,1))}catch(e){Jn.call(this,e)}},(Sn=function(e){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1}).prototype=wn(Yn.prototype,{then:function(e,t){var n=In(Xt(this,Yn));return n.ok=\"function\"!=typeof e||e,n.fail=\"function\"==typeof t&&t,n.domain=Wn?Pn.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&Bn(this,!1),n.promise},catch:function(e){return this.then(void 0,e)}}),Tn=function(){var e=new Sn;this.promise=e,this.resolve=C(Kn,e,1),this.reject=C(Jn,e,1)},gn.f=In=function(e){return e===Yn||e===Cn?new Tn(e):Mn(e)}),L(L.G+L.W+L.F*!Hn,{Promise:Yn}),X(Yn,Nn),xn(Nn),Cn=M[Nn],L(L.S+L.F*!Hn,Nn,{reject:function(e){var t=In(this);return(0,t.reject)(e),t.promise}}),L(L.S+!0*L.F,Nn,{resolve:function(e){return bn(this===Cn?Yn:this,e)}}),L(L.S+L.F*!(Hn&&Dn(function(e){Yn.all(e).catch(qn)})),Nn,{all:function(e){var o=this,t=In(o),s=t.resolve,u=t.reject,n=vn(function(){var r=[],a=0,i=1;Jt(e,!1,function(e){var t=a++,n=!1;r.push(void 0),i++,o.resolve(e).then(function(e){n||(n=!0,r[t]=e,--i||s(r))},u)}),--i||s(r)});return n.e&&u(n.v),t.promise},race:function(e){var t=this,n=In(t),r=n.reject,a=vn(function(){Jt(e,!1,function(e){t.resolve(e).then(n.resolve,r)})});return a.e&&r(a.v),n.promise}}),L(L.P+L.R,\"Promise\",{finally:function(t){var n=Xt(this,M.Promise||y.Promise),e=\"function\"==typeof t;return this.then(e?function(e){return bn(n,t()).then(function(){return e})}:t,e?function(e){return bn(n,t()).then(function(){throw e})}:t)}}),L(L.S,\"Promise\",{try:function(e){var t=gn.f(this),n=vn(e);return(n.e?t.reject:t.resolve)(n.v),t.promise}});var Xn=M.Promise;function Zn(e,t,n,r,a,i,o){try{var s=e[i](o),u=s.value}catch(e){return void n(e)}s.done?t(u):Xn.resolve(u).then(r,a)}var Qn=function(s){return function(){var e=this,o=arguments;return new Xn(function(t,n){var r=s.apply(e,o);function a(e){Zn(r,t,n,a,i,\"next\",e)}function i(e){Zn(r,t,n,a,i,\"throw\",e)}a(void 0)})}},er=\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},tr=e(function(O,j){!function(e){var t=j&&!j.nodeType&&j,n=O&&!O.nodeType&&O,r=\"object\"==typeof er&&er;r.global!==r&&r.window!==r&&r.self!==r||(e=r);var a,i,v=2147483647,y=36,_=1,b=26,o=38,s=700,w=72,A=128,x=\"-\",u=/^xn--/,c=/[^\\x20-\\x7E]/,l=/[\\x2E\\u3002\\uFF0E\\uFF61]/g,f={overflow:\"Overflow: input needs wider integers to process\",\"not-basic\":\"Illegal input >= 0x80 (not a basic code point)\",\"invalid-input\":\"Invalid input\"},h=y-_,k=Math.floor,E=String.fromCharCode;function S(e){throw RangeError(f[e])}function d(e,t){for(var n=e.length,r=[];n--;)r[n]=t(e[n]);return r}function p(e,t){var n=e.split(\"@\"),r=\"\";return 1<n.length&&(r=n[0]+\"@\",e=n[1]),r+d((e=e.replace(l,\".\")).split(\".\"),t).join(\".\")}function M(e){for(var t,n,r=[],a=0,i=e.length;a<i;)55296<=(t=e.charCodeAt(a++))&&t<=56319&&a<i?56320==(64512&(n=e.charCodeAt(a++)))?r.push(((1023&t)<<10)+(1023&n)+65536):(r.push(t),a--):r.push(t);return r}function T(e){return d(e,function(e){var t=\"\";return 65535<e&&(t+=E((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+=E(e)}).join(\"\")}function C(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function D(e,t,n){var r=0;for(e=n?k(e/s):e>>1,e+=k(e/t);h*b>>1<e;r+=y)e=k(e/h);return k(r+(h+1)*e/(e+o))}function m(e){var t,n,r,a,i,o,s,u,c,l,f,h=[],d=e.length,p=0,m=A,g=w;for((n=e.lastIndexOf(x))<0&&(n=0),r=0;r<n;++r)128<=e.charCodeAt(r)&&S(\"not-basic\"),h.push(e.charCodeAt(r));for(a=0<n?n+1:0;a<d;){for(i=p,o=1,s=y;d<=a&&S(\"invalid-input\"),f=e.charCodeAt(a++),(y<=(u=f-48<10?f-22:f-65<26?f-65:f-97<26?f-97:y)||u>k((v-p)/o))&&S(\"overflow\"),p+=u*o,!(u<(c=s<=g?_:g+b<=s?b:s-g));s+=y)o>k(v/(l=y-c))&&S(\"overflow\"),o*=l;g=D(p-i,t=h.length+1,0==i),k(p/t)>v-m&&S(\"overflow\"),m+=k(p/t),p%=t,h.splice(p++,0,m)}return T(h)}function g(e){var t,n,r,a,i,o,s,u,c,l,f,h,d,p,m,g=[];for(h=(e=M(e)).length,t=A,i=w,o=n=0;o<h;++o)(f=e[o])<128&&g.push(E(f));for(r=a=g.length,a&&g.push(x);r<h;){for(s=v,o=0;o<h;++o)t<=(f=e[o])&&f<s&&(s=f);for(s-t>k((v-n)/(d=r+1))&&S(\"overflow\"),n+=(s-t)*d,t=s,o=0;o<h;++o)if((f=e[o])<t&&++n>v&&S(\"overflow\"),f==t){for(u=n,c=y;!(u<(l=c<=i?_:i+b<=c?b:c-i));c+=y)m=u-l,p=y-l,g.push(E(C(l+m%p,0))),u=k(m/p);g.push(E(C(u,0))),i=D(n,d,r==a),n=0,++r}++n,++t}return g.join(\"\")}if(a={version:\"1.3.2\",ucs2:{decode:M,encode:T},decode:m,encode:g,toASCII:function(e){return p(e,function(e){return c.test(e)?\"xn--\"+g(e):e})},toUnicode:function(e){return p(e,function(e){return u.test(e)?m(e.slice(4).toLowerCase()):e})}},t&&n)if(O.exports==t)n.exports=a;else for(i in a)a.hasOwnProperty(i)&&(t[i]=a[i]);else e.punycode=a}(this)}),nr={isString:function(e){return\"string\"==typeof e},isObject:function(e){return\"object\"==typeof e&&null!==e},isNull:function(e){return null===e},isNullOrUndefined:function(e){return null==e}};var rr=function(e,t,n,r){t=t||\"&\",n=n||\"=\";var a={};if(\"string\"!=typeof e||0===e.length)return a;var i=/\\+/g;e=e.split(t);var o=1e3;r&&\"number\"==typeof r.maxKeys&&(o=r.maxKeys);var s,u,c=e.length;0<o&&o<c&&(c=o);for(var l=0;l<c;++l){var f,h,d,p,m=e[l].replace(i,\"%20\"),g=m.indexOf(n);h=0<=g?(f=m.substr(0,g),m.substr(g+1)):(f=m,\"\"),d=decodeURIComponent(f),p=decodeURIComponent(h),s=a,u=d,Object.prototype.hasOwnProperty.call(s,u)?Array.isArray(a[d])?a[d].push(p):a[d]=[a[d],p]:a[d]=p}return a},ar=function(e){switch(typeof e){case\"string\":return e;case\"boolean\":return e?\"true\":\"false\";case\"number\":return isFinite(e)?e:\"\";default:return\"\"}},ir=function(n,r,a,e){return r=r||\"&\",a=a||\"=\",null===n&&(n=void 0),\"object\"==typeof n?Object.keys(n).map(function(e){var t=encodeURIComponent(ar(e))+a;return Array.isArray(n[e])?n[e].map(function(e){return t+encodeURIComponent(ar(e))}).join(r):t+encodeURIComponent(ar(n[e]))}).join(r):e?encodeURIComponent(ar(e))+a+encodeURIComponent(ar(n)):\"\"},or=e(function(e,t){t.decode=t.parse=rr,t.encode=t.stringify=ir}),sr=(or.decode,or.parse,or.encode,or.stringify,Er),ur=function(e,t){return Er(e,!1,!0).resolve(t)},cr=function(e,t){return e?Er(e,!1,!0).resolveObject(t):t},lr=function(e){nr.isString(e)&&(e=Er(e));return e instanceof hr?e.format():hr.prototype.format.call(e)},fr=hr;function hr(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}var dr=/^([a-z0-9.+-]+:)/i,pr=/:[0-9]*$/,mr=/^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/,gr=[\"{\",\"}\",\"|\",\"\\\\\",\"^\",\"`\"].concat([\"<\",\">\",'\"',\"`\",\" \",\"\\r\",\"\\n\",\"\\t\"]),vr=[\"'\"].concat(gr),yr=[\"%\",\"/\",\"?\",\";\",\"#\"].concat(vr),_r=[\"/\",\"?\",\"#\"],br=/^[+a-z0-9A-Z_-]{0,63}$/,wr=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,Ar={javascript:!0,\"javascript:\":!0},xr={javascript:!0,\"javascript:\":!0},kr={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,\"http:\":!0,\"https:\":!0,\"ftp:\":!0,\"gopher:\":!0,\"file:\":!0};function Er(e,t,n){if(e&&nr.isObject(e)&&e instanceof hr)return e;var r=new hr;return r.parse(e,t,n),r}hr.prototype.parse=function(e,t,n){if(!nr.isString(e))throw new TypeError(\"Parameter 'url' must be a string, not \"+typeof e);var r=e.indexOf(\"?\"),a=-1!==r&&r<e.indexOf(\"#\")?\"?\":\"#\",i=e.split(a);i[0]=i[0].replace(/\\\\/g,\"/\");var o=e=i.join(a);if(o=o.trim(),!n&&1===e.split(\"#\").length){var s=mr.exec(o);if(s)return this.path=o,this.href=o,this.pathname=s[1],s[2]?(this.search=s[2],this.query=t?or.parse(this.search.substr(1)):this.search.substr(1)):t&&(this.search=\"\",this.query={}),this}var u=dr.exec(o);if(u){var c=(u=u[0]).toLowerCase();this.protocol=c,o=o.substr(u.length)}if(n||u||o.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)){var l=\"//\"===o.substr(0,2);!l||u&&xr[u]||(o=o.substr(2),this.slashes=!0)}if(!xr[u]&&(l||u&&!kr[u])){for(var f,h,d=-1,p=0;p<_r.length;p++){-1!==(m=o.indexOf(_r[p]))&&(-1===d||m<d)&&(d=m)}-1!==(h=-1===d?o.lastIndexOf(\"@\"):o.lastIndexOf(\"@\",d))&&(f=o.slice(0,h),o=o.slice(h+1),this.auth=decodeURIComponent(f)),d=-1;for(p=0;p<yr.length;p++){var m;-1!==(m=o.indexOf(yr[p]))&&(-1===d||m<d)&&(d=m)}-1===d&&(d=o.length),this.host=o.slice(0,d),o=o.slice(d),this.parseHost(),this.hostname=this.hostname||\"\";var g=\"[\"===this.hostname[0]&&\"]\"===this.hostname[this.hostname.length-1];if(!g)for(var v=this.hostname.split(/\\./),y=(p=0,v.length);p<y;p++){var _=v[p];if(_&&!_.match(br)){for(var b=\"\",w=0,A=_.length;w<A;w++)127<_.charCodeAt(w)?b+=\"x\":b+=_[w];if(!b.match(br)){var x=v.slice(0,p),k=v.slice(p+1),E=_.match(wr);E&&(x.push(E[1]),k.unshift(E[2])),k.length&&(o=\"/\"+k.join(\".\")+o),this.hostname=x.join(\".\");break}}}255<this.hostname.length?this.hostname=\"\":this.hostname=this.hostname.toLowerCase(),g||(this.hostname=tr.toASCII(this.hostname));var S=this.port?\":\"+this.port:\"\",M=this.hostname||\"\";this.host=M+S,this.href+=this.host,g&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),\"/\"!==o[0]&&(o=\"/\"+o))}if(!Ar[c])for(p=0,y=vr.length;p<y;p++){var T=vr[p];if(-1!==o.indexOf(T)){var C=encodeURIComponent(T);C===T&&(C=escape(T)),o=o.split(T).join(C)}}var D=o.indexOf(\"#\");-1!==D&&(this.hash=o.substr(D),o=o.slice(0,D));var O=o.indexOf(\"?\");if(-1!==O?(this.search=o.substr(O),this.query=o.substr(O+1),t&&(this.query=or.parse(this.query)),o=o.slice(0,O)):t&&(this.search=\"\",this.query={}),o&&(this.pathname=o),kr[c]&&this.hostname&&!this.pathname&&(this.pathname=\"/\"),this.pathname||this.search){S=this.pathname||\"\";var j=this.search||\"\";this.path=S+j}return this.href=this.format(),this},hr.prototype.format=function(){var e=this.auth||\"\";e&&(e=(e=encodeURIComponent(e)).replace(/%3A/i,\":\"),e+=\"@\");var t=this.protocol||\"\",n=this.pathname||\"\",r=this.hash||\"\",a=!1,i=\"\";this.host?a=e+this.host:this.hostname&&(a=e+(-1===this.hostname.indexOf(\":\")?this.hostname:\"[\"+this.hostname+\"]\"),this.port&&(a+=\":\"+this.port)),this.query&&nr.isObject(this.query)&&Object.keys(this.query).length&&(i=or.stringify(this.query));var o=this.search||i&&\"?\"+i||\"\";return t&&\":\"!==t.substr(-1)&&(t+=\":\"),this.slashes||(!t||kr[t])&&!1!==a?(a=\"//\"+(a||\"\"),n&&\"/\"!==n.charAt(0)&&(n=\"/\"+n)):a||(a=\"\"),r&&\"#\"!==r.charAt(0)&&(r=\"#\"+r),o&&\"?\"!==o.charAt(0)&&(o=\"?\"+o),t+a+(n=n.replace(/[?#]/g,function(e){return encodeURIComponent(e)}))+(o=o.replace(\"#\",\"%23\"))+r},hr.prototype.resolve=function(e){return this.resolveObject(Er(e,!1,!0)).format()},hr.prototype.resolveObject=function(e){if(nr.isString(e)){var t=new hr;t.parse(e,!1,!0),e=t}for(var n=new hr,r=Object.keys(this),a=0;a<r.length;a++){var i=r[a];n[i]=this[i]}if(n.hash=e.hash,\"\"===e.href)return n.href=n.format(),n;if(e.slashes&&!e.protocol){for(var o=Object.keys(e),s=0;s<o.length;s++){var u=o[s];\"protocol\"!==u&&(n[u]=e[u])}return kr[n.protocol]&&n.hostname&&!n.pathname&&(n.path=n.pathname=\"/\"),n.href=n.format(),n}if(e.protocol&&e.protocol!==n.protocol){if(!kr[e.protocol]){for(var c=Object.keys(e),l=0;l<c.length;l++){var f=c[l];n[f]=e[f]}return n.href=n.format(),n}if(n.protocol=e.protocol,e.host||xr[e.protocol])n.pathname=e.pathname;else{for(var h=(e.pathname||\"\").split(\"/\");h.length&&!(e.host=h.shift()););e.host||(e.host=\"\"),e.hostname||(e.hostname=\"\"),\"\"!==h[0]&&h.unshift(\"\"),h.length<2&&h.unshift(\"\"),n.pathname=h.join(\"/\")}if(n.search=e.search,n.query=e.query,n.host=e.host||\"\",n.auth=e.auth,n.hostname=e.hostname||e.host,n.port=e.port,n.pathname||n.search){var d=n.pathname||\"\",p=n.search||\"\";n.path=d+p}return n.slashes=n.slashes||e.slashes,n.href=n.format(),n}var m=n.pathname&&\"/\"===n.pathname.charAt(0),g=e.host||e.pathname&&\"/\"===e.pathname.charAt(0),v=g||m||n.host&&e.pathname,y=v,_=n.pathname&&n.pathname.split(\"/\")||[],b=(h=e.pathname&&e.pathname.split(\"/\")||[],n.protocol&&!kr[n.protocol]);if(b&&(n.hostname=\"\",n.port=null,n.host&&(\"\"===_[0]?_[0]=n.host:_.unshift(n.host)),n.host=\"\",e.protocol&&(e.hostname=null,e.port=null,e.host&&(\"\"===h[0]?h[0]=e.host:h.unshift(e.host)),e.host=null),v=v&&(\"\"===h[0]||\"\"===_[0])),g)n.host=e.host||\"\"===e.host?e.host:n.host,n.hostname=e.hostname||\"\"===e.hostname?e.hostname:n.hostname,n.search=e.search,n.query=e.query,_=h;else if(h.length)_||(_=[]),_.pop(),_=_.concat(h),n.search=e.search,n.query=e.query;else if(!nr.isNullOrUndefined(e.search)){if(b)n.hostname=n.host=_.shift(),(E=!!(n.host&&0<n.host.indexOf(\"@\"))&&n.host.split(\"@\"))&&(n.auth=E.shift(),n.host=n.hostname=E.shift());return n.search=e.search,n.query=e.query,nr.isNull(n.pathname)&&nr.isNull(n.search)||(n.path=(n.pathname?n.pathname:\"\")+(n.search?n.search:\"\")),n.href=n.format(),n}if(!_.length)return n.pathname=null,n.search?n.path=\"/\"+n.search:n.path=null,n.href=n.format(),n;for(var w=_.slice(-1)[0],A=(n.host||e.host||1<_.length)&&(\".\"===w||\"..\"===w)||\"\"===w,x=0,k=_.length;0<=k;k--)\".\"===(w=_[k])?_.splice(k,1):\"..\"===w?(_.splice(k,1),x++):x&&(_.splice(k,1),x--);if(!v&&!y)for(;x--;x)_.unshift(\"..\");!v||\"\"===_[0]||_[0]&&\"/\"===_[0].charAt(0)||_.unshift(\"\"),A&&\"/\"!==_.join(\"/\").substr(-1)&&_.push(\"\");var E,S=\"\"===_[0]||_[0]&&\"/\"===_[0].charAt(0);b&&(n.hostname=n.host=S?\"\":_.length?_.shift():\"\",(E=!!(n.host&&0<n.host.indexOf(\"@\"))&&n.host.split(\"@\"))&&(n.auth=E.shift(),n.host=n.hostname=E.shift()));return(v=v||n.host&&_.length)&&!S&&_.unshift(\"\"),_.length?n.pathname=_.join(\"/\"):(n.pathname=null,n.path=null),nr.isNull(n.pathname)&&nr.isNull(n.search)||(n.path=(n.pathname?n.pathname:\"\")+(n.search?n.search:\"\")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},hr.prototype.parseHost=function(){var e=this.host,t=pr.exec(e);t&&(\":\"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)};var Sr,Mr={parse:sr,resolve:ur,resolveObject:cr,format:lr,Url:fr},Tr=e(function(e){var t,n;t=\"undefined\"!=typeof window?window:this,n=function(x,e){var t=[],k=x.document,r=Object.getPrototypeOf,s=t.slice,m=t.concat,u=t.push,a=t.indexOf,n={},i=n.toString,g=n.hasOwnProperty,o=g.toString,c=o.call(Object),v={},y=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},_=function(e){return null!=e&&e===e.window},l={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,a,i=(n=n||k).createElement(\"script\");if(i.text=e,t)for(r in l)(a=t[r]||t.getAttribute&&t.getAttribute(r))&&i.setAttribute(r,a);n.head.appendChild(i).parentNode.removeChild(i)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[i.call(e)]||\"object\":typeof e}var E=function(e,t){return new E.fn.init(e,t)},f=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;function h(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!y(e)&&!_(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}E.fn=E.prototype={jquery:\"3.4.1\",constructor:E,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=E.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return E.each(this,e)},map:function(n){return this.pushStack(E.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},E.extend=E.fn.extend=function(){var e,t,n,r,a,i,o=arguments[0]||{},s=1,u=arguments.length,c=!1;for(\"boolean\"==typeof o&&(c=o,o=arguments[s]||{},s++),\"object\"==typeof o||y(o)||(o={}),s===u&&(o=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&o!==r&&(c&&r&&(E.isPlainObject(r)||(a=Array.isArray(r)))?(n=o[t],i=a&&!Array.isArray(n)?[]:a||E.isPlainObject(n)?n:{},a=!1,o[t]=E.extend(c,i,r)):void 0!==r&&(o[t]=r));return o},E.extend({expando:\"jQuery\"+(\"3.4.1\"+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==i.call(e)||(t=r(e))&&(\"function\"!=typeof(n=g.call(t,\"constructor\")&&t.constructor)||o.call(n)!==c))},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(h(e))for(n=e.length;r<n&&!1!==t.call(e[r],r,e[r]);r++);else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(f,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(h(Object(e))?E.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:a.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,a=e.length;r<n;r++)e[a++]=t[r];return e.length=a,e},grep:function(e,t,n){for(var r=[],a=0,i=e.length,o=!n;a<i;a++)!t(e[a],a)!==o&&r.push(e[a]);return r},map:function(e,t,n){var r,a,i=0,o=[];if(h(e))for(r=e.length;i<r;i++)null!=(a=t(e[i],i,n))&&o.push(a);else for(i in e)null!=(a=t(e[i],i,n))&&o.push(a);return m.apply([],o)},guid:1,support:v}),\"function\"==typeof Symbol&&(E.fn[Symbol.iterator]=t[Symbol.iterator]),E.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var d=function(n){var e,d,b,i,a,p,f,m,w,u,c,A,x,o,k,g,s,l,v,E=\"sizzle\"+1*new Date,y=n.document,S=0,r=0,h=ue(),_=ue(),M=ue(),T=ue(),C=function(e,t){return e===t&&(c=!0),0},D={}.hasOwnProperty,t=[],O=t.pop,j=t.push,N=t.push,z=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},L=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",R=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",Y=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",W=\"\\\\[\"+R+\"*(\"+Y+\")(?:\"+R+\"*([*^$|!~]?=)\"+R+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+Y+\"))|)\"+R+\"*\\\\]\",q=\":(\"+Y+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",I=new RegExp(R+\"+\",\"g\"),H=new RegExp(\"^\"+R+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+R+\"+$\",\"g\"),F=new RegExp(\"^\"+R+\"*,\"+R+\"*\"),B=new RegExp(\"^\"+R+\"*([>+~]|\"+R+\")\"+R+\"*\"),G=new RegExp(R+\"|>\"),U=new RegExp(q),$=new RegExp(\"^\"+Y+\"$\"),V={ID:new RegExp(\"^#(\"+Y+\")\"),CLASS:new RegExp(\"^\\\\.(\"+Y+\")\"),TAG:new RegExp(\"^(\"+Y+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+q),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+R+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+R+\"*(?:([+-]|)\"+R+\"*(\\\\d+)|))\"+R+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+L+\")$\",\"i\"),needsContext:new RegExp(\"^\"+R+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+R+\"*((?:-\\\\d)?\\\\d*)\"+R+\"*\\\\)|)(?=[^-]|$)\",\"i\")},J=/HTML$/i,K=/^(?:input|select|textarea|button)$/i,X=/^h\\d$/i,Z=/^[^{]+\\{\\s*\\[native \\w/,Q=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+R+\"?|(\"+R+\")|.)\",\"ig\"),ne=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ae=function(e,t){return t?\"\\0\"===e?\"�\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},ie=function(){A()},oe=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{N.apply(t=z.call(y.childNodes),y.childNodes),t[y.childNodes.length].nodeType}catch(e){N={apply:t.length?function(e,t){j.apply(e,z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function se(e,t,n,r){var a,i,o,s,u,c,l,f=t&&t.ownerDocument,h=t?t.nodeType:9;if(n=n||[],\"string\"!=typeof e||!e||1!==h&&9!==h&&11!==h)return n;if(!r&&((t?t.ownerDocument||t:y)!==x&&A(t),t=t||x,k)){if(11!==h&&(u=Q.exec(e)))if(a=u[1]){if(9===h){if(!(o=t.getElementById(a)))return n;if(o.id===a)return n.push(o),n}else if(f&&(o=f.getElementById(a))&&v(t,o)&&o.id===a)return n.push(o),n}else{if(u[2])return N.apply(n,t.getElementsByTagName(e)),n;if((a=u[3])&&d.getElementsByClassName&&t.getElementsByClassName)return N.apply(n,t.getElementsByClassName(a)),n}if(d.qsa&&!T[e+\" \"]&&(!g||!g.test(e))&&(1!==h||\"object\"!==t.nodeName.toLowerCase())){if(l=e,f=t,1===h&&G.test(e)){for((s=t.getAttribute(\"id\"))?s=s.replace(re,ae):t.setAttribute(\"id\",s=E),i=(c=p(e)).length;i--;)c[i]=\"#\"+s+\" \"+_e(c[i]);l=c.join(\",\"),f=ee.test(e)&&ve(t.parentNode)||t}try{return N.apply(n,f.querySelectorAll(l)),n}catch(t){T(e,!0)}finally{s===E&&t.removeAttribute(\"id\")}}}return m(e.replace(H,\"$1\"),t,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function ce(e){return e[E]=!0,e}function le(e){var t=x.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split(\"|\"),r=n.length;r--;)b.attrHandle[n[r]]=t}function he(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function pe(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function me(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&oe(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ge(o){return ce(function(i){return i=+i,ce(function(e,t){for(var n,r=o([],e.length,i),a=r.length;a--;)e[n=r[a]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&void 0!==e.getElementsByTagName&&e}for(e in d=se.support={},a=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!J.test(t||n&&n.nodeName||\"HTML\")},A=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:y;return r!==x&&9===r.nodeType&&r.documentElement&&(o=(x=r).documentElement,k=!a(x),y!==x&&(n=x.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",ie,!1):n.attachEvent&&n.attachEvent(\"onunload\",ie)),d.attributes=le(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=le(function(e){return e.appendChild(x.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=Z.test(x.getElementsByClassName),d.getById=le(function(e){return o.appendChild(e).id=E,!x.getElementsByName||!x.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(void 0!==t.getElementById&&k){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=void 0!==e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(void 0!==t.getElementById&&k){var n,r,a,i=t.getElementById(e);if(i){if((n=i.getAttributeNode(\"id\"))&&n.value===e)return[i];for(a=t.getElementsByName(e),r=0;i=a[r++];)if((n=i.getAttributeNode(\"id\"))&&n.value===e)return[i]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],a=0,i=t.getElementsByTagName(e);if(\"*\"!==e)return i;for(;n=i[a++];)1===n.nodeType&&r.push(n);return r},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&k)return t.getElementsByClassName(e)},s=[],g=[],(d.qsa=Z.test(x.querySelectorAll))&&(le(function(e){o.appendChild(e).innerHTML=\"<a id='\"+E+\"'></a><select id='\"+E+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&g.push(\"[*^$]=\"+R+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||g.push(\"\\\\[\"+R+\"*(?:value|\"+L+\")\"),e.querySelectorAll(\"[id~=\"+E+\"-]\").length||g.push(\"~=\"),e.querySelectorAll(\":checked\").length||g.push(\":checked\"),e.querySelectorAll(\"a#\"+E+\"+*\").length||g.push(\".#.+[+~]\")}),le(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=x.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&g.push(\"name\"+R+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&g.push(\":enabled\",\":disabled\"),o.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&g.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),g.push(\",.*:\")})),(d.matchesSelector=Z.test(l=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&le(function(e){d.disconnectedMatch=l.call(e,\"*\"),l.call(e,\"[s!='']:x\"),s.push(\"!=\",q)}),g=g.length&&new RegExp(g.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=Z.test(o.compareDocumentPosition),v=t||Z.test(o.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},C=t?function(e,t){if(e===t)return c=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===x||e.ownerDocument===y&&v(y,e)?-1:t===x||t.ownerDocument===y&&v(y,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return c=!0,0;var n,r=0,a=e.parentNode,i=t.parentNode,o=[e],s=[t];if(!a||!i)return e===x?-1:t===x?1:a?-1:i?1:u?P(u,e)-P(u,t):0;if(a===i)return he(e,t);for(n=e;n=n.parentNode;)o.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;o[r]===s[r];)r++;return r?he(o[r],s[r]):o[r]===y?-1:s[r]===y?1:0}),x},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==x&&A(e),d.matchesSelector&&k&&!T[t+\" \"]&&(!s||!s.test(t))&&(!g||!g.test(t)))try{var n=l.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){T(t,!0)}return 0<se(t,x,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==x&&A(e),v(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==x&&A(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!k):void 0;return void 0!==r?r:d.attributes||!k?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ae)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,a=0;if(c=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(C),c){for(;t=e[a++];)t===e[a]&&(r=n.push(a));for(;r--;)e.splice(n[r],1)}return u=null,e},i=se.getText=function(e){var t,n=\"\",r=0,a=e.nodeType;if(a){if(1===a||9===a||11===a){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===a||4===a)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},(b=se.selectors={cacheLength:50,createPseudo:ce,match:V,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&U.test(n)&&(t=p(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=h[e+\" \"];return t||(t=new RegExp(\"(^|\"+R+\")\"+e+\"(\"+R+\"|$)\"))&&h(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,a){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===a:\"!=\"===r?t!==a:\"^=\"===r?a&&0===t.indexOf(a):\"*=\"===r?a&&-1<t.indexOf(a):\"$=\"===r?a&&t.slice(-a.length)===a:\"~=\"===r?-1<(\" \"+t.replace(I,\" \")+\" \").indexOf(a):\"|=\"===r&&(t===a||t.slice(0,a.length+1)===a+\"-\"))}},CHILD:function(p,e,t,m,g){var v=\"nth\"!==p.slice(0,3),y=\"last\"!==p.slice(-4),_=\"of-type\"===e;return 1===m&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,a,i,o,s,u,c=v!==y?\"nextSibling\":\"previousSibling\",l=e.parentNode,f=_&&e.nodeName.toLowerCase(),h=!n&&!_,d=!1;if(l){if(v){for(;c;){for(o=e;o=o[c];)if(_?o.nodeName.toLowerCase()===f:1===o.nodeType)return!1;u=c=\"only\"===p&&!u&&\"nextSibling\"}return!0}if(u=[y?l.firstChild:l.lastChild],y&&h){for(d=(s=(r=(a=(i=(o=l)[E]||(o[E]={}))[o.uniqueID]||(i[o.uniqueID]={}))[p]||[])[0]===S&&r[1])&&r[2],o=s&&l.childNodes[s];o=++s&&o&&o[c]||(d=s=0)||u.pop();)if(1===o.nodeType&&++d&&o===e){a[p]=[S,s,d];break}}else if(h&&(d=s=(r=(a=(i=(o=e)[E]||(o[E]={}))[o.uniqueID]||(i[o.uniqueID]={}))[p]||[])[0]===S&&r[1]),!1===d)for(;(o=++s&&o&&o[c]||(d=s=0)||u.pop())&&((_?o.nodeName.toLowerCase()!==f:1!==o.nodeType)||!++d||(h&&((a=(i=o[E]||(o[E]={}))[o.uniqueID]||(i[o.uniqueID]={}))[p]=[S,d]),o!==e)););return(d-=g)===m||d%m==0&&0<=d/m}}},PSEUDO:function(e,i){var t,o=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return o[E]?o(i):1<o.length?(t=[e,e,\"\",i],b.setFilters.hasOwnProperty(e.toLowerCase())?ce(function(e,t){for(var n,r=o(e,i),a=r.length;a--;)e[n=P(e,r[a])]=!(t[n]=r[a])}):function(e){return o(e,0,t)}):o}},pseudos:{not:ce(function(e){var r=[],a=[],s=f(e.replace(H,\"$1\"));return s[E]?ce(function(e,t,n,r){for(var a,i=s(e,null,r,[]),o=e.length;o--;)(a=i[o])&&(e[o]=!(t[o]=a))}):function(e,t,n){return r[0]=e,s(r,null,n,a),r[0]=null,!a.pop()}}),has:ce(function(t){return function(e){return 0<se(t,e).length}}),contains:ce(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||i(e)).indexOf(t)}}),lang:ce(function(n){return $.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=k?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===o},focus:function(e){return e===x.activeElement&&(!x.hasFocus||x.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:me(!1),disabled:me(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return X.test(e.nodeName)},input:function(e){return K.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ge(function(){return[0]}),last:ge(function(e,t){return[t-1]}),eq:ge(function(e,t,n){return[n<0?n+t:n]}),even:ge(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ge(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ge(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ge(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=pe(e);function ye(){}function _e(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,c=e.next,l=c||u,f=t&&\"parentNode\"===l,h=r++;return e.first?function(e,t,n){for(;e=e[u];)if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,a,i,o=[S,h];if(n){for(;e=e[u];)if((1===e.nodeType||f)&&s(e,t,n))return!0}else for(;e=e[u];)if(1===e.nodeType||f)if(a=(i=e[E]||(e[E]={}))[e.uniqueID]||(i[e.uniqueID]={}),c&&c===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=a[l])&&r[0]===S&&r[1]===h)return o[2]=r[2];if((a[l]=o)[2]=s(e,t,n))return!0}return!1}}function we(a){return 1<a.length?function(e,t,n){for(var r=a.length;r--;)if(!a[r](e,t,n))return!1;return!0}:a[0]}function Ae(e,t,n,r,a){for(var i,o=[],s=0,u=e.length,c=null!=t;s<u;s++)(i=e[s])&&(n&&!n(i,r,a)||(o.push(i),c&&t.push(s)));return o}function xe(d,p,m,g,v,e){return g&&!g[E]&&(g=xe(g)),v&&!v[E]&&(v=xe(v,e)),ce(function(e,t,n,r){var a,i,o,s=[],u=[],c=t.length,l=e||function(e,t,n){for(var r=0,a=t.length;r<a;r++)se(e,t[r],n);return n}(p||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&p?l:Ae(l,s,d,n,r),h=m?v||(e?d:c||g)?[]:t:f;if(m&&m(f,h,n,r),g)for(a=Ae(h,u),g(a,[],n,r),i=a.length;i--;)(o=a[i])&&(h[u[i]]=!(f[u[i]]=o));if(e){if(v||d){if(v){for(a=[],i=h.length;i--;)(o=h[i])&&a.push(f[i]=o);v(null,h=[],a,r)}for(i=h.length;i--;)(o=h[i])&&-1<(a=v?P(e,o):s[i])&&(e[a]=!(t[a]=o))}}else h=Ae(h===t?h.splice(c,h.length):h),v?v(null,t,h,r):N.apply(t,h)})}function ke(e){for(var a,t,n,r=e.length,i=b.relative[e[0].type],o=i||b.relative[\" \"],s=i?1:0,u=be(function(e){return e===a},o,!0),c=be(function(e){return-1<P(a,e)},o,!0),l=[function(e,t,n){var r=!i&&(n||t!==w)||((a=t).nodeType?u(e,t,n):c(e,t,n));return a=null,r}];s<r;s++)if(t=b.relative[e[s].type])l=[be(we(l),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[E]){for(n=++s;n<r&&!b.relative[e[n].type];n++);return xe(1<s&&we(l),1<s&&_e(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(H,\"$1\"),t,s<n&&ke(e.slice(s,n)),n<r&&ke(e=e.slice(n)),n<r&&_e(e))}l.push(t)}return we(l)}return ye.prototype=b.filters=b.pseudos,b.setFilters=new ye,p=se.tokenize=function(e,t){var n,r,a,i,o,s,u,c=_[e+\" \"];if(c)return t?0:c.slice(0);for(o=e,s=[],u=b.preFilter;o;){for(i in n&&!(r=F.exec(o))||(r&&(o=o.slice(r[0].length)||o),s.push(a=[])),n=!1,(r=B.exec(o))&&(n=r.shift(),a.push({value:n,type:r[0].replace(H,\" \")}),o=o.slice(n.length)),b.filter)!(r=V[i].exec(o))||u[i]&&!(r=u[i](r))||(n=r.shift(),a.push({value:n,type:i,matches:r}),o=o.slice(n.length));if(!n)break}return t?o.length:o?se.error(e):_(e,s).slice(0)},f=se.compile=function(e,t){var n,g,v,y,_,r,a=[],i=[],o=M[e+\" \"];if(!o){for(t||(t=p(e)),n=t.length;n--;)(o=ke(t[n]))[E]?a.push(o):i.push(o);(o=M(e,(g=i,y=0<(v=a).length,_=0<g.length,r=function(e,t,n,r,a){var i,o,s,u=0,c=\"0\",l=e&&[],f=[],h=w,d=e||_&&b.find.TAG(\"*\",a),p=S+=null==h?1:Math.random()||.1,m=d.length;for(a&&(w=t===x||t||a);c!==m&&null!=(i=d[c]);c++){if(_&&i){for(o=0,t||i.ownerDocument===x||(A(i),n=!k);s=g[o++];)if(s(i,t||x,n)){r.push(i);break}a&&(S=p)}y&&((i=!s&&i)&&u--,e&&l.push(i))}if(u+=c,y&&c!==u){for(o=0;s=v[o++];)s(l,f,t,n);if(e){if(0<u)for(;c--;)l[c]||f[c]||(f[c]=O.call(r));f=Ae(f)}N.apply(r,f),a&&!e&&0<f.length&&1<u+v.length&&se.uniqueSort(r)}return a&&(S=p,w=h),l},y?ce(r):r))).selector=e}return o},m=se.select=function(e,t,n,r){var a,i,o,s,u,c=\"function\"==typeof e&&e,l=!r&&p(e=c.selector||e);if(n=n||[],1===l.length){if(2<(i=l[0]=l[0].slice(0)).length&&\"ID\"===(o=i[0]).type&&9===t.nodeType&&k&&b.relative[i[1].type]){if(!(t=(b.find.ID(o.matches[0].replace(te,ne),t)||[])[0]))return n;c&&(t=t.parentNode),e=e.slice(i.shift().value.length)}for(a=V.needsContext.test(e)?0:i.length;a--&&(o=i[a],!b.relative[s=o.type]);)if((u=b.find[s])&&(r=u(o.matches[0].replace(te,ne),ee.test(i[0].type)&&ve(t.parentNode)||t))){if(i.splice(a,1),!(e=r.length&&_e(i)))return N.apply(n,r),n;break}}return(c||f(e,l))(r,t,!k,n,!t||ee.test(e)&&ve(t.parentNode)||t),n},d.sortStable=E.split(\"\").sort(C).join(\"\")===E,d.detectDuplicates=!!c,A(),d.sortDetached=le(function(e){return 1&e.compareDocumentPosition(x.createElement(\"fieldset\"))}),le(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&le(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),le(function(e){return null==e.getAttribute(\"disabled\")})||fe(L,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(x);E.find=d,E.expr=d.selectors,E.expr[\":\"]=E.expr.pseudos,E.uniqueSort=E.unique=d.uniqueSort,E.text=d.getText,E.isXMLDoc=d.isXML,E.contains=d.contains,E.escapeSelector=d.escape;var p=function(e,t,n){for(var r=[],a=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(a&&E(e).is(n))break;r.push(e)}return r},A=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},S=E.expr.match.needsContext;function M(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var T=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function C(e,n,r){return y(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?E.grep(e,function(e){return-1<a.call(n,e)!==r}):E.filter(n,e,r)}E.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?E.find.matchesSelector(r,e)?[r]:[]:E.find.matches(e,E.grep(t,function(e){return 1===e.nodeType}))},E.fn.extend({find:function(e){var t,n,r=this.length,a=this;if(\"string\"!=typeof e)return this.pushStack(E(e).filter(function(){for(t=0;t<r;t++)if(E.contains(a[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)E.find(e,a[t],n);return 1<r?E.uniqueSort(n):n},filter:function(e){return this.pushStack(C(this,e||[],!1))},not:function(e){return this.pushStack(C(this,e||[],!0))},is:function(e){return!!C(this,\"string\"==typeof e&&S.test(e)?E(e):e||[],!1).length}});var D,O=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(E.fn.init=function(e,t,n){var r,a;if(!e)return this;if(n=n||D,\"string\"!=typeof e)return e.nodeType?(this[0]=e,this.length=1,this):y(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this);if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:O.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:k,!0)),T.test(r[1])&&E.isPlainObject(t))for(r in t)y(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(a=k.getElementById(r[2]))&&(this[0]=a,this.length=1),this}).prototype=E.fn,D=E(k);var j=/^(?:parents|prev(?:Until|All))/,N={children:!0,contents:!0,next:!0,prev:!0};function z(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(E.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,a=this.length,i=[],o=\"string\"!=typeof e&&E(e);if(!S.test(e))for(;r<a;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(o?-1<o.index(n):1===n.nodeType&&E.find.matchesSelector(n,e))){i.push(n);break}return this.pushStack(1<i.length?E.uniqueSort(i):i)},index:function(e){return e?\"string\"==typeof e?a.call(E(e),this[0]):a.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(E.uniqueSort(E.merge(this.get(),E(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),E.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return p(e,\"parentNode\")},parentsUntil:function(e,t,n){return p(e,\"parentNode\",n)},next:function(e){return z(e,\"nextSibling\")},prev:function(e){return z(e,\"previousSibling\")},nextAll:function(e){return p(e,\"nextSibling\")},prevAll:function(e){return p(e,\"previousSibling\")},nextUntil:function(e,t,n){return p(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return p(e,\"previousSibling\",n)},siblings:function(e){return A((e.parentNode||{}).firstChild,e)},children:function(e){return A(e.firstChild)},contents:function(e){return void 0!==e.contentDocument?e.contentDocument:(M(e,\"template\")&&(e=e.content||e),E.merge([],e.childNodes))}},function(r,a){E.fn[r]=function(e,t){var n=E.map(this,a,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=E.filter(t,n)),1<this.length&&(N[r]||E.uniqueSort(n),j.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\\x20\\t\\r\\n\\f]+/g;function L(e){return e}function R(e){throw e}function Y(e,t,n,r){var a;try{e&&y(a=e.promise)?a.call(e).done(t).fail(n):e&&y(a=e.then)?a.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}E.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},E.each(e.match(P)||[],function(e,t){n[t]=!0}),n):E.extend({},r);var a,t,i,o,s=[],u=[],c=-1,l=function(){for(o=o||r.once,i=a=!0;u.length;c=-1)for(t=u.shift();++c<s.length;)!1===s[c].apply(t[0],t[1])&&r.stopOnFalse&&(c=s.length,t=!1);r.memory||(t=!1),a=!1,o&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!a&&(c=s.length-1,u.push(t)),function n(e){E.each(e,function(e,t){y(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!a&&l()),this},remove:function(){return E.each(arguments,function(e,t){for(var n;-1<(n=E.inArray(t,s,n));)s.splice(n,1),n<=c&&c--}),this},has:function(e){return e?-1<E.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return o=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return o=u=[],t||a||(s=t=\"\"),this},locked:function(){return!!o},fireWith:function(e,t){return o||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),a||l()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!i}};return f},E.extend({Deferred:function(e){var i=[[\"notify\",\"progress\",E.Callbacks(\"memory\"),E.Callbacks(\"memory\"),2],[\"resolve\",\"done\",E.Callbacks(\"once memory\"),E.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",E.Callbacks(\"once memory\"),E.Callbacks(\"once memory\"),1,\"rejected\"]],a=\"pending\",o={state:function(){return a},always:function(){return s.done(arguments).fail(arguments),this},catch:function(e){return o.then(null,e)},pipe:function(){var a=arguments;return E.Deferred(function(r){E.each(i,function(e,t){var n=y(a[t[4]])&&a[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&y(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),a=null}).promise()},then:function(t,n,r){var u=0;function c(a,i,o,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(a<u)){if((e=o.apply(n,r))===i.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,y(t)?s?t.call(e,c(u,i,L,s),c(u,i,R,s)):(u++,t.call(e,c(u,i,L,s),c(u,i,R,s),c(u,i,L,i.notifyWith))):(o!==L&&(n=void 0,r=[e]),(s||i.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){E.Deferred.exceptionHook&&E.Deferred.exceptionHook(e,t.stackTrace),u<=a+1&&(o!==R&&(n=void 0,r=[e]),i.rejectWith(n,r))}};a?t():(E.Deferred.getStackHook&&(t.stackTrace=E.Deferred.getStackHook()),x.setTimeout(t))}}return E.Deferred(function(e){i[0][3].add(c(0,e,y(r)?r:L,e.notifyWith)),i[1][3].add(c(0,e,y(t)?t:L)),i[2][3].add(c(0,e,y(n)?n:R))}).promise()},promise:function(e){return null!=e?E.extend(e,o):o}},s={};return E.each(i,function(e,t){var n=t[2],r=t[5];o[t[1]]=n.add,r&&n.add(function(){a=r},i[3-e][2].disable,i[3-e][3].disable,i[0][2].lock,i[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),o.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),a=s.call(arguments),i=E.Deferred(),o=function(t){return function(e){r[t]=this,a[t]=1<arguments.length?s.call(arguments):e,--n||i.resolveWith(r,a)}};if(n<=1&&(Y(e,i.done(o(t)).resolve,i.reject,!n),\"pending\"===i.state()||y(a[t]&&a[t].then)))return i.then();for(;t--;)Y(a[t],o(t),i.reject);return i.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;E.Deferred.exceptionHook=function(e,t){x.console&&x.console.warn&&e&&W.test(e.name)&&x.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},E.readyException=function(e){x.setTimeout(function(){throw e})};var q=E.Deferred();function I(){k.removeEventListener(\"DOMContentLoaded\",I),x.removeEventListener(\"load\",I),E.ready()}E.fn.ready=function(e){return q.then(e).catch(function(e){E.readyException(e)}),this},E.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--E.readyWait:E.isReady)||(E.isReady=!0)!==e&&0<--E.readyWait||q.resolveWith(k,[E])}}),E.ready.then=q.then,\"complete\"===k.readyState||\"loading\"!==k.readyState&&!k.documentElement.doScroll?x.setTimeout(E.ready):(k.addEventListener(\"DOMContentLoaded\",I),x.addEventListener(\"load\",I));var H=function(e,t,n,r,a,i,o){var s=0,u=e.length,c=null==n;if(\"object\"===w(n))for(s in a=!0,n)H(e,t,s,n[s],!0,i,o);else if(void 0!==r&&(a=!0,y(r)||(o=!0),c&&(t=o?(t.call(e,r),null):(c=t,function(e,t,n){return c.call(E(e),n)})),t))for(;s<u;s++)t(e[s],n,o?r:r.call(e[s],s,t(e[s],n)));return a?e:c?t.call(e):u?t(e[0],n):i},F=/^-ms-/,B=/-([a-z])/g;function G(e,t){return t.toUpperCase()}function U(e){return e.replace(F,\"ms-\").replace(B,G)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function V(){this.expando=E.expando+V.uid++}V.uid=1,V.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,a=this.cache(e);if(\"string\"==typeof t)a[U(t)]=n;else for(r in t)a[U(r)]=t[r];return a},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][U(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(U):(t=U(t))in r?[t]:t.match(P)||[]).length;for(;n--;)delete r[t[n]]}(void 0===t||E.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!E.isEmptyObject(t)}};var J=new V,K=new V,X=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function Q(e,t,n){var r,a;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(Z,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(a=n)||\"false\"!==a&&(\"null\"===a?null:a===+a+\"\"?+a:X.test(a)?JSON.parse(a):a)}catch(e){}K.set(e,t,n)}else n=void 0;return n}E.extend({hasData:function(e){return K.hasData(e)||J.hasData(e)},data:function(e,t,n){return K.access(e,t,n)},removeData:function(e,t){K.remove(e,t)},_data:function(e,t,n){return J.access(e,t,n)},_removeData:function(e,t){J.remove(e,t)}}),E.fn.extend({data:function(n,e){var t,r,a,i=this[0],o=i&&i.attributes;if(void 0!==n)return\"object\"==typeof n?this.each(function(){K.set(this,n)}):H(this,function(e){var t;if(i&&void 0===e)return void 0!==(t=K.get(i,n))?t:void 0!==(t=Q(i,n))?t:void 0;this.each(function(){K.set(this,n,e)})},null,e,1<arguments.length,null,!0);if(this.length&&(a=K.get(i),1===i.nodeType&&!J.get(i,\"hasDataAttrs\"))){for(t=o.length;t--;)o[t]&&0===(r=o[t].name).indexOf(\"data-\")&&(r=U(r.slice(5)),Q(i,r,a[r]));J.set(i,\"hasDataAttrs\",!0)}return a},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),E.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,E.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=E.queue(e,t),r=n.length,a=n.shift(),i=E._queueHooks(e,t);\"inprogress\"===a&&(a=n.shift(),r--),a&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete i.stop,a.call(e,function(){E.dequeue(e,t)},i)),!r&&i&&i.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return J.get(e,n)||J.access(e,n,{empty:E.Callbacks(\"once memory\").add(function(){J.remove(e,[t+\"queue\",n])})})}}),E.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?E.queue(this[0],t):void 0===n?this:this.each(function(){var e=E.queue(this,t,n);E._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&E.dequeue(this,t)})},dequeue:function(e){return this.each(function(){E.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,a=E.Deferred(),i=this,o=this.length,s=function(){--r||a.resolveWith(i,[i])};for(\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";o--;)(n=J.get(i[o],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),a.promise(t)}});var ee=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,te=new RegExp(\"^(?:([+-])=|)(\"+ee+\")([a-z%]*)$\",\"i\"),ne=[\"Top\",\"Right\",\"Bottom\",\"Left\"],re=k.documentElement,ae=function(e){return E.contains(e.ownerDocument,e)},ie={composed:!0};re.getRootNode&&(ae=function(e){return E.contains(e.ownerDocument,e)||e.getRootNode(ie)===e.ownerDocument});var oe=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&ae(e)&&\"none\"===E.css(e,\"display\")},se=function(e,t,n,r){var a,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in a=n.apply(e,r||[]),t)e.style[i]=o[i];return a};function ue(e,t,n,r){var a,i,o=20,s=r?function(){return r.cur()}:function(){return E.css(e,t,\"\")},u=s(),c=n&&n[3]||(E.cssNumber[t]?\"\":\"px\"),l=e.nodeType&&(E.cssNumber[t]||\"px\"!==c&&+u)&&te.exec(E.css(e,t));if(l&&l[3]!==c){for(u/=2,c=c||l[3],l=+u||1;o--;)E.style(e,t,l+c),(1-i)*(1-(i=s()/u||.5))<=0&&(o=0),l/=i;l*=2,E.style(e,t,l+c),n=n||[]}return n&&(l=+l||+u||0,a=n[1]?l+(n[1]+1)*n[2]:+n[2],r&&(r.unit=c,r.start=l,r.end=a)),a}var ce={};function le(e,t){for(var n,r,a,i,o,s,u,c=[],l=0,f=e.length;l<f;l++)(r=e[l]).style&&(n=r.style.display,t?(\"none\"===n&&(c[l]=J.get(r,\"display\")||null,c[l]||(r.style.display=\"\")),\"\"===r.style.display&&oe(r)&&(c[l]=(u=o=i=void 0,o=(a=r).ownerDocument,s=a.nodeName,(u=ce[s])||(i=o.body.appendChild(o.createElement(s)),u=E.css(i,\"display\"),i.parentNode.removeChild(i),\"none\"===u&&(u=\"block\"),ce[s]=u)))):\"none\"!==n&&(c[l]=\"none\",J.set(r,\"display\",n)));for(l=0;l<f;l++)null!=c[l]&&(e[l].style.display=c[l]);return e}E.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){oe(this)?E(this).show():E(this).hide()})}});var fe=/^(?:checkbox|radio)$/i,he=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,de=/^$|^module$|\\/(?:java|ecma)script/i,pe={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function me(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):void 0!==e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&M(e,t)?E.merge([e],n):n}function ge(e,t){for(var n=0,r=e.length;n<r;n++)J.set(e[n],\"globalEval\",!t||J.get(t[n],\"globalEval\"))}pe.optgroup=pe.option,pe.tbody=pe.tfoot=pe.colgroup=pe.caption=pe.thead,pe.th=pe.td;var ve,ye,_e=/<|&#?\\w+;/;function be(e,t,n,r,a){for(var i,o,s,u,c,l,f=t.createDocumentFragment(),h=[],d=0,p=e.length;d<p;d++)if((i=e[d])||0===i)if(\"object\"===w(i))E.merge(h,i.nodeType?[i]:i);else if(_e.test(i)){for(o=o||f.appendChild(t.createElement(\"div\")),s=(he.exec(i)||[\"\",\"\"])[1].toLowerCase(),u=pe[s]||pe._default,o.innerHTML=u[1]+E.htmlPrefilter(i)+u[2],l=u[0];l--;)o=o.lastChild;E.merge(h,o.childNodes),(o=f.firstChild).textContent=\"\"}else h.push(t.createTextNode(i));for(f.textContent=\"\",d=0;i=h[d++];)if(r&&-1<E.inArray(i,r))a&&a.push(i);else if(c=ae(i),o=me(f.appendChild(i),\"script\"),c&&ge(o),n)for(l=0;i=o[l++];)de.test(i.type||\"\")&&n.push(i);return f}ve=k.createDocumentFragment().appendChild(k.createElement(\"div\")),(ye=k.createElement(\"input\")).setAttribute(\"type\",\"radio\"),ye.setAttribute(\"checked\",\"checked\"),ye.setAttribute(\"name\",\"t\"),ve.appendChild(ye),v.checkClone=ve.cloneNode(!0).cloneNode(!0).lastChild.checked,ve.innerHTML=\"<textarea>x</textarea>\",v.noCloneChecked=!!ve.cloneNode(!0).lastChild.defaultValue;var we=/^key/,Ae=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,xe=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return k.activeElement}catch(e){}}()==(\"focus\"===t)}function Me(e,t,n,r,a,i){var o,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Me(e,s,n,r,t[s],i);return e}if(null==r&&null==a?(a=n,r=n=void 0):null==a&&(\"string\"==typeof n?(a=r,r=void 0):(a=r,r=n,n=void 0)),!1===a)a=Ee;else if(!a)return e;return 1===i&&(o=a,(a=function(e){return E().off(e),o.apply(this,arguments)}).guid=o.guid||(o.guid=E.guid++)),e.each(function(){E.event.add(this,t,a,r,n)})}function Te(e,a,i){i?(J.set(e,a,!1),E.event.add(e,a,{namespace:!1,handler:function(e){var t,n,r=J.get(this,a);if(1&e.isTrigger&&this[a]){if(r.length)(E.event.special[a]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),J.set(this,a,r),t=i(this,a),this[a](),r!==(n=J.get(this,a))||t?J.set(this,a,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(J.set(this,a,{value:E.event.trigger(E.extend(r[0],E.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===J.get(e,a)&&E.event.add(e,a,ke)}E.event={global:{},add:function(t,e,n,r,a){var i,o,s,u,c,l,f,h,d,p,m,g=J.get(t);if(g)for(n.handler&&(n=(i=n).handler,a=i.selector),a&&E.find.matchesSelector(re,a),n.guid||(n.guid=E.guid++),(u=g.events)||(u=g.events={}),(o=g.handle)||(o=g.handle=function(e){return void 0!==E&&E.event.triggered!==e.type?E.event.dispatch.apply(t,arguments):void 0}),c=(e=(e||\"\").match(P)||[\"\"]).length;c--;)d=m=(s=xe.exec(e[c])||[])[1],p=(s[2]||\"\").split(\".\").sort(),d&&(f=E.event.special[d]||{},d=(a?f.delegateType:f.bindType)||d,f=E.event.special[d]||{},l=E.extend({type:d,origType:m,data:r,handler:n,guid:n.guid,selector:a,needsContext:a&&E.expr.match.needsContext.test(a),namespace:p.join(\".\")},i),(h=u[d])||((h=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,p,o)||t.addEventListener&&t.addEventListener(d,o)),f.add&&(f.add.call(t,l),l.handler.guid||(l.handler.guid=n.guid)),a?h.splice(h.delegateCount++,0,l):h.push(l),E.event.global[d]=!0)},remove:function(e,t,n,r,a){var i,o,s,u,c,l,f,h,d,p,m,g=J.hasData(e)&&J.get(e);if(g&&(u=g.events)){for(c=(t=(t||\"\").match(P)||[\"\"]).length;c--;)if(d=m=(s=xe.exec(t[c])||[])[1],p=(s[2]||\"\").split(\".\").sort(),d){for(f=E.event.special[d]||{},h=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+p.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),o=i=h.length;i--;)l=h[i],!a&&m!==l.origType||n&&n.guid!==l.guid||s&&!s.test(l.namespace)||r&&r!==l.selector&&(\"**\"!==r||!l.selector)||(h.splice(i,1),l.selector&&h.delegateCount--,f.remove&&f.remove.call(e,l));o&&!h.length&&(f.teardown&&!1!==f.teardown.call(e,p,g.handle)||E.removeEvent(e,d,g.handle),delete u[d])}else for(d in u)E.event.remove(e,d+t[c],n,r,!0);E.isEmptyObject(u)&&J.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,a,i,o,s=E.event.fix(e),u=new Array(arguments.length),c=(J.get(this,\"events\")||{})[s.type]||[],l=E.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!l.preDispatch||!1!==l.preDispatch.call(this,s)){for(o=E.event.handlers.call(this,s,c),t=0;(a=o[t++])&&!s.isPropagationStopped();)for(s.currentTarget=a.elem,n=0;(i=a.handlers[n++])&&!s.isImmediatePropagationStopped();)s.rnamespace&&!1!==i.namespace&&!s.rnamespace.test(i.namespace)||(s.handleObj=i,s.data=i.data,void 0!==(r=((E.event.special[i.origType]||{}).handle||i.handler).apply(a.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,a,i,o,s=[],u=t.delegateCount,c=e.target;if(u&&c.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&(\"click\"!==e.type||!0!==c.disabled)){for(i=[],o={},n=0;n<u;n++)void 0===o[a=(r=t[n]).selector+\" \"]&&(o[a]=r.needsContext?-1<E(a,this).index(c):E.find(a,this,null,[c]).length),o[a]&&i.push(r);i.length&&s.push({elem:c,handlers:i})}return c=this,u<t.length&&s.push({elem:c,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(E.Event.prototype,t,{enumerable:!0,configurable:!0,get:y(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[E.expando]?e:new E.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return fe.test(t.type)&&t.click&&M(t,\"input\")&&Te(t,\"click\",ke),!1},trigger:function(e){var t=this||e;return fe.test(t.type)&&t.click&&M(t,\"input\")&&Te(t,\"click\"),!0},_default:function(e){var t=e.target;return fe.test(t.type)&&t.click&&M(t,\"input\")&&J.get(t,\"click\")||M(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},E.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},E.Event=function(e,t){if(!(this instanceof E.Event))return new E.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&E.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[E.expando]=!0},E.Event.prototype={constructor:E.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},E.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,char:!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&we.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ae.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},E.event.addProp),E.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){E.event.special[e]={setup:function(){return Te(this,e,Se),!1},trigger:function(){return Te(this,e),!0},delegateType:t}}),E.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,a){E.event.special[e]={delegateType:a,bindType:a,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||E.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=a),t}}}),E.fn.extend({on:function(e,t,n,r){return Me(this,e,t,n,r)},one:function(e,t,n,r){return Me(this,e,t,n,r,1)},off:function(e,t,n){var r,a;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,E(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"!=typeof e)return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){E.event.remove(this,e,n,t)});for(a in e)this.off(a,t,e[a]);return this}});var Ce=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,De=/<script|<style|<link/i,Oe=/checked\\s*(?:[^=]|=\\s*.checked.)/i,je=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Ne(e,t){return M(e,\"table\")&&M(11!==t.nodeType?t:t.firstChild,\"tr\")&&E(e).children(\"tbody\")[0]||e}function ze(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Pe(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Le(e,t){var n,r,a,i,o,s,u,c;if(1===t.nodeType){if(J.hasData(e)&&(i=J.access(e),o=J.set(t,i),c=i.events))for(a in delete o.handle,o.events={},c)for(n=0,r=c[a].length;n<r;n++)E.event.add(t,a,c[a][n]);K.hasData(e)&&(s=K.access(e),u=E.extend({},s),K.set(t,u))}}function Re(n,r,a,i){r=m.apply([],r);var e,t,o,s,u,c,l=0,f=n.length,h=f-1,d=r[0],p=y(d);if(p||1<f&&\"string\"==typeof d&&!v.checkClone&&Oe.test(d))return n.each(function(e){var t=n.eq(e);p&&(r[0]=d.call(this,e,t.html())),Re(t,r,a,i)});if(f&&(t=(e=be(r,n[0].ownerDocument,!1,n,i)).firstChild,1===e.childNodes.length&&(e=t),t||i)){for(s=(o=E.map(me(e,\"script\"),ze)).length;l<f;l++)u=e,l!==h&&(u=E.clone(u,!0,!0),s&&E.merge(o,me(u,\"script\"))),a.call(n[l],u,l);if(s)for(c=o[o.length-1].ownerDocument,E.map(o,Pe),l=0;l<s;l++)u=o[l],de.test(u.type||\"\")&&!J.access(u,\"globalEval\")&&E.contains(c,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?E._evalUrl&&!u.noModule&&E._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")}):b(u.textContent.replace(je,\"\"),u,c))}return n}function Ye(e,t,n){for(var r,a=t?E.filter(t,e):e,i=0;null!=(r=a[i]);i++)n||1!==r.nodeType||E.cleanData(me(r)),r.parentNode&&(n&&ae(r)&&ge(me(r,\"script\")),r.parentNode.removeChild(r));return e}E.extend({htmlPrefilter:function(e){return e.replace(Ce,\"<$1></$2>\")},clone:function(e,t,n){var r,a,i,o,s,u,c,l=e.cloneNode(!0),f=ae(e);if(!(v.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||E.isXMLDoc(e)))for(o=me(l),r=0,a=(i=me(e)).length;r<a;r++)s=i[r],\"input\"===(c=(u=o[r]).nodeName.toLowerCase())&&fe.test(s.type)?u.checked=s.checked:\"input\"!==c&&\"textarea\"!==c||(u.defaultValue=s.defaultValue);if(t)if(n)for(i=i||me(e),o=o||me(l),r=0,a=i.length;r<a;r++)Le(i[r],o[r]);else Le(e,l);return 0<(o=me(l,\"script\")).length&&ge(o,!f&&me(e,\"script\")),l},cleanData:function(e){for(var t,n,r,a=E.event.special,i=0;void 0!==(n=e[i]);i++)if($(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)a[r]?E.event.remove(n,r):E.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),E.fn.extend({detach:function(e){return Ye(this,e,!0)},remove:function(e){return Ye(this,e)},text:function(e){return H(this,function(e){return void 0===e?E.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Ne(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Ne(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(E.cleanData(me(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return E.clone(this,e,t)})},html:function(e){return H(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!De.test(e)&&!pe[(he.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=E.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(E.cleanData(me(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Re(this,arguments,function(e){var t=this.parentNode;E.inArray(this,n)<0&&(E.cleanData(me(this)),t&&t.replaceChild(e,this))},n)}}),E.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,o){E.fn[e]=function(e){for(var t,n=[],r=E(e),a=r.length-1,i=0;i<=a;i++)t=i===a?this:this.clone(!0),E(r[i])[o](t),u.apply(n,t.get());return this.pushStack(n)}});var We=new RegExp(\"^(\"+ee+\")(?!px)[a-z%]+$\",\"i\"),qe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=x),t.getComputedStyle(e)},Ie=new RegExp(ne.join(\"|\"),\"i\");function He(e,t,n){var r,a,i,o,s=e.style;return(n=n||qe(e))&&(\"\"!==(o=n.getPropertyValue(t)||n[t])||ae(e)||(o=E.style(e,t)),!v.pixelBoxStyles()&&We.test(o)&&Ie.test(t)&&(r=s.width,a=s.minWidth,i=s.maxWidth,s.minWidth=s.maxWidth=s.width=o,o=n.width,s.width=r,s.minWidth=a,s.maxWidth=i)),void 0!==o?o+\"\":o}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",u.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",re.appendChild(s).appendChild(u);var e=x.getComputedStyle(u);n=\"1%\"!==e.top,o=12===t(e.marginLeft),u.style.right=\"60%\",i=36===t(e.right),r=36===t(e.width),u.style.position=\"absolute\",a=12===t(u.offsetWidth/3),re.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,a,i,o,s=k.createElement(\"div\"),u=k.createElement(\"div\");u.style&&(u.style.backgroundClip=\"content-box\",u.cloneNode(!0).style.backgroundClip=\"\",v.clearCloneStyle=\"content-box\"===u.style.backgroundClip,E.extend(v,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),i},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),o},scrollboxSize:function(){return e(),a}}))}();var Be=[\"Webkit\",\"Moz\",\"ms\"],Ge=k.createElement(\"div\").style,Ue={};function $e(e){return E.cssProps[e]||Ue[e]||(e in Ge?e:Ue[e]=function(e){for(var t=e[0].toUpperCase()+e.slice(1),n=Be.length;n--;)if((e=Be[n]+t)in Ge)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Je=/^--/,Ke={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Xe={letterSpacing:\"0\",fontWeight:\"400\"};function Ze(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function Qe(e,t,n,r,a,i){var o=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;o<4;o+=2)\"margin\"===n&&(u+=E.css(e,n+ne[o],!0,a)),r?(\"content\"===n&&(u-=E.css(e,\"padding\"+ne[o],!0,a)),\"margin\"!==n&&(u-=E.css(e,\"border\"+ne[o]+\"Width\",!0,a))):(u+=E.css(e,\"padding\"+ne[o],!0,a),\"padding\"!==n?u+=E.css(e,\"border\"+ne[o]+\"Width\",!0,a):s+=E.css(e,\"border\"+ne[o]+\"Width\",!0,a));return!r&&0<=i&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-i-u-s-.5))||0),u}function et(e,t,n){var r=qe(e),a=(!v.boxSizingReliable()||n)&&\"border-box\"===E.css(e,\"boxSizing\",!1,r),i=a,o=He(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if(We.test(o)){if(!n)return o;o=\"auto\"}return(!v.boxSizingReliable()&&a||\"auto\"===o||!parseFloat(o)&&\"inline\"===E.css(e,\"display\",!1,r))&&e.getClientRects().length&&(a=\"border-box\"===E.css(e,\"boxSizing\",!1,r),(i=s in e)&&(o=e[s])),(o=parseFloat(o)||0)+Qe(e,t,n||(a?\"border\":\"content\"),i,r,o)+\"px\"}function tt(e,t,n,r,a){return new tt.prototype.init(e,t,n,r,a)}E.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=He(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var a,i,o,s=U(t),u=Je.test(t),c=e.style;if(u||(t=$e(s)),o=E.cssHooks[t]||E.cssHooks[s],void 0===n)return o&&\"get\"in o&&void 0!==(a=o.get(e,!1,r))?a:c[t];\"string\"==(i=typeof n)&&(a=te.exec(n))&&a[1]&&(n=ue(e,t,a),i=\"number\"),null!=n&&n==n&&(\"number\"!==i||u||(n+=a&&a[3]||(E.cssNumber[s]?\"\":\"px\")),v.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(c[t]=\"inherit\"),o&&\"set\"in o&&void 0===(n=o.set(e,n,r))||(u?c.setProperty(t,n):c[t]=n))}},css:function(e,t,n,r){var a,i,o,s=U(t);return Je.test(t)||(t=$e(s)),(o=E.cssHooks[t]||E.cssHooks[s])&&\"get\"in o&&(a=o.get(e,!0,n)),void 0===a&&(a=He(e,t,r)),\"normal\"===a&&t in Xe&&(a=Xe[t]),\"\"===n||n?(i=parseFloat(a),!0===n||isFinite(i)?i||0:a):a}}),E.each([\"height\",\"width\"],function(e,u){E.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(E.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,u,n):se(e,Ke,function(){return et(e,u,n)})},set:function(e,t,n){var r,a=qe(e),i=!v.scrollboxSize()&&\"absolute\"===a.position,o=(i||n)&&\"border-box\"===E.css(e,\"boxSizing\",!1,a),s=n?Qe(e,u,n,o,a):0;return o&&i&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(a[u])-Qe(e,u,\"border\",!1,a)-.5)),s&&(r=te.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=E.css(e,u)),Ze(0,t,s)}}}),E.cssHooks.marginLeft=Fe(v.reliableMarginLeft,function(e,t){if(t)return(parseFloat(He(e,\"marginLeft\"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),E.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,i){E.cssHooks[a+i]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[a+ne[t]+i]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==a&&(E.cssHooks[a+i].set=Ze)}),E.fn.extend({css:function(e,t){return H(this,function(e,t,n){var r,a,i={},o=0;if(Array.isArray(t)){for(r=qe(e),a=t.length;o<a;o++)i[t[o]]=E.css(e,t[o],!1,r);return i}return void 0!==n?E.style(e,t,n):E.css(e,t)},e,t,1<arguments.length)}}),((E.Tween=tt).prototype={constructor:tt,init:function(e,t,n,r,a,i){this.elem=e,this.prop=n,this.easing=a||E.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=i||(E.cssNumber[n]?\"\":\"px\")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=E.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}}).init.prototype=tt.prototype,(tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=E.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){E.fx.step[e.prop]?E.fx.step[e.prop](e):1!==e.elem.nodeType||!E.cssHooks[e.prop]&&null==e.elem.style[$e(e.prop)]?e.elem[e.prop]=e.now:E.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},E.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},E.fx=tt.prototype.init,E.fx.step={};var nt,rt,at,it,ot=/^(?:toggle|show|hide)$/,st=/queueHooks$/;function ut(){rt&&(!1===k.hidden&&x.requestAnimationFrame?x.requestAnimationFrame(ut):x.setTimeout(ut,E.fx.interval),E.fx.tick())}function ct(){return x.setTimeout(function(){nt=void 0}),nt=Date.now()}function lt(e,t){var n,r=0,a={height:e};for(t=t?1:0;r<4;r+=2-t)a[\"margin\"+(n=ne[r])]=a[\"padding\"+n]=e;return t&&(a.opacity=a.width=e),a}function ft(e,t,n){for(var r,a=(ht.tweeners[t]||[]).concat(ht.tweeners[\"*\"]),i=0,o=a.length;i<o;i++)if(r=a[i].call(n,t,e))return r}function ht(i,e,t){var n,o,r=0,a=ht.prefilters.length,s=E.Deferred().always(function(){delete u.elem}),u=function(){if(o)return!1;for(var e=nt||ct(),t=Math.max(0,c.startTime+c.duration-e),n=1-(t/c.duration||0),r=0,a=c.tweens.length;r<a;r++)c.tweens[r].run(n);return s.notifyWith(i,[c,n,t]),n<1&&a?t:(a||s.notifyWith(i,[c,1,0]),s.resolveWith(i,[c]),!1)},c=s.promise({elem:i,props:E.extend({},e),opts:E.extend(!0,{specialEasing:{},easing:E.easing._default},t),originalProperties:e,originalOptions:t,startTime:nt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=E.Tween(i,c.opts,e,t,c.opts.specialEasing[e]||c.opts.easing);return c.tweens.push(n),n},stop:function(e){var t=0,n=e?c.tweens.length:0;if(o)return this;for(o=!0;t<n;t++)c.tweens[t].run(1);return e?(s.notifyWith(i,[c,1,0]),s.resolveWith(i,[c,e])):s.rejectWith(i,[c,e]),this}}),l=c.props;for(function(e,t){var n,r,a,i,o;for(n in e)if(a=t[r=U(n)],i=e[n],Array.isArray(i)&&(a=i[1],i=e[n]=i[0]),n!==r&&(e[r]=i,delete e[n]),(o=E.cssHooks[r])&&\"expand\"in o)for(n in i=o.expand(i),delete e[r],i)n in e||(e[n]=i[n],t[n]=a);else t[r]=a}(l,c.opts.specialEasing);r<a;r++)if(n=ht.prefilters[r].call(c,i,l,c.opts))return y(n.stop)&&(E._queueHooks(c.elem,c.opts.queue).stop=n.stop.bind(n)),n;return E.map(l,ft,c),y(c.opts.start)&&c.opts.start.call(i,c),c.progress(c.opts.progress).done(c.opts.done,c.opts.complete).fail(c.opts.fail).always(c.opts.always),E.fx.timer(E.extend(u,{elem:i,anim:c,queue:c.opts.queue})),c}E.Animation=E.extend(ht,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return ue(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){for(var n,r=0,a=(e=y(e)?(t=e,[\"*\"]):e.match(P)).length;r<a;r++)n=e[r],ht.tweeners[n]=ht.tweeners[n]||[],ht.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,a,i,o,s,u,c,l,f=\"width\"in t||\"height\"in t,h=this,d={},p=e.style,m=e.nodeType&&oe(e),g=J.get(e,\"fxshow\");for(r in n.queue||(null==(o=E._queueHooks(e,\"fx\")).unqueued&&(o.unqueued=0,s=o.empty.fire,o.empty.fire=function(){o.unqueued||s()}),o.unqueued++,h.always(function(){h.always(function(){o.unqueued--,E.queue(e,\"fx\").length||o.empty.fire()})})),t)if(a=t[r],ot.test(a)){if(delete t[r],i=i||\"toggle\"===a,a===(m?\"hide\":\"show\")){if(\"show\"!==a||!g||void 0===g[r])continue;m=!0}d[r]=g&&g[r]||E.style(e,r)}if((u=!E.isEmptyObject(t))||!E.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],null==(c=g&&g.display)&&(c=J.get(e,\"display\")),\"none\"===(l=E.css(e,\"display\"))&&(c?l=c:(le([e],!0),c=e.style.display||c,l=E.css(e,\"display\"),le([e]))),(\"inline\"===l||\"inline-block\"===l&&null!=c)&&\"none\"===E.css(e,\"float\")&&(u||(h.done(function(){p.display=c}),null==c&&(l=p.display,c=\"none\"===l?\"\":l)),p.display=\"inline-block\")),n.overflow&&(p.overflow=\"hidden\",h.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]})),u=!1,d)u||(g?\"hidden\"in g&&(m=g.hidden):g=J.access(e,\"fxshow\",{display:c}),i&&(g.hidden=!m),m&&le([e],!0),h.done(function(){for(r in m||le([e]),J.remove(e,\"fxshow\"),d)E.style(e,r,d[r])})),u=ft(m?g[r]:0,r,h),r in g||(g[r]=u.start,m&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ht.prefilters.unshift(e):ht.prefilters.push(e)}}),E.speed=function(e,t,n){var r=e&&\"object\"==typeof e?E.extend({},e):{complete:n||!n&&t||y(e)&&e,duration:e,easing:n&&t||t&&!y(t)&&t};return E.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in E.fx.speeds?r.duration=E.fx.speeds[r.duration]:r.duration=E.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){y(r.old)&&r.old.call(this),r.queue&&E.dequeue(this,r.queue)},r},E.fn.extend({fadeTo:function(e,t,n,r){return this.filter(oe).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var a=E.isEmptyObject(t),i=E.speed(e,n,r),o=function(){var e=ht(this,E.extend({},t),i);(a||J.get(this,\"finish\"))&&e.stop(!0)};return o.finish=o,a||!1===i.queue?this.each(o):this.queue(i.queue,o)},stop:function(a,e,i){var o=function(e){var t=e.stop;delete e.stop,t(i)};return\"string\"!=typeof a&&(i=e,e=a,a=void 0),e&&!1!==a&&this.queue(a||\"fx\",[]),this.each(function(){var e=!0,t=null!=a&&a+\"queueHooks\",n=E.timers,r=J.get(this);if(t)r[t]&&r[t].stop&&o(r[t]);else for(t in r)r[t]&&r[t].stop&&st.test(t)&&o(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=a&&n[t].queue!==a||(n[t].anim.stop(i),e=!1,n.splice(t,1));!e&&i||E.dequeue(this,a)})},finish:function(o){return!1!==o&&(o=o||\"fx\"),this.each(function(){var e,t=J.get(this),n=t[o+\"queue\"],r=t[o+\"queueHooks\"],a=E.timers,i=n?n.length:0;for(t.finish=!0,E.queue(this,o,[]),r&&r.stop&&r.stop.call(this,!0),e=a.length;e--;)a[e].elem===this&&a[e].queue===o&&(a[e].anim.stop(!0),a.splice(e,1));for(e=0;e<i;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),E.each([\"toggle\",\"show\",\"hide\"],function(e,r){var a=E.fn[r];E.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?a.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),E.each({slideDown:lt(\"show\"),slideUp:lt(\"hide\"),slideToggle:lt(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){E.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),E.timers=[],E.fx.tick=function(){var e,t=0,n=E.timers;for(nt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||E.fx.stop(),nt=void 0},E.fx.timer=function(e){E.timers.push(e),E.fx.start()},E.fx.interval=13,E.fx.start=function(){rt||(rt=!0,ut())},E.fx.stop=function(){rt=null},E.fx.speeds={slow:600,fast:200,_default:400},E.fn.delay=function(r,e){return r=E.fx&&E.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=x.setTimeout(e,r);t.stop=function(){x.clearTimeout(n)}})},at=k.createElement(\"input\"),it=k.createElement(\"select\").appendChild(k.createElement(\"option\")),at.type=\"checkbox\",v.checkOn=\"\"!==at.value,v.optSelected=it.selected,(at=k.createElement(\"input\")).value=\"t\",at.type=\"radio\",v.radioValue=\"t\"===at.value;var dt,pt=E.expr.attrHandle;E.fn.extend({attr:function(e,t){return H(this,E.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){E.removeAttr(this,e)})}}),E.extend({attr:function(e,t,n){var r,a,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return void 0===e.getAttribute?E.prop(e,t,n):(1===i&&E.isXMLDoc(e)||(a=E.attrHooks[t.toLowerCase()]||(E.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void E.removeAttr(e,t):a&&\"set\"in a&&void 0!==(r=a.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):a&&\"get\"in a&&null!==(r=a.get(e,t))?r:null==(r=E.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!v.radioValue&&\"radio\"===t&&M(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,a=t&&t.match(P);if(a&&1===e.nodeType)for(;n=a[r++];)e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?E.removeAttr(e,n):e.setAttribute(n,n),n}},E.each(E.expr.match.bool.source.match(/\\w+/g),function(e,t){var o=pt[t]||E.find.attr;pt[t]=function(e,t,n){var r,a,i=t.toLowerCase();return n||(a=pt[i],pt[i]=r,r=null!=o(e,t,n)?i:null,pt[i]=a),r}});var mt=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(\" \")}function yt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function _t(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(P)||[]}E.fn.extend({prop:function(e,t){return H(this,E.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[E.propFix[e]||e]})}}),E.extend({prop:function(e,t,n){var r,a,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return 1===i&&E.isXMLDoc(e)||(t=E.propFix[t]||t,a=E.propHooks[t]),void 0!==n?a&&\"set\"in a&&void 0!==(r=a.set(e,n,t))?r:e[t]=n:a&&\"get\"in a&&null!==(r=a.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=E.find.attr(e,\"tabindex\");return t?parseInt(t,10):mt.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:\"htmlFor\",class:\"className\"}}),v.optSelected||(E.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),E.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){E.propFix[this.toLowerCase()]=this}),E.fn.extend({addClass:function(t){var e,n,r,a,i,o,s,u=0;if(y(t))return this.each(function(e){E(this).addClass(t.call(this,e,yt(this)))});if((e=_t(t)).length)for(;n=this[u++];)if(a=yt(n),r=1===n.nodeType&&\" \"+vt(a)+\" \"){for(o=0;i=e[o++];)r.indexOf(\" \"+i+\" \")<0&&(r+=i+\" \");a!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,a,i,o,s,u=0;if(y(t))return this.each(function(e){E(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=_t(t)).length)for(;n=this[u++];)if(a=yt(n),r=1===n.nodeType&&\" \"+vt(a)+\" \"){for(o=0;i=e[o++];)for(;-1<r.indexOf(\" \"+i+\" \");)r=r.replace(\" \"+i+\" \",\" \");a!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(a,t){var i=typeof a,o=\"string\"===i||Array.isArray(a);return\"boolean\"==typeof t&&o?t?this.addClass(a):this.removeClass(a):y(a)?this.each(function(e){E(this).toggleClass(a.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(o)for(t=0,n=E(this),r=_t(a);e=r[t++];)n.hasClass(e)?n.removeClass(e):n.addClass(e);else void 0!==a&&\"boolean\"!==i||((e=yt(this))&&J.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===a?\"\":J.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;for(t=\" \"+e+\" \";n=this[r++];)if(1===n.nodeType&&-1<(\" \"+vt(yt(n))+\" \").indexOf(t))return!0;return!1}});var bt=/\\r/g;E.fn.extend({val:function(n){var r,e,a,t=this[0];return arguments.length?(a=y(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=a?n.call(this,e,E(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=E.map(t,function(e){return null==e?\"\":e+\"\"})),(r=E.valHooks[this.type]||E.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=E.valHooks[t.type]||E.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(bt,\"\"):null==e?\"\":e:void 0}}),E.extend({valHooks:{option:{get:function(e){var t=E.find.attr(e,\"value\");return null!=t?t:vt(E.text(e))}},select:{get:function(e){var t,n,r,a=e.options,i=e.selectedIndex,o=\"select-one\"===e.type,s=o?null:[],u=o?i+1:a.length;for(r=i<0?u:o?i:0;r<u;r++)if(((n=a[r]).selected||r===i)&&!n.disabled&&(!n.parentNode.disabled||!M(n.parentNode,\"optgroup\"))){if(t=E(n).val(),o)return t;s.push(t)}return s},set:function(e,t){for(var n,r,a=e.options,i=E.makeArray(t),o=a.length;o--;)((r=a[o]).selected=-1<E.inArray(E.valHooks.option.get(r),i))&&(n=!0);return n||(e.selectedIndex=-1),i}}}}),E.each([\"radio\",\"checkbox\"],function(){E.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<E.inArray(E(e).val(),t)}},v.checkOn||(E.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),v.focusin=\"onfocusin\"in x;var wt=/^(?:focusinfocus|focusoutblur)$/,At=function(e){e.stopPropagation()};E.extend(E.event,{trigger:function(e,t,n,r){var a,i,o,s,u,c,l,f,h=[n||k],d=g.call(e,\"type\")?e.type:e,p=g.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(i=f=o=n=n||k,3!==n.nodeType&&8!==n.nodeType&&!wt.test(d+E.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(p=d.split(\".\")).shift(),p.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[E.expando]?e:new E.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=p.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+p.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:E.makeArray(t,[e]),l=E.event.special[d]||{},r||!l.trigger||!1!==l.trigger.apply(n,t))){if(!r&&!l.noBubble&&!_(n)){for(s=l.delegateType||d,wt.test(s+d)||(i=i.parentNode);i;i=i.parentNode)h.push(i),o=i;o===(n.ownerDocument||k)&&h.push(o.defaultView||o.parentWindow||x)}for(a=0;(i=h[a++])&&!e.isPropagationStopped();)f=i,e.type=1<a?s:l.bindType||d,(c=(J.get(i,\"events\")||{})[e.type]&&J.get(i,\"handle\"))&&c.apply(i,t),(c=u&&i[u])&&c.apply&&$(i)&&(e.result=c.apply(i,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||l._default&&!1!==l._default.apply(h.pop(),t)||!$(n)||u&&y(n[d])&&!_(n)&&((o=n[u])&&(n[u]=null),E.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,At),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,At),E.event.triggered=void 0,o&&(n[u]=o)),e.result}},simulate:function(e,t,n){var r=E.extend(new E.Event,n,{type:e,isSimulated:!0});E.event.trigger(r,null,t)}}),E.fn.extend({trigger:function(e,t){return this.each(function(){E.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return E.event.trigger(e,t,n,!0)}}),v.focusin||E.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var a=function(e){E.event.simulate(r,e.target,E.event.fix(e))};E.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=J.access(e,r);t||e.addEventListener(n,a,!0),J.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=J.access(e,r)-1;t?J.access(e,r,t):(e.removeEventListener(n,a,!0),J.remove(e,r))}}});var xt=x.location,kt=Date.now(),Et=/\\?/;E.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new x.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||E.error(\"Invalid XML: \"+e),t};var St=/\\[\\]$/,Mt=/\\r?\\n/g,Tt=/^(?:submit|button|image|reset|file)$/i,Ct=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,a){var t;if(Array.isArray(e))E.each(e,function(e,t){r||St.test(n)?a(n,t):Dt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,a)});else if(r||\"object\"!==w(e))a(n,e);else for(t in e)Dt(n+\"[\"+t+\"]\",e[t],r,a)}E.param=function(e,t){var n,r=[],a=function(e,t){var n=y(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!E.isPlainObject(e))E.each(e,function(){a(this.name,this.value)});else for(n in e)Dt(n,e[n],t,a);return r.join(\"&\")},E.fn.extend({serialize:function(){return E.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=E.prop(this,\"elements\");return e?E.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!E(this).is(\":disabled\")&&Ct.test(this.nodeName)&&!Tt.test(e)&&(this.checked||!fe.test(e))}).map(function(e,t){var n=E(this).val();return null==n?null:Array.isArray(n)?E.map(n,function(e){return{name:t.name,value:e.replace(Mt,\"\\r\\n\")}}):{name:t.name,value:n.replace(Mt,\"\\r\\n\")}}).get()}});var Ot=/%20/g,jt=/#.*$/,Nt=/([?&])_=[^&]*/,zt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Pt=/^(?:GET|HEAD)$/,Lt=/^\\/\\//,Rt={},Yt={},Wt=\"*/\".concat(\"*\"),qt=k.createElement(\"a\");function It(i){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,a=e.toLowerCase().match(P)||[];if(y(t))for(;n=a[r++];)\"+\"===n[0]?(n=n.slice(1)||\"*\",(i[n]=i[n]||[]).unshift(t)):(i[n]=i[n]||[]).push(t)}}function Ht(t,a,i,o){var s={},u=t===Yt;function c(e){var r;return s[e]=!0,E.each(t[e]||[],function(e,t){var n=t(a,i,o);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(a.dataTypes.unshift(n),c(n),!1)}),r}return c(a.dataTypes[0])||!s[\"*\"]&&c(\"*\")}function Ft(e,t){var n,r,a=E.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((a[n]?e:r||(r={}))[n]=t[n]);return r&&E.extend(!0,e,r),e}qt.href=xt.href,E.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:xt.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(xt.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Wt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":E.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,E.ajaxSettings),t):Ft(E.ajaxSettings,e)},ajaxPrefilter:It(Rt),ajaxTransport:It(Yt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var l,f,h,n,d,r,p,m,a,i,g=E.ajaxSetup({},t),v=g.context||g,y=g.context&&(v.nodeType||v.jquery)?E(v):E.event,_=E.Deferred(),b=E.Callbacks(\"once memory\"),w=g.statusCode||{},o={},s={},u=\"canceled\",A={readyState:0,getResponseHeader:function(e){var t;if(p){if(!n)for(n={};t=zt.exec(h);)n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2]);t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return p?h:null},setRequestHeader:function(e,t){return null==p&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,o[e]=t),this},overrideMimeType:function(e){return null==p&&(g.mimeType=e),this},statusCode:function(e){var t;if(e)if(p)A.always(e[A.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return l&&l.abort(t),c(0,t),this}};if(_.promise(A),g.url=((e||g.url||xt.href)+\"\").replace(Lt,xt.protocol+\"//\"),g.type=t.method||t.type||g.method||g.type,g.dataTypes=(g.dataType||\"*\").toLowerCase().match(P)||[\"\"],null==g.crossDomain){r=k.createElement(\"a\");try{r.href=g.url,r.href=r.href,g.crossDomain=qt.protocol+\"//\"+qt.host!=r.protocol+\"//\"+r.host}catch(e){g.crossDomain=!0}}if(g.data&&g.processData&&\"string\"!=typeof g.data&&(g.data=E.param(g.data,g.traditional)),Ht(Rt,g,t,A),p)return A;for(a in(m=E.event&&g.global)&&0==E.active++&&E.event.trigger(\"ajaxStart\"),g.type=g.type.toUpperCase(),g.hasContent=!Pt.test(g.type),f=g.url.replace(jt,\"\"),g.hasContent?g.data&&g.processData&&0===(g.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(g.data=g.data.replace(Ot,\"+\")):(i=g.url.slice(f.length),g.data&&(g.processData||\"string\"==typeof g.data)&&(f+=(Et.test(f)?\"&\":\"?\")+g.data,delete g.data),!1===g.cache&&(f=f.replace(Nt,\"$1\"),i=(Et.test(f)?\"&\":\"?\")+\"_=\"+kt+++i),g.url=f+i),g.ifModified&&(E.lastModified[f]&&A.setRequestHeader(\"If-Modified-Since\",E.lastModified[f]),E.etag[f]&&A.setRequestHeader(\"If-None-Match\",E.etag[f])),(g.data&&g.hasContent&&!1!==g.contentType||t.contentType)&&A.setRequestHeader(\"Content-Type\",g.contentType),A.setRequestHeader(\"Accept\",g.dataTypes[0]&&g.accepts[g.dataTypes[0]]?g.accepts[g.dataTypes[0]]+(\"*\"!==g.dataTypes[0]?\", \"+Wt+\"; q=0.01\":\"\"):g.accepts[\"*\"]),g.headers)A.setRequestHeader(a,g.headers[a]);if(g.beforeSend&&(!1===g.beforeSend.call(v,A,g)||p))return A.abort();if(u=\"abort\",b.add(g.complete),A.done(g.success),A.fail(g.error),l=Ht(Yt,g,t,A)){if(A.readyState=1,m&&y.trigger(\"ajaxSend\",[A,g]),p)return A;g.async&&0<g.timeout&&(d=x.setTimeout(function(){A.abort(\"timeout\")},g.timeout));try{p=!1,l.send(o,c)}catch(e){if(p)throw e;c(-1,e)}}else c(-1,\"No Transport\");function c(e,t,n,r){var a,i,o,s,u,c=t;p||(p=!0,d&&x.clearTimeout(d),l=void 0,h=r||\"\",A.readyState=0<e?4:0,a=200<=e&&e<300||304===e,n&&(s=function(e,t,n){for(var r,a,i,o,s=e.contents,u=e.dataTypes;\"*\"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(a in s)if(s[a]&&s[a].test(r)){u.unshift(a);break}if(u[0]in n)i=u[0];else{for(a in n){if(!u[0]||e.converters[a+\" \"+u[0]]){i=a;break}o||(o=a)}i=i||o}if(i)return i!==u[0]&&u.unshift(i),n[i]}(g,A,n)),s=function(e,t,n,r){var a,i,o,s,u,c={},l=e.dataTypes.slice();if(l[1])for(o in e.converters)c[o.toLowerCase()]=e.converters[o];for(i=l.shift();i;)if(e.responseFields[i]&&(n[e.responseFields[i]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=i,i=l.shift())if(\"*\"===i)i=u;else if(\"*\"!==u&&u!==i){if(!(o=c[u+\" \"+i]||c[\"* \"+i]))for(a in c)if((s=a.split(\" \"))[1]===i&&(o=c[u+\" \"+s[0]]||c[\"* \"+s[0]])){!0===o?o=c[a]:!0!==c[a]&&(i=s[0],l.unshift(s[1]));break}if(!0!==o)if(o&&e.throws)t=o(t);else try{t=o(t)}catch(e){return{state:\"parsererror\",error:o?e:\"No conversion from \"+u+\" to \"+i}}}return{state:\"success\",data:t}}(g,s,A,a),a?(g.ifModified&&((u=A.getResponseHeader(\"Last-Modified\"))&&(E.lastModified[f]=u),(u=A.getResponseHeader(\"etag\"))&&(E.etag[f]=u)),204===e||\"HEAD\"===g.type?c=\"nocontent\":304===e?c=\"notmodified\":(c=s.state,i=s.data,a=!(o=s.error))):(o=c,!e&&c||(c=\"error\",e<0&&(e=0))),A.status=e,A.statusText=(t||c)+\"\",a?_.resolveWith(v,[i,c,A]):_.rejectWith(v,[A,c,o]),A.statusCode(w),w=void 0,m&&y.trigger(a?\"ajaxSuccess\":\"ajaxError\",[A,g,a?i:o]),b.fireWith(v,[A,c]),m&&(y.trigger(\"ajaxComplete\",[A,g]),--E.active||E.event.trigger(\"ajaxStop\")))}return A},getJSON:function(e,t,n){return E.get(e,t,n,\"json\")},getScript:function(e,t){return E.get(e,void 0,t,\"script\")}}),E.each([\"get\",\"post\"],function(e,a){E[a]=function(e,t,n,r){return y(t)&&(r=r||n,n=t,t=void 0),E.ajax(E.extend({url:e,type:a,dataType:r,data:t,success:n},E.isPlainObject(e)&&e))}}),E._evalUrl=function(e,t){return E.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){E.globalEval(e,t)}})},E.fn.extend({wrapAll:function(e){var t;return this[0]&&(y(e)&&(e=e.call(this[0])),t=E(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return y(n)?this.each(function(e){E(this).wrapInner(n.call(this,e))}):this.each(function(){var e=E(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=y(t);return this.each(function(e){E(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){E(this).replaceWith(this.childNodes)}),this}}),E.expr.pseudos.hidden=function(e){return!E.expr.pseudos.visible(e)},E.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},E.ajaxSettings.xhr=function(){try{return new x.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},Gt=E.ajaxSettings.xhr();v.cors=!!Gt&&\"withCredentials\"in Gt,v.ajax=Gt=!!Gt,E.ajaxTransport(function(a){var i,o;if(v.cors||Gt&&!a.crossDomain)return{send:function(e,t){var n,r=a.xhr();if(r.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(n in a.xhrFields)r[n]=a.xhrFields[n];for(n in a.mimeType&&r.overrideMimeType&&r.overrideMimeType(a.mimeType),a.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);i=function(e){return function(){i&&(i=o=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=i(),o=r.onerror=r.ontimeout=i(\"error\"),void 0!==r.onabort?r.onabort=o:r.onreadystatechange=function(){4===r.readyState&&x.setTimeout(function(){i&&o()})},i=i(\"abort\");try{r.send(a.hasContent&&a.data||null)}catch(e){if(i)throw e}},abort:function(){i&&i()}}}),E.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),E.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return E.globalEval(e),e}}}),E.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),E.ajaxTransport(\"script\",function(n){var r,a;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=E(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",a=function(e){r.remove(),a=null,e&&t(\"error\"===e.type?404:200,e.type)}),k.head.appendChild(r[0])},abort:function(){a&&a()}}});var Ut,$t=[],Vt=/(=)\\?(?=&|$)|\\?\\?/;E.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=$t.pop()||E.expando+\"_\"+kt++;return this[e]=!0,e}}),E.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,a,i,o=!1!==e.jsonp&&(Vt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Vt.test(e.data)&&\"data\");if(o||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=y(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,o?e[o]=e[o].replace(Vt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return i||E.error(r+\" was not called\"),i[0]},e.dataTypes[0]=\"json\",a=x[r],x[r]=function(){i=arguments},n.always(function(){void 0===a?E(x).removeProp(r):x[r]=a,e[r]&&(e.jsonpCallback=t.jsonpCallback,$t.push(r)),i&&y(a)&&a(i[0]),i=a=void 0}),\"script\"}),v.createHTMLDocument=((Ut=k.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=k.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=k.location.href,t.head.appendChild(r)):t=k),i=!n&&[],(a=T.exec(e))?[t.createElement(a[1])]:(a=be([e],t,i),i&&i.length&&E(i).remove(),E.merge([],a.childNodes)));var r,a,i},E.fn.load=function(e,t,n){var r,a,i,o=this,s=e.indexOf(\" \");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),y(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(a=\"POST\"),0<o.length&&E.ajax({url:e,type:a||\"GET\",dataType:\"html\",data:t}).done(function(e){i=arguments,o.html(r?E(\"<div>\").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){o.each(function(){n.apply(this,i||[e.responseText,t,e])})}),this},E.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,a,i,o,s,u,c=E.css(e,\"position\"),l=E(e),f={};\"static\"===c&&(e.style.position=\"relative\"),s=l.offset(),i=E.css(e,\"top\"),u=E.css(e,\"left\"),a=(\"absolute\"===c||\"fixed\"===c)&&-1<(i+u).indexOf(\"auto\")?(o=(r=l.position()).top,r.left):(o=parseFloat(i)||0,parseFloat(u)||0),y(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+o),null!=t.left&&(f.left=t.left-s.left+a),\"using\"in t?t.using.call(e,f):l.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],a={top:0,left:0};if(\"fixed\"===E.css(r,\"position\"))t=r.getBoundingClientRect();else{for(t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;e&&(e===n.body||e===n.documentElement)&&\"static\"===E.css(e,\"position\");)e=e.parentNode;e&&e!==r&&1===e.nodeType&&((a=E(e).offset()).top+=E.css(e,\"borderTopWidth\",!0),a.left+=E.css(e,\"borderLeftWidth\",!0))}return{top:t.top-a.top-E.css(r,\"marginTop\",!0),left:t.left-a.left-E.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&\"static\"===E.css(e,\"position\");)e=e.offsetParent;return e||re})}}),E.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,a){var i=\"pageYOffset\"===a;E.fn[t]=function(e){return H(this,function(e,t,n){var r;if(_(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[a]:e[t];r?r.scrollTo(i?r.pageXOffset:n,i?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each([\"top\",\"left\"],function(e,n){E.cssHooks[n]=Fe(v.pixelPosition,function(e,t){if(t)return t=He(e,n),We.test(t)?E(e).position()[n]+\"px\":t})}),E.each({Height:\"height\",Width:\"width\"},function(o,s){E.each({padding:\"inner\"+o,content:s,\"\":\"outer\"+o},function(r,i){E.fn[i]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),a=r||(!0===e||!0===t?\"margin\":\"border\");return H(this,function(e,t,n){var r;return _(e)?0===i.indexOf(\"outer\")?e[\"inner\"+o]:e.document.documentElement[\"client\"+o]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+o],r[\"scroll\"+o],e.body[\"offset\"+o],r[\"offset\"+o],r[\"client\"+o])):void 0===n?E.css(e,t,a):E.style(e,t,n,a)},s,n?e:void 0,n)}})}),E.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){E.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),E.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),E.proxy=function(e,t){var n,r,a;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),y(e))return r=s.call(arguments,2),(a=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||E.guid++,a},E.holdReady=function(e){e?E.readyWait++:E.ready(!0)},E.isArray=Array.isArray,E.parseJSON=JSON.parse,E.nodeName=M,E.isFunction=y,E.isWindow=_,E.camelCase=U,E.type=w,E.now=Date.now,E.isNumeric=function(e){var t=E.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))};var Jt=x.jQuery,Kt=x.$;return E.noConflict=function(e){return x.$===E&&(x.$=Kt),e&&x.jQuery===E&&(x.jQuery=Jt),E},e||(x.jQuery=x.$=E),E},e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return n(e)}});Tr.noConflict();var Cr=function(e,t,n){return(!(3<arguments.length&&void 0!==arguments[3])||arguments[3])&&(t&&\"string\"==typeof t?t=Sr.find(t):t||(t=Sr)),new Tr.fn.init(e,t,n)};Cr.fn=Cr.prototype=Tr.fn,Tr.extend(Cr,Tr);var Dr=function(e){return e.find('script, style, link[rel=\"stylesheet\"]').remove(),e};Cr.cloneHtml=function(){return Dr(Cr(\"html\",null,null,!1).clone()).children().wrap(\"<div />\").wrap(\"<div />\")},Cr.root=function(){return Cr(\"*\").first()},Cr.browser=!0;var Or=function(e){var t=e.get(0);return!(!t||!t.tagName)&&\"container\"===t.tagName.toLowerCase()};function jr(e,t){return Array(t+1).join(e)}Cr.html=function(e){if(e)return Or(e)||Or(e.children(\"container\"))?e.children(\"container\").html()||e.html():Cr(\"<div>\").append(e.eq(0).clone()).html();var t=Dr(Cr(\"body\",null,null,!1).clone()),n=Dr(Cr(\"head\",null,null,!1).clone());return Sr&&0<Sr.length?Sr.children().html():Cr(\"<container />\").append(Cr(\"<container>\".concat(n.html(),\"</container>\"))).append(Cr(\"<container>\".concat(t.html(),\"</container>\"))).wrap(\"<container />\").parent().html()},Cr.load=function(e){var t=2<arguments.length&&void 0!==arguments[2]&&arguments[2];return e=e?Cr(\"<container />\").html(e):Cr.cloneHtml(),Sr=Sr||Cr('<div class=\"'.concat(\"mercury-parsing-container\",'\" style=\"display:none;\" />')),(e=Dr(e)).find(\"*\").contents().each(function(){this.nodeType===Node.COMMENT_NODE&&Cr(this).remove()}),Sr.html(e),t?{$:Cr,html:e.html()}:Cr};var Nr=[\"address\",\"article\",\"aside\",\"audio\",\"blockquote\",\"body\",\"canvas\",\"center\",\"dd\",\"dir\",\"div\",\"dl\",\"dt\",\"fieldset\",\"figcaption\",\"figure\",\"footer\",\"form\",\"frameset\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"hgroup\",\"hr\",\"html\",\"isindex\",\"li\",\"main\",\"menu\",\"nav\",\"noframes\",\"noscript\",\"ol\",\"output\",\"p\",\"pre\",\"section\",\"table\",\"tbody\",\"td\",\"tfoot\",\"th\",\"thead\",\"tr\",\"ul\"];function zr(e){return-1!==Nr.indexOf(e.nodeName.toLowerCase())}var Pr=[\"area\",\"base\",\"br\",\"col\",\"command\",\"embed\",\"hr\",\"img\",\"input\",\"keygen\",\"link\",\"meta\",\"param\",\"source\",\"track\",\"wbr\"];function Lr(e){return-1!==Pr.indexOf(e.nodeName.toLowerCase())}var Rr=Pr.join();var Yr={};function Wr(e){for(var t in this.options=e,this._keep=[],this._remove=[],this.blankRule={replacement:e.blankReplacement},this.keepReplacement=e.keepReplacement,this.defaultRule={replacement:e.defaultReplacement},this.array=[],e.rules)this.array.push(e.rules[t])}function qr(e,t,n){for(var r=0;r<e.length;r++){var a=e[r];if(Ir(a,t,n))return a}}function Ir(e,t,n){var r=e.filter;if(\"string\"==typeof r){if(r===t.nodeName.toLowerCase())return!0}else if(Array.isArray(r)){if(-1<r.indexOf(t.nodeName.toLowerCase()))return!0}else{if(\"function\"!=typeof r)throw new TypeError(\"`filter` needs to be a string, array, or function\");if(r.call(e,t,n))return!0}}function Hr(e){var t=e.nextSibling||e.parentNode;return e.parentNode.removeChild(e),t}function Fr(e,t,n){return e&&e.parentNode===t||n(t)?t.nextSibling||t.parentNode:t.firstChild||t.nextSibling||t.parentNode}Yr.paragraph={filter:\"p\",replacement:function(e){return\"\\n\\n\"+e+\"\\n\\n\"}},Yr.lineBreak={filter:\"br\",replacement:function(e,t,n){return n.br+\"\\n\"}},Yr.heading={filter:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"],replacement:function(e,t,n){var r=Number(t.nodeName.charAt(1));return\"setext\"===n.headingStyle&&r<3?\"\\n\\n\"+e+\"\\n\"+jr(1===r?\"=\":\"-\",e.length)+\"\\n\\n\":\"\\n\\n\"+jr(\"#\",r)+\" \"+e+\"\\n\\n\"}},Yr.blockquote={filter:\"blockquote\",replacement:function(e){return\"\\n\\n\"+(e=(e=e.replace(/^\\n+|\\n+$/g,\"\")).replace(/^/gm,\"> \"))+\"\\n\\n\"}},Yr.list={filter:[\"ul\",\"ol\"],replacement:function(e,t){var n=t.parentNode;return\"LI\"===n.nodeName&&n.lastElementChild===t?\"\\n\"+e:\"\\n\\n\"+e+\"\\n\\n\"}},Yr.listItem={filter:\"li\",replacement:function(e,t,n){e=e.replace(/^\\n+/,\"\").replace(/\\n+$/,\"\\n\").replace(/\\n/gm,\"\\n    \");var r=n.bulletListMarker+\"   \",a=t.parentNode;if(\"OL\"===a.nodeName){var i=a.getAttribute(\"start\"),o=Array.prototype.indexOf.call(a.children,t);r=(i?Number(i)+o:o+1)+\".  \"}return r+e+(t.nextSibling&&!/\\n$/.test(e)?\"\\n\":\"\")}},Yr.indentedCodeBlock={filter:function(e,t){return\"indented\"===t.codeBlockStyle&&\"PRE\"===e.nodeName&&e.firstChild&&\"CODE\"===e.firstChild.nodeName},replacement:function(e,t,n){return\"\\n\\n    \"+t.firstChild.textContent.replace(/\\n/g,\"\\n    \")+\"\\n\\n\"}},Yr.fencedCodeBlock={filter:function(e,t){return\"fenced\"===t.codeBlockStyle&&\"PRE\"===e.nodeName&&e.firstChild&&\"CODE\"===e.firstChild.nodeName},replacement:function(e,t,n){var r=((t.firstChild.className||\"\").match(/language-(\\S+)/)||[null,\"\"])[1];return\"\\n\\n\"+n.fence+r+\"\\n\"+t.firstChild.textContent+\"\\n\"+n.fence+\"\\n\\n\"}},Yr.horizontalRule={filter:\"hr\",replacement:function(e,t,n){return\"\\n\\n\"+n.hr+\"\\n\\n\"}},Yr.inlineLink={filter:function(e,t){return\"inlined\"===t.linkStyle&&\"A\"===e.nodeName&&e.getAttribute(\"href\")},replacement:function(e,t){return\"[\"+e+\"](\"+t.getAttribute(\"href\")+(t.title?' \"'+t.title+'\"':\"\")+\")\"}},Yr.referenceLink={filter:function(e,t){return\"referenced\"===t.linkStyle&&\"A\"===e.nodeName&&e.getAttribute(\"href\")},replacement:function(e,t,n){var r,a,i=t.getAttribute(\"href\"),o=t.title?' \"'+t.title+'\"':\"\";switch(n.linkReferenceStyle){case\"collapsed\":r=\"[\"+e+\"][]\",a=\"[\"+e+\"]: \"+i+o;break;case\"shortcut\":r=\"[\"+e+\"]\",a=\"[\"+e+\"]: \"+i+o;break;default:var s=this.references.length+1;r=\"[\"+e+\"][\"+s+\"]\",a=\"[\"+s+\"]: \"+i+o}return this.references.push(a),r},references:[],append:function(e){var t=\"\";return this.references.length&&(t=\"\\n\\n\"+this.references.join(\"\\n\")+\"\\n\\n\",this.references=[]),t}},Yr.emphasis={filter:[\"em\",\"i\"],replacement:function(e,t,n){return e.trim()?n.emDelimiter+e+n.emDelimiter:\"\"}},Yr.strong={filter:[\"strong\",\"b\"],replacement:function(e,t,n){return e.trim()?n.strongDelimiter+e+n.strongDelimiter:\"\"}},Yr.code={filter:function(e){var t=e.previousSibling||e.nextSibling,n=\"PRE\"===e.parentNode.nodeName&&!t;return\"CODE\"===e.nodeName&&!n},replacement:function(e){if(!e.trim())return\"\";var t=\"`\",n=\"\",r=\"\",a=e.match(/`+/gm);if(a)for(/^`/.test(e)&&(n=\" \"),/`$/.test(e)&&(r=\" \");-1!==a.indexOf(t);)t+=\"`\";return t+n+e+r+t}},Yr.image={filter:\"img\",replacement:function(e,t){var n=t.alt||\"\",r=t.getAttribute(\"src\")||\"\",a=t.title||\"\";return r?\"![\"+n+\"](\"+r+(a?' \"'+a+'\"':\"\")+\")\":\"\"}},Wr.prototype={add:function(e,t){this.array.unshift(t)},keep:function(e){this._keep.unshift({filter:e,replacement:this.keepReplacement})},remove:function(e){this._remove.unshift({filter:e,replacement:function(){return\"\"}})},forNode:function(e){return e.isBlank?this.blankRule:(t=qr(this.array,e,this.options))?t:(t=qr(this._keep,e,this.options))?t:(t=qr(this._remove,e,this.options))?t:this.defaultRule;var t},forEach:function(e){for(var t=0;t<this.array.length;t++)e(this.array[t],t)}};var Br=\"undefined\"!=typeof window?window:{};var Gr,Ur,$r,Vr=function(){var e=Br.DOMParser,t=!1;try{(new e).parseFromString(\"\",\"text/html\")&&(t=!0)}catch(e){}return t}()?Br.DOMParser:(Gr=function(){},Ur=require(\"jsdom\").JSDOM,Gr.prototype.parseFromString=function(e){return new Ur(e).window.document},Gr);function Jr(e){var t;\"string\"==typeof e?t=($r=$r||new Vr).parseFromString('<x-turndown id=\"turndown-root\">'+e+\"</x-turndown>\",\"text/html\").getElementById(\"turndown-root\"):t=e.cloneNode(!0);return function(e){var t=e.element,n=e.isBlock,r=e.isVoid,a=e.isPre||function(e){return\"PRE\"===e.nodeName};if(t.firstChild&&!a(t)){for(var i=null,o=!1,s=null,u=Fr(s,t,a);u!==t;){if(3===u.nodeType||4===u.nodeType){var c=u.data.replace(/[ \\r\\n\\t]+/g,\" \");if(i&&!/ $/.test(i.data)||o||\" \"!==c[0]||(c=c.substr(1)),!c){u=Hr(u);continue}u.data=c,i=u}else{if(1!==u.nodeType){u=Hr(u);continue}n(u)||\"BR\"===u.nodeName?(i&&(i.data=i.data.replace(/ $/,\"\")),i=null,o=!1):r(u)&&(o=!(i=null))}var l=Fr(s,u,a);s=u,u=l}i&&(i.data=i.data.replace(/ $/,\"\"),i.data||Hr(i))}}({element:t,isBlock:zr,isVoid:Lr}),t}function Kr(e){var t,n;return e.isBlock=zr(e),e.isCode=\"code\"===e.nodeName.toLowerCase()||e.parentNode.isCode,e.isBlank=-1===[\"A\",\"TH\",\"TD\",\"IFRAME\",\"SCRIPT\",\"AUDIO\",\"VIDEO\"].indexOf((t=e).nodeName)&&/^\\s*$/i.test(t.textContent)&&!Lr(t)&&!((n=t).querySelector&&n.querySelector(Rr)),e.flankingWhitespace=function(e){var t=\"\",n=\"\";if(!e.isBlock){var r=/^[ \\r\\n\\t]/.test(e.textContent),a=/[ \\r\\n\\t]$/.test(e.textContent);r&&!Xr(\"left\",e)&&(t=\" \"),a&&!Xr(\"right\",e)&&(n=\" \")}return{leading:t,trailing:n}}(e),e}function Xr(e,t){var n,r,a;return r=\"left\"===e?(n=t.previousSibling,/ $/):(n=t.nextSibling,/^ /),n&&(3===n.nodeType?a=r.test(n.nodeValue):1!==n.nodeType||zr(n)||(a=r.test(n.textContent))),a}var Zr=Array.prototype.reduce,Qr=/^\\n*/,ea=/\\n*$/,ta=[[/\\\\/g,\"\\\\\\\\\"],[/\\*/g,\"\\\\*\"],[/^-/g,\"\\\\-\"],[/^\\+ /g,\"\\\\+ \"],[/^(=+)/g,\"\\\\$1\"],[/^(#{1,6}) /g,\"\\\\$1 \"],[/`/g,\"\\\\`\"],[/^~~~/g,\"\\\\~~~\"],[/\\[/g,\"\\\\[\"],[/\\]/g,\"\\\\]\"],[/^>/g,\"\\\\>\"],[/_/g,\"\\\\_\"],[/^(\\d+)\\. /g,\"$1\\\\. \"]];function na(e){if(!(this instanceof na))return new na(e);var t={rules:Yr,headingStyle:\"setext\",hr:\"* * *\",bulletListMarker:\"*\",codeBlockStyle:\"indented\",fence:\"```\",emDelimiter:\"_\",strongDelimiter:\"**\",linkStyle:\"inlined\",linkReferenceStyle:\"full\",br:\"  \",blankReplacement:function(e,t){return t.isBlock?\"\\n\\n\":\"\"},keepReplacement:function(e,t){return t.isBlock?\"\\n\\n\"+t.outerHTML+\"\\n\\n\":t.outerHTML},defaultReplacement:function(e,t){return t.isBlock?\"\\n\\n\"+e+\"\\n\\n\":e}};this.options=function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)n.hasOwnProperty(r)&&(e[r]=n[r])}return e}({},t,e),this.rules=new Wr(this.options)}function ra(e){var r=this;return Zr.call(e.childNodes,function(e,t){var n=\"\";return 3===(t=new Kr(t)).nodeType?n=t.isCode?t.nodeValue:r.escape(t.nodeValue):1===t.nodeType&&(n=function(e){var t=this.rules.forNode(e),n=ra.call(this,e),r=e.flankingWhitespace;(r.leading||r.trailing)&&(n=n.trim());return r.leading+t.replacement(n,e,this.options)+r.trailing}.call(r,t)),aa(e,n)},\"\")}function aa(e,t){var n,r,a,i=(n=t,r=[e.match(ea)[0],n.match(Qr)[0]].sort(),(a=r[r.length-1]).length<2?a:\"\\n\\n\");return(e=e.replace(ea,\"\"))+i+(t=t.replace(Qr,\"\"))}na.prototype={turndown:function(e){if(null==(t=e)||\"string\"!=typeof t&&(!t.nodeType||1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType))throw new TypeError(e+\" is not a string, or an element/document/fragment node.\");var t;if(\"\"===e)return\"\";var n=ra.call(this,new Jr(e));return function(t){var n=this;return this.rules.forEach(function(e){\"function\"==typeof e.append&&(t=aa(t,e.append(n.options)))}),t.replace(/^[\\t\\r\\n]+/,\"\").replace(/[\\t\\r\\n\\s]+$/,\"\")}.call(this,n)},use:function(e){if(Array.isArray(e))for(var t=0;t<e.length;t++)this.use(e[t]);else{if(\"function\"!=typeof e)throw new TypeError(\"plugin must be a Function or an Array of Functions\");e(this)}return this},addRule:function(e,t){return this.rules.add(e,t),this},keep:function(e){return this.rules.keep(e),this},remove:function(e){return this.rules.remove(e),this},escape:function(e){return ta.reduce(function(e,t){return e.replace(t[0],t[1])},e)}};var ia=function(){return!1},oa=function(e){return e},sa=/\\s{2,}(?![^<>]*<\\/(pre|code|textarea)>)/g;function ua(e){return e.replace(sa,\" \").trim()}var ca=\"\\t\\n\\v\\f\\r   ᠎             　\\u2028\\u2029\\ufeff\",la=\"[\"+ca+\"]\",fa=RegExp(\"^\"+la+la+\"*\"),ha=RegExp(la+la+\"*$\"),da=function(e,t,n){var r={},a=g(function(){return!!ca[e]()||\"​\"!=\"​\"[e]()}),i=r[e]=a?t(pa):ca[e];n&&(r[n]=i),L(L.P+L.F*a,\"String\",r)},pa=da.trim=function(e,t){return e=String(u(e)),1&t&&(e=e.replace(fa,\"\")),2&t&&(e=e.replace(ha,\"\")),e},ma=da,ga=y.parseInt,va=ma.trim,ya=/^[-+]?0[xX]/,_a=8!==ga(ca+\"08\")||22!==ga(ca+\"0x16\")?function(e,t){var n=va(String(e),3);return ga(n,t>>>0||(ya.test(n)?16:10))}:ga;L(L.G+L.F*(parseInt!=_a),{parseInt:_a});var ba=M.parseInt,wa=new RegExp(\"(page|paging|(p(a|g|ag)?(e|enum|ewanted|ing|ination)))?(=|/)([0-9]{1,3})\",\"i\"),Aa=/[a-z]/i,xa=/^[a-z]+$/i,ka=/^[0-9]+$/i,Ea=/charset=([\\w-]+)\\b/;function Sa(e){return e.split(\"#\")[0].replace(/\\/$/,\"\")}L(L.S,\"Array\",{isArray:ge});var Ma=M.Array.isArray;var Ta=function(e){if(Ma(e))return e},Ca=M.getIterator=function(e){var t=Vt(e);if(\"function\"!=typeof t)throw TypeError(e+\" is not iterable!\");return D(t.call(e))};var Da=function(e,t){var n=[],r=!0,a=!1,i=void 0;try{for(var o,s=Ca(e);!(r=(o=s.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){a=!0,i=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw i}}return n};var Oa=function(){throw new TypeError(\"Invalid attempt to destructure non-iterable instance\")};var ja=function(e,t){return Ta(e)||Da(e,t)||Oa()};function Na(e,t){var n=t||Mr.parse(e),r=n.protocol,a=n.host,i=n.path,h=!1,o=i.split(\"/\").reverse().reduce(function(e,t,n){var r,a,i,o,s=t;if(s.includes(\".\")){var u=s.split(\".\"),c=ja(u,2),l=c[0],f=c[1];xa.test(f)&&(s=l)}return wa.test(s)&&n<2&&(s=s.replace(wa,\"\")),0===n&&(h=Aa.test(s)),r=s,i=h,o=!0,(a=n)<2&&ka.test(r)&&r.length<3&&(o=!0),0===a&&\"index\"===r.toLowerCase()&&(o=!1),a<2&&r.length<3&&!i&&(o=!1),o&&e.push(s),e},[]);return\"\".concat(r,\"//\").concat(a).concat(o.reverse().join(\"/\"))}var za=new RegExp(\".( |$)\");function Pa(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:10;return e.trim().split(/\\s+/).slice(0,t).join(\" \")}function La(e){var t=\"utf-8\",n=Ea.exec(e);null!==n&&(e=ja(n,2)[1]);return ia(e)&&(t=e),t}var Ra=function(i){var o=0;return i=i.toString(),function(){var e=i.indexOf(\"\\r\\n\",o),t=i.indexOf(\"\\n\",o),n=i.indexOf(\"\\r\",o),r=[e,t,n].sort(function(e,t){return t<e?1:e<t?-1:0}).filter(function(e){return-1!==e})[0];if(void 0!==r)return s(r,r===e?2:1);var a=i.length;return a===o?null:s(a,0)};function s(e,t){var n=i.substr(o,e-o);return o=e+t,n}},Ya=/^[A-Z_]+(\\/\\d\\.\\d)? /,Wa=/^([A-Z_]+) (.+) [A-Z]+\\/(\\d)\\.(\\d)$/,qa=/^[A-Z]+\\/(\\d)\\.(\\d) (\\d{3}) (.*)$/,Ia=function(e,t){return n=function(e){e&&e._header&&(e=e._header);return e&&\"function\"==typeof e.toString?e.toString().trim():\"\"}(e),r=t,s=(o=n).indexOf(\"\\r\\n\"),i=-1===s?o:o.slice(0,s),r&&Ya.test(i)?Ha(n):null!==(a=i.match(Wa))?{method:a[1],url:a[2],version:{major:parseInt(a[3],10),minor:parseInt(a[4],10)},headers:Ha(n)}:null!==(a=i.match(qa))?{version:{major:parseInt(a[1],10),minor:parseInt(a[2],10)},statusCode:parseInt(a[3],10),statusMessage:a[4],headers:Ha(n)}:Ha(n);var n,r,a,i,o,s};function Ha(e){var t,n,r,a={},i=Ra(e),o=i();for(Ya.test(o)&&(o=i());o;)o=(\" \"!==o[0]&&\"\\t\"!==o[0]?(n&&Fa(n,r,a),t=o.indexOf(\":\"),n=o.substr(0,t),r=o.substr(t+1).trim()):r+=\" \"+o.trim(),i());return n&&Fa(n,r,a),a}function Fa(e,t,n){switch(e=e.toLowerCase()){case\"set-cookie\":void 0!==n[e]?n[e].push(t):n[e]=[t];break;case\"content-type\":case\"content-length\":case\"user-agent\":case\"referer\":case\"host\":case\"authorization\":case\"proxy-authorization\":case\"if-modified-since\":case\"if-unmodified-since\":case\"from\":case\"location\":case\"max-forwards\":case\"retry-after\":case\"etag\":case\"last-modified\":case\"server\":case\"age\":case\"expires\":void 0===n[e]&&(n[e]=t);break;default:\"string\"==typeof n[e]?n[e]+=\", \"+t:n[e]=t}}var Ba=XMLHttpRequest;if(!Ba)throw new Error(\"missing XMLHttpRequest\");Ga.log={trace:$a,debug:$a,info:$a,warn:$a,error:$a};function Ga(e,t){if(\"function\"!=typeof t)throw new Error(\"Bad callback given: \"+t);if(!e)throw new Error(\"No options given\");var n=e.onResponse;if((e=\"string\"==typeof e?{uri:e}:JSON.parse(JSON.stringify(e))).onResponse=n,e.verbose&&(Ga.log=function(){var e,t,n={},r=[\"trace\",\"debug\",\"info\",\"warn\",\"error\"];for(t=0;t<r.length;t++)n[e=r[t]]=$a,\"undefined\"!=typeof console&&console&&console[e]&&(n[e]=Va(console,e));return n}()),e.url&&(e.uri=e.url,delete e.url),!e.uri&&\"\"!==e.uri)throw new Error(\"options.uri is a required argument\");if(\"string\"!=typeof e.uri)throw new Error(\"options.uri must be a string\");for(var r=[\"proxy\",\"_redirectsFollowed\",\"maxRedirects\",\"followRedirect\"],a=0;a<r.length;a++)if(e[r[a]])throw new Error(\"options.\"+r[a]+\" is not supported\");if(e.callback=t,e.method=e.method||\"GET\",e.headers=e.headers||{},e.body=e.body||null,e.timeout=e.timeout||Ga.DEFAULT_TIMEOUT,e.headers.host)throw new Error(\"Options.headers.host is not supported\");e.json&&(e.headers.accept=e.headers.accept||\"application/json\",\"GET\"!==e.method&&(e.headers[\"content-type\"]=\"application/json\"),\"boolean\"!=typeof e.json?e.body=JSON.stringify(e.json):\"string\"!=typeof e.body&&(e.body=JSON.stringify(e.body)));var i=function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+\"=\"+encodeURIComponent(e[n]));return t.join(\"&\")};if(e.qs){var o=\"string\"==typeof e.qs?e.qs:i(e.qs);-1!==e.uri.indexOf(\"?\")?e.uri=e.uri+\"&\"+o:e.uri=e.uri+\"?\"+o}if(e.form){if(\"string\"==typeof e.form)throw\"form name unsupported\";if(\"POST\"===e.method){var s=(e.encoding||\"application/x-www-form-urlencoded\").toLowerCase();switch(e.headers[\"content-type\"]=s){case\"application/x-www-form-urlencoded\":e.body=i(e.form).replace(/%20/g,\"+\");break;case\"multipart/form-data\":var u=function(e){var t={};t.boundry=\"-------------------------------\"+Math.floor(1e9*Math.random());var n=[];for(var r in e)e.hasOwnProperty(r)&&n.push(\"--\"+t.boundry+'\\nContent-Disposition: form-data; name=\"'+r+'\"\\n\\n'+e[r]+\"\\n\");return n.push(\"--\"+t.boundry+\"--\"),t.body=n.join(\"\"),t.length=t.body.length,t.type=\"multipart/form-data; boundary=\"+t.boundry,t}(e.form);e.body=u.body,e.headers[\"content-type\"]=u.type;break;default:throw new Error(\"unsupported encoding:\"+s)}}}return e.onResponse=e.onResponse||$a,!0===e.onResponse&&(e.onResponse=t,e.callback=$a),!e.headers.authorization&&e.auth&&(e.headers.authorization=\"Basic \"+function(e){var t,n,r,a,i,o,s,u,c=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",l=0,f=0,h=\"\",d=[];if(!e)return e;for(;t=e.charCodeAt(l++),n=e.charCodeAt(l++),r=e.charCodeAt(l++),a=(u=t<<16|n<<8|r)>>18&63,i=u>>12&63,o=u>>6&63,s=63&u,d[f++]=c.charAt(a)+c.charAt(i)+c.charAt(o)+c.charAt(s),l<e.length;);switch(h=d.join(\"\"),e.length%3){case 1:h=h.slice(0,-2)+\"==\";break;case 2:h=h.slice(0,-1)+\"=\"}return h}(e.auth.username+\":\"+e.auth.password)),function(n){var r=new Ba,a=!1,t=function(e){var t,n=/^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/;try{t=location.href}catch(e){(t=document.createElement(\"a\")).href=\"\",t=t.href}var r=n.exec(t.toLowerCase())||[],a=n.exec(e.toLowerCase());return!(!a||a[1]==r[1]&&a[2]==r[2]&&(a[3]||(\"http:\"===a[1]?80:443))==(r[3]||(\"http:\"===r[1]?80:443)))}(n.uri),e=\"withCredentials\"in r;if(Ua+=1,r.seq_id=Ua,r.id=Ua+\": \"+n.method+\" \"+n.uri,r._id=r.id,t&&!e){var i=new Error(\"Browser does not support cross-origin request: \"+n.uri);return i.cors=\"unsupported\",n.callback(i,r)}r.timeoutTimer=setTimeout(function(){a=!0;var e=new Error(\"ETIMEDOUT\");return e.code=\"ETIMEDOUT\",e.duration=n.timeout,Ga.log.error(\"Timeout\",{id:r._id,milliseconds:n.timeout}),n.callback(e,r)},n.timeout);var o={response:!1,loading:!1,end:!1};r.onreadystatechange=function(e){if(a)return Ga.log.debug(\"Ignoring timed out state change\",{state:r.readyState,id:r.id});if(Ga.log.debug(\"State change\",{state:r.readyState,id:r.id,timed_out:a}),r.readyState===Ba.OPENED)for(var t in Ga.log.debug(\"Request started\",{id:r.id}),n.headers)r.setRequestHeader(t,n.headers[t]);else r.readyState===Ba.HEADERS_RECEIVED?s():r.readyState===Ba.LOADING?(s(),u()):r.readyState===Ba.DONE&&(s(),u(),function(){if(!o.end){if(o.end=!0,Ga.log.debug(\"Request done\",{id:r.id}),r.body=r.responseText,r.headers=Ia(r.getAllResponseHeaders()),n.json)try{r.body=JSON.parse(r.responseText)}catch(e){return n.callback(e,r)}n.callback(null,r,r.body)}}())},r.open(n.method,n.uri,!0),t&&(r.withCredentials=!!n.withCredentials);return r.send(n.body),r;function s(){if(!o.response){if(o.response=!0,Ga.log.debug(\"Got response\",{id:r.id,status:r.status}),clearTimeout(r.timeoutTimer),r.statusCode=r.status,t&&0==r.statusCode){var e=new Error(\"CORS request rejected: \"+n.uri);return e.cors=\"rejected\",o.loading=!0,o.end=!0,n.callback(e,r)}n.onResponse(null,r)}}function u(){o.loading||(o.loading=!0,Ga.log.debug(\"Response body loading\",{id:r.id}))}}(e)}var Ua=0;Ga.withCredentials=!1,Ga.DEFAULT_TIMEOUT=18e4,Ga.defaults=function(a,e){var t=function(r){return function(e,t){for(var n in e=\"string\"==typeof e?{uri:e}:JSON.parse(JSON.stringify(e)),a)void 0===e[n]&&(e[n]=a[n]);return r(e,t)}},n=t(Ga);return n.get=t(Ga.get),n.post=t(Ga.post),n.put=t(Ga.put),n.head=t(Ga.head),n};function $a(){}function Va(n,r){return function(e,t){\"object\"==typeof t&&(e+=\" \"+JSON.stringify(t));return n[r].call(n,e)}}[\"get\",\"put\",\"post\",\"head\"].forEach(function(e){var n=e.toUpperCase();Ga[e.toLowerCase()]=function(e){\"string\"==typeof e?e={method:n,uri:e}:(e=JSON.parse(JSON.stringify(e))).method=n;var t=[e].concat(Array.prototype.slice.apply(arguments,[1]));return Ga.apply(this,t)}}),Ga.couch=function(e,a){return\"string\"==typeof e&&(e={uri:e}),e.json=!0,e.body&&(e.json=e.body),delete e.body,a=a||$a,Ga(e,function(e,t,n){if(e)return a(e,t,n);if((t.statusCode<200||299<t.statusCode)&&n.error){for(var r in e=new Error(\"CouchDB error: \"+(n.error.reason||n.error.error)),n)e[r]=n[r];return a(e,t,n)}return a(e,t,n)})};var Ja=Ga,Ka=Cr.browser?{}:{\"User-Agent\":\"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36\"},Xa=1e4,Za=new RegExp(\"^(\".concat([\"audio/mpeg\",\"image/gif\",\"image/jpeg\",\"image/jpg\"].join(\"|\"),\")$\"),\"i\"),Qa=5242880;function ei(e){return new Xn(function(r,a){Ja(e,function(e,t,n){e?a(e):r({body:n,response:t})})})}function ti(e){var t=1<arguments.length&&void 0!==arguments[1]&&arguments[1];if(e.statusMessage&&\"OK\"!==e.statusMessage||200!==e.statusCode){if(!e.statusCode)throw new Error(\"Unable to fetch content. Original exception was \".concat(e.error));if(!t)throw new Error(\"Resource returned a response status code of \".concat(e.statusCode,\" and resource was instructed to reject non-200 status codes.\"))}var n=e.headers,r=n[\"content-type\"],a=n[\"content-length\"];if(Za.test(r))throw new Error(\"Content-type for this resource was \".concat(r,\" and is not allowed.\"));if(Qa<a)throw new Error(\"Content for this resource was too large. Maximum content length is \".concat(Qa,\".\"));return!0}function ni(e,t){return ri.apply(this,arguments)}function ri(){return(ri=Qn(S.mark(function e(t,n){var r,a,i,o,s,u=arguments;return S.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return r=2<u.length&&void 0!==u[2]?u[2]:{},n=n||Mr.parse(encodeURI(t)),a=pt({url:n.href,headers:pt({},Ka,r),timeout:Xa,jar:!0,encoding:null,gzip:!0,followAllRedirects:!0},\"undefined\"!=typeof window?{}:{followRedirect:!0}),e.next=5,ei(a);case 5:return i=e.sent,o=i.response,s=i.body,e.prev=8,ti(o),e.abrupt(\"return\",{body:s,response:o});case 13:return e.prev=13,e.t0=e.catch(8),e.abrupt(\"return\",{error:!0,message:e.t0.message});case 16:case\"end\":return e.stop()}},e,this,[[8,13]])}))).apply(this,arguments)}function ai(a,i,o){return a(\"meta[\".concat(i,\"]\")).each(function(e,t){var n=a(t),r=n.attr(i);n.attr(o,r),n.removeAttr(i)}),a}var ii=y.Reflect,oi=ii&&ii.ownKeys||function(e){var t=Se.f(D(e)),n=me.f;return n?t.concat(n(e)):t};L(L.S,\"Reflect\",{ownKeys:oi});var si=M.Reflect.ownKeys,ui=new RegExp(\"transparent|spacer|blank\",\"i\"),ci=\"mercury-parser-keep\",li=['iframe[src^=\"https://www.youtube.com\"]','iframe[src^=\"https://www.youtube-nocookie.com\"]','iframe[src^=\"http://www.youtube.com\"]','iframe[src^=\"https://player.vimeo\"]','iframe[src^=\"http://player.vimeo\"]','iframe[src^=\"https://www.redditmedia.com\"]'],fi=[\"title\",\"script\",\"noscript\",\"link\",\"style\",\"hr\",\"embed\",\"iframe\",\"object\"],hi=new RegExp(\"^(\".concat([\"src\",\"srcset\",\"sizes\",\"type\",\"href\",\"class\",\"id\",\"alt\",\"xlink:href\",\"width\",\"height\"].join(\"|\"),\")$\"),\"i\"),di=[\"ul\",\"ol\",\"table\",\"div\",\"button\",\"form\"].join(\",\"),pi=[\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"].join(\",\"),mi=[\"a\",\"blockquote\",\"dl\",\"div\",\"img\",\"p\",\"pre\",\"table\"].join(\",\"),gi=new RegExp([\"article\",\"articlecontent\",\"instapaper_body\",\"blog\",\"body\",\"content\",\"entry-content-asset\",\"entry\",\"hentry\",\"main\",\"Normal\",\"page\",\"pagination\",\"permalink\",\"post\",\"story\",\"text\",\"[-_]copy\",\"\\\\Bcopy\"].join(\"|\"),\"i\"),vi=new RegExp([\"adbox\",\"advert\",\"author\",\"bio\",\"bookmark\",\"bottom\",\"byline\",\"clear\",\"com-\",\"combx\",\"comment\",\"comment\\\\B\",\"contact\",\"copy\",\"credit\",\"crumb\",\"date\",\"deck\",\"excerpt\",\"featured\",\"foot\",\"footer\",\"footnote\",\"graf\",\"head\",\"info\",\"infotext\",\"instapaper_ignore\",\"jump\",\"linebreak\",\"link\",\"masthead\",\"media\",\"meta\",\"modal\",\"outbrain\",\"promo\",\"pr_\",\"related\",\"respond\",\"roundcontent\",\"scroll\",\"secondary\",\"share\",\"shopping\",\"shoutbox\",\"side\",\"sidebar\",\"sponsor\",\"stamp\",\"sub\",\"summary\",\"tags\",\"tools\",\"widget\"].join(\"|\"),\"i\"),yi=\"meta[name=generator][value^=WordPress]\",_i=new RegExp(\"pag(e|ing|inat)\",\"i\"),bi=new RegExp(\"^(\".concat([\"article\",\"aside\",\"blockquote\",\"body\",\"br\",\"button\",\"canvas\",\"caption\",\"col\",\"colgroup\",\"dd\",\"div\",\"dl\",\"dt\",\"embed\",\"fieldset\",\"figcaption\",\"figure\",\"footer\",\"form\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"hgroup\",\"hr\",\"li\",\"map\",\"object\",\"ol\",\"output\",\"p\",\"pre\",\"progress\",\"section\",\"table\",\"tbody\",\"textarea\",\"tfoot\",\"th\",\"thead\",\"tr\",\"ul\",\"video\"].join(\"|\"),\")$\"),\"i\"),wi=[\"ad-break\",\"adbox\",\"advert\",\"addthis\",\"agegate\",\"aux\",\"blogger-labels\",\"combx\",\"comment\",\"conversation\",\"disqus\",\"entry-unrelated\",\"extra\",\"foot\",\"header\",\"hidden\",\"loader\",\"login\",\"menu\",\"meta\",\"nav\",\"outbrain\",\"pager\",\"pagination\",\"predicta\",\"presence_control_external\",\"popup\",\"printfriendly\",\"related\",\"remove\",\"remark\",\"rss\",\"share\",\"shoutbox\",\"sidebar\",\"sociable\",\"sponsor\",\"taboola\",\"tools\"].join(\"|\"),Ai=new RegExp(wi,\"i\"),xi=[\"and\",\"article\",\"body\",\"blogindex\",\"column\",\"content\",\"entry-content-asset\",\"format\",\"hfeed\",\"hentry\",\"hatom\",\"main\",\"page\",\"posts\",\"shadow\"].join(\"|\"),ki=new RegExp(xi,\"i\");function Ei(a){var i=!1;return a(\"br\").each(function(e,t){var n=a(t),r=n.next().get(0);r&&\"br\"===r.tagName.toLowerCase()?(i=!0,n.remove()):i&&function(e,t){var n=2<arguments.length&&void 0!==arguments[2]&&arguments[2],r=t(e);if(n){for(var a=e.nextSibling,i=t(\"<p></p>\");a&&(!a.tagName||!bi.test(a.tagName));){var o=a,s=o.nextSibling;t(a).appendTo(i),a=s}return r.replaceWith(i),r.remove()}}(t,a,!(i=!1))}),a}function Si(e){var r,a;return e=Ei(e),(r=e)(\"div\").each(function(e,t){var n=r(t);0===n.children(mi).length&&Mi(n,r,\"p\")}),(a=e=r)(\"span\").each(function(e,t){var n=a(t);0===n.parents(\"p, div\").length&&Mi(n,a,\"p\")}),e=a}function Mi(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:\"p\",r=e.get(0);if(!r)return t;var a,i=ns(r)||{},o=si(i).map(function(e){return\"\".concat(e,\"=\").concat(i[e])}).join(\" \");return a=t.browser?\"noscript\"===r.tagName.toLowerCase()?e.text():e.html():e.contents(),e.replaceWith(\"<\".concat(n,\" \").concat(o,\">\").concat(a,\"</\").concat(n,\">\")),t}function Ti(e,s){return e.find(\"img\").each(function(e,t){var n,r,a,i,o=s(t);r=ba((n=o).attr(\"height\"),10),a=ba(n.attr(\"width\"),10)||20,(r||20)<10||a<10?n.remove():r&&n.removeAttr(\"height\"),i=o,ui.test(i.attr(\"src\"))&&i.remove()}),s}var Ci=function(e){if(Ma(e)){for(var t=0,n=new Array(e.length);t<e.length;t++)n[t]=e[t];return n}},Di=function(e,t,n){t in e?j.f(e,t,A(0,n)):e[t]=n};L(L.S+L.F*!Dn(function(e){}),\"Array\",{from:function(e){var t,n,r,a,i=ct(e),o=\"function\"==typeof this?this:Array,s=arguments.length,u=1<s?arguments[1]:void 0,c=void 0!==u,l=0,f=Vt(i);if(c&&(u=C(u,2<s?arguments[2]:void 0,2)),null==f||o==Array&&Ut(f))for(n=new o(t=ie(i.length));l<t;l++)Di(n,l,c?u(i[l],l):i[l]);else for(a=f.call(i),n=new o;!(r=a.next()).done;l++)Di(n,l,c?Ft(a,u,[r.value,l],!0):r.value);return n.length=l,n}});var Oi=M.Array.from,ji=V(\"iterator\"),Ni=M.isIterable=function(e){var t=Object(e);return void 0!==t[ji]||\"@@iterator\"in t||vt.hasOwnProperty(It(t))};var zi=function(e){if(Ni(Object(e))||\"[object Arguments]\"===Object.prototype.toString.call(e))return Oi(e)};var Pi=function(){throw new TypeError(\"Invalid attempt to spread non-iterable instance\")};var Li=function(e){return Ci(e)||zi(e)||Pi()};function Ri(e,t){return e.find(\"*\").each(function(e,t){var n=ns(t);!function(t,n){if(t.attribs)t.attribs=n;else if(t.attributes){for(;0<t.attributes.length;)t.removeAttribute(t.attributes[0].name);si(n).forEach(function(e){t.setAttribute(e,n[e])})}}(t,si(n).reduce(function(e,t){return hi.test(t)?pt({},e,dt({},t,n[t])):e},{}))}),t(\".\".concat(ci),e).removeClass(ci),e}var Yi=new RegExp(\"^(\".concat([\"br\",\"b\",\"i\",\"label\",\"hr\",\"area\",\"base\",\"basefont\",\"input\",\"img\",\"link\",\"meta\"].join(\"|\"),\")$\"),\"i\"),Wi=[[\".hentry\",\".entry-content\"],[\"entry\",\".entry-content\"],[\".entry\",\".entry_content\"],[\".post\",\".postbody\"],[\".post\",\".post_body\"],[\".post\",\".post-body\"]],qi=new RegExp([\"figure\",\"photo\",\"image\",\"caption\"].join(\"|\"),\"i\"),Ii=new RegExp([\"article\",\"articlecontent\",\"instapaper_body\",\"blog\",\"body\",\"content\",\"entry-content-asset\",\"entry\",\"hentry\",\"main\",\"Normal\",\"page\",\"pagination\",\"permalink\",\"post\",\"story\",\"text\",\"[-_]copy\",\"\\\\Bcopy\"].join(\"|\"),\"i\"),Hi=new RegExp(\"entry-content-asset\",\"i\"),Fi=new RegExp([\"adbox\",\"advert\",\"author\",\"bio\",\"bookmark\",\"bottom\",\"byline\",\"clear\",\"com-\",\"combx\",\"comment\",\"comment\\\\B\",\"contact\",\"copy\",\"credit\",\"crumb\",\"date\",\"deck\",\"excerpt\",\"featured\",\"foot\",\"footer\",\"footnote\",\"graf\",\"head\",\"info\",\"infotext\",\"instapaper_ignore\",\"jump\",\"linebreak\",\"link\",\"masthead\",\"media\",\"meta\",\"modal\",\"outbrain\",\"promo\",\"pr_\",\"related\",\"respond\",\"roundcontent\",\"scroll\",\"secondary\",\"share\",\"shopping\",\"shoutbox\",\"side\",\"sidebar\",\"sponsor\",\"stamp\",\"sub\",\"summary\",\"tags\",\"tools\",\"widget\"].join(\"|\"),\"i\"),Bi=new RegExp(\"^(p|li|span|pre)$\",\"i\"),Gi=new RegExp(\"^(td|blockquote|ol|ul|dl)$\",\"i\"),Ui=new RegExp(\"^(address|form)$\",\"i\");function $i(e){var t=e.attr(\"class\"),n=e.attr(\"id\"),r=0;return n&&(Ii.test(n)&&(r+=25),Fi.test(n)&&(r-=25)),t&&(0===r&&(Ii.test(t)&&(r+=25),Fi.test(t)&&(r-=25)),qi.test(t)&&(r+=10),Hi.test(t)&&(r+=25)),r}var Vi=y.parseFloat,Ji=ma.trim,Ki=1/Vi(ca+\"-0\")!=-1/0?function(e){var t=Ji(String(e),3),n=Vi(t);return 0===n&&\"-\"==t.charAt(0)?-0:n}:Vi;L(L.G+L.F*(parseFloat!=Ki),{parseFloat:Ki});var Xi=M.parseFloat;function Zi(e){return Xi(e.attr(\"score\"))||null}function Qi(e){return(e.match(/,/g)||[]).length}var eo=new RegExp(\"^(p|pre)$\",\"i\");function to(e){var t=1,n=e.text().trim(),r=n.length;return r<25?0:(t+=Qi(n),t+=function(e){var t,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:\"p\",r=e/50;return 0<r?(t=eo.test(n)?r-2:r-1.25,Math.min(Math.max(t,0),3)):0}(r),\":\"===n.slice(-1)&&(t-=1),t)}function no(e,t,n){return e.attr(\"score\",n),e}function ro(e,t,n){try{no(e,0,ao(e,t)+n)}catch(e){}return e}function ao(e,t){var n,r,a,i=!(2<arguments.length&&void 0!==arguments[2])||arguments[2],o=Zi(e);return o||(o=io(e),i&&(o+=$i(e)),n=t,r=o,(a=e.parent())&&ro(a,n,.25*r),o)}function io(e){var t=e.get(0).tagName;return Bi.test(t)?to(e):\"div\"===t.toLowerCase()?5:Gi.test(t)?3:Ui.test(t)?-3:\"th\"===t.toLowerCase()?-5:0}function oo(e,t,n){var r,a;e&&(a=t,(r=e).get(0)&&\"span\"===r.get(0).tagName&&Mi(r,a,\"div\"),ro(e,t,n))}function so(i,o){return i(\"p, pre\").not(\"[score]\").each(function(e,t){var n=i(t),r=(n=no(n,0,ao(n,i,o))).parent(),a=io(n);oo(r,i,a),r&&oo(r.parent(),i,a/2)}),i}function uo(c,l,f){if(!c.parent().length)return c;var h=Math.max(10,.25*l),d=f(\"<div></div>\");return c.parent().children().each(function(e,t){var n=f(t);if(Yi.test(t.tagName))return null;var r,a=Zi(n);if(a)if(n.get(0)===c.get(0))d.append(n);else{var i=0,o=$o(n);if(o<.05&&(i+=20),.5<=o&&(i-=20),n.attr(\"class\")===c.attr(\"class\")&&(i+=.2*l),h<=a+i)return d.append(n);if(\"p\"===t.tagName){var s=n.text(),u=Uo(s);if(80<u&&o<.25)return d.append(n);if(u<=80&&0===o&&(r=s,za.test(r)))return d.append(n)}}return null}),1===d.children().length&&d.children().first().get(0)===c.get(0)?c:d}function co(e,a){return a(di,e).each(function(e,t){var n=a(t);if(!(n.hasClass(ci)||0<n.find(\".\".concat(ci)).length)){var r=Zi(n);r||no(n,0,r=ao(n,a)),r<0?n.remove():function(e,t,n){if(!e.hasClass(\"entry-content-asset\")){var r=ua(e.text());if(Qi(r)<10){if(t(\"p\",e).length/3<t(\"input\",e).length)return e.remove();var a=r.length,i=t(\"img\",e).length;if(a<25&&0===i)return e.remove();var o=$o(e);if(n<25&&.2<o&&75<a)return e.remove();if(25<=n&&.5<o){var s=e.get(0).tagName.toLowerCase();if(\"ol\"===s||\"ul\"===s){var u=e.prev();if(u&&\":\"===ua(u.text()).slice(-1))return}return e.remove()}0<t(\"script\",e).length&&a<150&&e.remove()}}}(n,a,r)}}),a}var lo,fo,ho,po,mo,go,vo,yo,_o,bo,wo,Ao,xo,ko,Eo,So,Mo,To,Co,Do,Oo,jo=function(e,t){if(!l(e)||e._t!==t)throw TypeError(\"Incompatible receiver, \"+t+\" required!\");return e},No=j.f,zo=U.fastKey,Po=v?\"_s\":\"size\",Lo=function(e,t){var n,r=zo(t);if(\"F\"!==r)return e._i[r];for(n=e._f;n;n=n.n)if(n.k==t)return n},Ro={getConstructor:function(e,i,n,r){var a=e(function(e,t){Ht(e,a,i,\"_i\"),e._t=i,e._i=ke(null),e._f=void 0,e._l=void 0,e[Po]=0,null!=t&&Jt(t,n,e[r],e)});return wn(a.prototype,{clear:function(){for(var e=jo(this,i),t=e._i,n=e._f;n;n=n.n)n.r=!0,n.p&&(n.p=n.p.n=void 0),delete t[n.i];e._f=e._l=void 0,e[Po]=0},delete:function(e){var t=jo(this,i),n=Lo(t,e);if(n){var r=n.n,a=n.p;delete t._i[n.i],n.r=!0,a&&(a.n=r),r&&(r.p=a),t._f==n&&(t._f=r),t._l==n&&(t._l=a),t[Po]--}return!!n},forEach:function(e){jo(this,i);for(var t,n=C(e,1<arguments.length?arguments[1]:void 0,3);t=t?t.n:this._f;)for(n(t.v,t.k,this);t&&t.r;)t=t.p},has:function(e){return!!Lo(jo(this,i),e)}}),v&&No(a.prototype,\"size\",{get:function(){return jo(this,i)[Po]}}),a},def:function(e,t,n){var r,a,i=Lo(e,t);return i?i.v=n:(e._l=i={i:a=zo(t,!0),k:t,v:n,p:r=e._l,n:void 0,r:!1},e._f||(e._f=i),r&&(r.n=i),e[Po]++,\"F\"!==a&&(e._i[a]=i)),e},getEntry:Lo,setStrong:function(e,n,t){Mt(e,n,function(e,t){this._t=jo(e,n),this._k=t,this._l=void 0},function(){for(var e=this._k,t=this._l;t&&t.r;)t=t.p;return this._t&&(this._l=t=t?t.n:this._t._f)?Ct(0,\"keys\"==e?t.k:\"values\"==e?t.v:[t.k,t.v]):(this._t=void 0,Ct(1))},t?\"entries\":\"values\",!t,!0),xn(n)}},Yo=V(\"species\"),Wo=function(e,t){return ge(n=e)&&(\"function\"!=typeof(r=n.constructor)||r!==Array&&!ge(r.prototype)||(r=void 0),l(r)&&null===(r=r[Yo])&&(r=void 0)),new(void 0===r?Array:r)(t);var n,r},qo=j.f,Io=(ho=1==(lo=0),po=2==lo,mo=3==lo,go=4==lo,vo=6==lo,yo=5==lo||vo,_o=fo||Wo,function(e,t,n){for(var r,a,i=ct(e),o=h(i),s=C(t,n,3),u=ie(o.length),c=0,l=ho?_o(e,u):po?_o(e,0):void 0;c<u;c++)if((yo||c in o)&&(a=s(r=o[c],c,i),lo))if(ho)l[c]=a;else if(a)switch(lo){case 3:return!0;case 5:return r;case 6:return c;case 2:l.push(r)}else if(go)return!1;return vo?-1:mo||go?go:l});wo=function(e){return function(){return e(this,0<arguments.length?arguments[0]:void 0)}},Ao={add:function(e){return Ro.def(jo(this,\"Set\"),e=0===e?0:e,e)}},xo=Ro,So=y[bo=\"Set\"],To=ko?\"set\":\"add\",Co=(Mo=So)&&Mo.prototype,Do={},v&&\"function\"==typeof Mo&&(Eo||Co.forEach&&!g(function(){(new Mo).entries().next()}))?(Mo=wo(function(e,t){Ht(e,Mo,bo,\"_c\"),e._c=new So,null!=t&&Jt(t,ko,e[To],e)}),Io(\"add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON\".split(\",\"),function(r){var a=\"add\"==r||\"set\"==r;r in Co&&(!Eo||\"clear\"!=r)&&N(Mo.prototype,r,function(e,t){if(Ht(this,Mo,r),!a&&Eo&&!l(e))return\"get\"==r&&void 0;var n=this._c[r](0===e?0:e,t);return a?this:n})}),Eo||qo(Mo.prototype,\"size\",{get:function(){return this._c.size}})):(Mo=xo.getConstructor(wo,bo,ko,To),wn(Mo.prototype,Ao),U.NEED=!0),X(Mo,bo),Do[bo]=Mo,L(L.G+L.W+L.F,Do),Eo||xo.setStrong(Mo,bo,ko);L(L.P+L.R,\"Set\",{toJSON:(Oo=\"Set\",function(){if(It(this)!=Oo)throw TypeError(Oo+\"#toJSON isn't generic\");return Jt(this,!(t=[]),t.push,t,e),t;var e,t})});var Ho;Ho=\"Set\",L(L.S,Ho,{of:function(){for(var e=arguments.length,t=new Array(e);e--;)t[e]=arguments[e];return new this(t)}});var Fo;Fo=\"Set\",L(L.S,Fo,{from:function(e){var t,n,r,a,i=arguments[1];return T(this),(t=void 0!==i)&&T(i),null==e?new this:(n=[],t?(r=0,a=C(i,arguments[2],2),Jt(e,!1,function(e){n.push(a(e,r++))})):Jt(e,!1,n.push,n),new this(n))}});var Bo=M.Set;function Go(e,n,r){var i;return[\"href\",\"src\"].forEach(function(e){return a=r,i=e,o=(t=n)(\"base\").attr(\"href\"),void t(\"[\".concat(i,\"]\")).each(function(e,t){var n=ns(t)[i];if(n){var r=Mr.resolve(o||a,n);rs(t,i,r)}});var t,a,i,o}),i=r,n(\"[srcset]\",e).each(function(e,t){var n=ns(t).srcset;if(n){var r=n.match(/(?:\\s*)(\\S+(?:\\s*[\\d.]+[wx])?)(?:\\s*,\\s*)?/g);if(!r)return;var a=r.map(function(e){var t=e.trim().replace(/,$/,\"\").split(/\\s+/);return t[0]=Mr.resolve(i,t[0]),t.join(\" \")});rs(t,\"srcset\",Li(new Bo(a)).join(\", \"))}}),e}function Uo(e){return e.trim().replace(/\\s+/g,\" \").length}function $o(e){var t=Uo(e.text()),n=Uo(e.find(\"a\").text());return 0<t?n/t:0===t&&0<n?1:0}var Vo=Z.f(\"iterator\");ee(\"asyncIterator\"),ee(\"observable\");var Jo=M.Symbol,Ko=e(function(t){function n(e){return(n=\"function\"==typeof Jo&&\"symbol\"==typeof Vo?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Jo&&e.constructor===Jo&&e!==Jo.prototype?\"symbol\":typeof e})(e)}function r(e){return\"function\"==typeof Jo&&\"symbol\"===n(Vo)?t.exports=r=function(e){return n(e)}:t.exports=r=function(e){return e&&\"function\"==typeof Jo&&e.constructor===Jo&&e!==Jo.prototype?\"symbol\":n(e)},r(e)}t.exports=r});function Xo(r,e,t){var a=!(3<arguments.length&&void 0!==arguments[3])||arguments[3],n=e.filter(function(e){return-1!==t.indexOf(e)}),i=!0,o=!1,s=void 0;try{for(var u,c=function(){var e=u.value,t=r(\"meta[\".concat(\"name\",'=\"').concat(e,'\"]')).map(function(e,t){return r(t).attr(\"value\")}).toArray().filter(function(e){return\"\"!==e});if(1===t.length){var n;if(a)n=es(t[0],r);else n=ja(t,1)[0];return{v:n}}},l=Ca(n);!(i=(u=l.next()).done);i=!0){var f=c();if(\"object\"===Ko(f))return f.v}}catch(e){o=!0,s=e}finally{try{i||null==l.return||l.return()}finally{if(o)throw s}}return null}function Zo(e,t){return!(e.children().length>t)&&void 0===e.parents().toArray().find(function(e){var t=ns(e),n=t.class,r=t.id,a=\"\".concat(n,\" \").concat(r);return a.includes(\"comment\")})}function Qo(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:1,r=!(3<arguments.length&&void 0!==arguments[3])||arguments[3],a=!0,i=!1,o=void 0;try{for(var s,u=Ca(t);!(a=(s=u.next()).done);a=!0){var c=e(s.value);if(1===c.length){var l=e(c[0]);if(Zo(l,n)){var f=void 0;if(f=r?l.text():l.html())return f}}}}catch(e){i=!0,o=e}finally{try{a||null==u.return||u.return()}finally{if(i)throw o}}return null}function es(e,t){var n=t(\"<span>\".concat(e,\"</span>\")).text();return\"\"===n?e:n}function ts(e){return 100<=e.text().trim().length}function ns(e){var t=e.attribs,r=e.attributes;return t||!r?t:si(r).reduce(function(e,t){var n=r[t];return n.name&&n.value&&(e[n.name]=n.value),e},{})}function rs(e,t,n){return e.attribs?e.attribs[t]=n:e.attributes&&e.setAttribute(t,n),e}var as=new RegExp(\"https?://\",\"i\"),is=\".(png|gif|jpe?g)\",os=new RegExp(\"\".concat(is),\"i\"),ss=new RegExp(\"\".concat(is,\"(\\\\?\\\\S+)?(\\\\s*[\\\\d.]+[wx])\"),\"i\"),us=[\"script\",\"style\",\"form\"].join(\",\");function cs(e,t){return\"comment\"===t.type}function ls(e){var t;return e(us).remove(),(t=e).root().find(\"*\").contents().filter(cs).remove(),e=t}var fs,hs={create:(fs=Qn(S.mark(function e(t,n,r){var a,i,o=arguments;return S.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(a=3<o.length&&void 0!==o[3]?o[3]:{},!n){e.next=6;break}i={body:n,response:{statusMessage:\"OK\",statusCode:200,headers:{\"content-type\":\"text/html\",\"content-length\":500}}},e.next=9;break;case 6:return e.next=8,ni(t,r,a);case 8:i=e.sent;case 9:if(i.error)return i.failed=!0,e.abrupt(\"return\",i);e.next=12;break;case 12:return e.abrupt(\"return\",this.generateDoc(i));case 13:case\"end\":return e.stop()}},e,this)})),function(e,t,n){return fs.apply(this,arguments)}),generateDoc:function(e){var t=e.body,n=e.response.headers[\"content-type\"],r=void 0===n?\"\":n;if(!r.includes(\"html\")&&!r.includes(\"text\"))throw new Error(\"Content does not appear to be text.\");var a,i=this.encodeDoc({content:t,contentType:r});if(0===i.root().children().length)throw new Error(\"No children, likely a bad parse.\");return i=ai(ai(i,\"content\",\"value\"),\"property\",\"name\"),(a=i)(\"img\").each(function(e,n){var r=ns(n);si(r).forEach(function(e){var t=r[e];\"srcset\"!==e&&as.test(t)&&ss.test(t)?a(n).attr(\"srcset\",t):\"src\"!==e&&\"srcset\"!==e&&as.test(t)&&os.test(t)&&a(n).attr(\"src\",t)})}),i=ls(i=a)},encodeDoc:function(e){var t=e.content,n=La(e.contentType),r=oa(t,n),a=Cr.load(r),i=a(Cr.browser?\"meta[http-equiv=content-type]\":\"meta[http-equiv=content-type i]\").attr(\"content\")||a(\"meta[charset]\").attr(\"charset\"),o=La(i);return i&&o!==n&&(r=oa(t,o),a=Cr.load(r)),a}},ds=S.mark(ps);function ps(){var t,n,r=arguments;return S.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:t=0<r.length&&void 0!==r[0]?r[0]:1,n=1<r.length&&void 0!==r[1]?r[1]:1;case 2:if(t<=n)return e.next=5,t+=1;e.next=7;break;case 5:e.next=2;break;case 7:case\"end\":return e.stop()}},ds,this)}var ms=Object.assign,gs=!ms||g(function(){var e={},t={},n=Symbol(),r=\"abcdefghijklmnopqrst\";return e[n]=7,r.split(\"\").forEach(function(e){t[e]=e}),7!=ms({},e)[n]||Object.keys(ms({},t)).join(\"\")!=r})?function(e,t){for(var n=ct(e),r=arguments.length,a=1,i=me.f,o=d.f;a<r;)for(var s,u=h(arguments[a++]),c=i?pe(u).concat(i(u)):pe(u),l=c.length,f=0;f<l;)o.call(u,s=c[f++])&&(n[s]=u[s]);return n}:ms;L(L.S+L.F,\"Object\",{assign:gs});var vs=M.Object.assign,ys=function(n,e){return e.reduce(function(e,t){return e[t]=n,e},{})};function _s(e){return e.supportedDomains?ys(e,[e.domain].concat(Li(e.supportedDomains))):ys(e,[e.domain])}var bs={};function ws(e){return e&&e.domain?(vs(bs,_s(e)),bs):{error:!0,message:\"Unable to add custom extractor. Invalid parameters.\"}}var As={domain:\"blogspot.com\",content:{selectors:[\".post-content noscript\"],clean:[],transforms:{noscript:\"div\"}},author:{selectors:[\".post-author-name\"]},title:{selectors:[\".post h2.title\"]},date_published:{selectors:[\"span.publishdate\"]}},xs={domain:\"nymag.com\",content:{selectors:[\"div.article-content\",\"section.body\",\"article.article\"],clean:[\".ad\",\".single-related-story\"],transforms:{h1:\"h2\",noscript:function(e,t){var n=t.browser?t(e.text()):e.children();return 1===n.length&&void 0!==n.get(0)&&\"img\"===n.get(0).tagName.toLowerCase()?\"figure\":null}}},title:{selectors:[\"h1.lede-feature-title\",\"h1.headline-primary\",\"h1\"]},author:{selectors:[\".by-authors\",\".lede-feature-author\"]},dek:{selectors:[\".lede-feature-teaser\"]},date_published:{selectors:[[\"time.article-timestamp[datetime]\",\"datetime\"],\"time.article-timestamp\"]}},ks={domain:\"www.apartmenttherapy.com\",title:{selectors:[\"h1.headline\"]},author:{selectors:[\".PostByline__name\"]},content:{selectors:[\"div.post__content\"],transforms:{'div[data-render-react-id=\"images/LazyPicture\"]':function(e,t){var n=JSON.parse(e.attr(\"data-props\")).sources[0].src,r=t(\"<img />\").attr(\"src\",n);e.replaceWith(r)}},clean:[]},date_published:{selectors:[[\".PostByline__timestamp[datetime]\",\"datetime\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:{selectors:[]},excerpt:{selectors:[]}},Es={domain:\"medium.com\",title:{selectors:[\"h1\",['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},content:{selectors:[\"article\"],transforms:{iframe:function(e){var t=/https:\\/\\/i.embed.ly\\/.+url=https:\\/\\/i\\.ytimg\\.com\\/vi\\/(\\w+)\\//,n=decodeURIComponent(e.attr(\"data-thumbnail\")),r=e.parents(\"figure\");if(t.test(n)){var a=n.match(t),i=ja(a,2),o=(i[0],i[1]);e.attr(\"src\",\"https://www.youtube.com/embed/\".concat(o));var s=r.find(\"figcaption\");r.empty().append([e,s])}else r.remove()},figure:function(e){if(!(0<e.find(\"iframe\").length)){var t=e.find(\"img\").slice(-1)[0],n=e.find(\"figcaption\");e.empty().append([t,n])}},img:function(e){ba(e.attr(\"width\"),10)<100&&e.remove()}},clean:[\"span\",\"svg\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:null,next_page_url:{selectors:[]},excerpt:{selectors:[]}},Ss={domain:\"www.msnbc.com\",title:{selectors:[\"h1\",\"h1.is-title-pane\"]},author:{selectors:[\".author\"]},date_published:{selectors:[['meta[name=\"DC.date.issued\"]',\"value\"]]},dek:{selectors:[['meta[name=\"description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".pane-node-body\"],transforms:{\".pane-node-body\":function(e,t){var n=ja(Ss.lead_image_url.selectors[0],2),r=n[0],a=n[1],i=t(r).attr(a);i&&e.prepend('<img src=\"'.concat(i,'\" />'))}},clean:[]}},Ms={domain:\"genius.com\",title:{selectors:[\"h1\"]},author:{selectors:[\"h2 a\"]},date_published:{selectors:[[\"meta[itemprop=page_data]\",\"value\",function(e){return JSON.parse(e).song.release_date}]]},dek:{selectors:[]},lead_image_url:{selectors:[[\"meta[itemprop=page_data]\",\"value\",function(e){return JSON.parse(e).song.album.cover_art_url}]]},content:{selectors:[\".lyrics\"],transforms:{},clean:[]}},Ts={domain:\"wired.jp\",title:{selectors:[\"h1.post-title\"]},author:{selectors:['p[itemprop=\"author\"]']},date_published:{selectors:[[\"time\",\"datetime\"]]},dek:{selectors:[\".post-intro\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"article.article-detail\"],transforms:{\"img[data-original]\":function(e){var t=e.attr(\"data-original\"),n=e.attr(\"src\"),r=Mr.resolve(n,t);e.attr(\"src\",r)}},clean:[\".post-category\",\"time\",\"h1.post-title\",\".social-area-syncer\"]}},Cs=Object.freeze({BloggerExtractor:As,NYMagExtractor:xs,WikipediaExtractor:{domain:\"wikipedia.org\",content:{selectors:[\"#mw-content-text\"],defaultCleaner:!1,transforms:{\".infobox img\":function(e){var t=e.parents(\".infobox\");0===t.children(\"img\").length&&t.prepend(e)},\".infobox caption\":\"figcaption\",\".infobox\":\"figure\"},clean:[\".mw-editsection\",\"figure tr, figure td, figure tbody\",\"#toc\",\".navbox\"]},author:\"Wikipedia Contributors\",title:{selectors:[\"h2.title\"]},date_published:{selectors:[\"#footer-info-lastmod\"]}},TwitterExtractor:{domain:\"twitter.com\",content:{transforms:{\".permalink[role=main]\":function(e,t){var n=e.find(\".tweet\"),r=t('<div id=\"TWEETS_GO_HERE\"></div>');r.append(n),e.replaceWith(r)},s:\"span\"},selectors:[\".permalink[role=main]\"],defaultCleaner:!1,clean:[\".stream-item-footer\",\"button\",\".tweet-details-fixer\"]},author:{selectors:[\".tweet.permalink-tweet .username\"]},date_published:{selectors:[[\".permalink-tweet ._timestamp[data-time-ms]\",\"data-time-ms\"]]}},NYTimesExtractor:{domain:\"www.nytimes.com\",title:{selectors:[\"h1.g-headline\",'h1[itemprop=\"headline\"]',\"h1.headline\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"],\".g-byline\",\".byline\"]},content:{selectors:[\"div.g-blocks\",\"article#story\"],transforms:{\"img.g-lazy\":function(e){var t=e.attr(\"src\");t=t.replace(\"{{size}}\",640),e.attr(\"src\",t)}},clean:[\".ad\",\"header#story-header\",\".story-body-1 .lede.video\",\".visually-hidden\",\"#newsletter-promo\",\".promo\",\".comments-button\",\".hidden\",\".comments\",\".supplemental\",\".nocontent\",\".story-footer-links\"]},date_published:{selectors:[['meta[name=\"article:published\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:null,next_page_url:null,excerpt:null},TheAtlanticExtractor:{domain:\"www.theatlantic.com\",title:{selectors:[\"h1\",\".c-article-header__hed\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"],\".c-byline__author\"]},content:{selectors:[\"article\",\".article-body\"],transforms:[],clean:[\".partner-box\",\".callout\",\".c-article-writer__image\",\".c-article-writer__content\",\".c-letters-cta__text\",\".c-footer__logo\",\".c-recirculation-link\",\".twitter-tweet\"]},dek:{selectors:[['meta[name=\"description\"]',\"value\"]]},date_published:{selectors:[['time[itemprop=\"datePublished\"]',\"datetime\"]]},lead_image_url:{selectors:[['img[itemprop=\"url\"]',\"src\"]]},next_page_url:null,excerpt:null},NewYorkerExtractor:{domain:\"www.newyorker.com\",title:{selectors:['h1[class^=\"ArticleHeader__hed\"]',['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:['div[class^=\"ArticleContributors\"] a[rel=\"author\"]','article header div[class*=\"Byline__multipleContributors\"]']},content:{selectors:['main[class^=\"Layout__content\"]'],transforms:[],clean:['footer[class^=\"ArticleFooter__footer\"]']},date_published:{selectors:[['meta[name=\"pubdate\"]',\"value\"]],format:\"YYYYMMDD\",timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:['h2[class^=\"ArticleHeader__dek\"]']},next_page_url:null,excerpt:null},WiredExtractor:{domain:\"www.wired.com\",title:{selectors:[\"h1.post-title\"]},author:{selectors:['a[rel=\"author\"]']},content:{selectors:[\"article.content\"],transforms:[],clean:[\".visually-hidden\",\"figcaption img.photo\"]},date_published:{selectors:[['meta[itemprop=\"datePublished\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:null,excerpt:null},MSNExtractor:{domain:\"www.msn.com\",title:{selectors:[\"h1\"]},author:{selectors:[\"span.authorname-txt\"]},content:{selectors:[\"div.richtext\"],transforms:[],clean:[\"span.caption\"]},date_published:{selectors:[\"span.time\"]},lead_image_url:{selectors:[]},dek:{selectors:[]},next_page_url:null,excerpt:null},YahooExtractor:{domain:\"www.yahoo.com\",title:{selectors:[\"header.canvas-header\"]},author:{selectors:[\"span.provider-name\"]},content:{selectors:[\".content-canvas\"],transforms:[],clean:[\".figure-caption\"]},date_published:{selectors:[[\"time.date[datetime]\",\"datetime\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:null,excerpt:null},BuzzfeedExtractor:{domain:\"www.buzzfeed.com\",title:{selectors:['h1[id=\"post-title\"]']},author:{selectors:['a[data-action=\"user/username\"]',\"byline__author\"]},content:{selectors:[[\".longform_custom_header_media\",\"#buzz_sub_buzz\"],\"#buzz_sub_buzz\"],defaultCleaner:!1,transforms:{h2:\"b\",\"div.longform_custom_header_media\":function(e){return e.has(\"img\")&&e.has(\".longform_header_image_source\")?\"figure\":null},\"figure.longform_custom_header_media .longform_header_image_source\":\"figcaption\"},clean:[\".instapaper_ignore\",\".suplist_list_hide .buzz_superlist_item .buzz_superlist_number_inline\",\".share-box\",\".print\"]},date_published:{selectors:[\".buzz-datetime\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:null,excerpt:null},WikiaExtractor:{domain:\"fandom.wikia.com\",title:{selectors:[\"h1.entry-title\"]},author:{selectors:[\".author vcard\",\".fn\"]},content:{selectors:[\".grid-content\",\".entry-content\"],transforms:[],clean:[]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:null,excerpt:null},LittleThingsExtractor:{domain:\"www.littlethings.com\",title:{selectors:[\"h1.post-title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},content:{selectors:[\".mainContentIntro\",\".content-wrapper\"],transforms:[],clean:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},next_page_url:null,excerpt:null},PoliticoExtractor:{domain:\"www.politico.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\".story-main-content .byline .vcard\"]},content:{selectors:[\".story-main-content\",\".content-group\",\".story-core\",\".story-text\"],transforms:[],clean:[\"figcaption\"]},date_published:{selectors:[[\".story-main-content .timestamp time[datetime]\",\"datetime\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:null,excerpt:null},DeadspinExtractor:{domain:\"deadspin.com\",supportedDomains:[\"jezebel.com\",\"lifehacker.com\",\"kotaku.com\",\"gizmodo.com\",\"jalopnik.com\",\"kinja.com\",\"avclub.com\",\"clickhole.com\",\"splinternews.com\",\"theonion.com\",\"theroot.com\",\"thetakeout.com\",\"theinventory.com\"],title:{selectors:[\"h1.headline\"]},author:{selectors:[\".author\"]},content:{selectors:[\".post-content\",\".entry-content\"],transforms:{'iframe.lazyload[data-recommend-id^=\"youtube://\"]':function(e){var t=e.attr(\"id\").split(\"youtube-\")[1];e.attr(\"src\",\"https://www.youtube.com/embed/\".concat(t))}},clean:[\".magnifier\",\".lightbox\"]},date_published:{selectors:[[\"time.updated[datetime]\",\"datetime\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:{selectors:[]},excerpt:{selectors:[]}},BroadwayWorldExtractor:{domain:\"www.broadwayworld.com\",title:{selectors:[\"h1.article-title\"]},author:{selectors:[\"span[itemprop=author]\"]},content:{selectors:[\"div[itemprop=articlebody]\"],transforms:{},clean:[]},date_published:{selectors:[[\"meta[itemprop=datePublished]\",\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},dek:{selectors:[]},next_page_url:{selectors:[]},excerpt:{selectors:[]}},ApartmentTherapyExtractor:ks,MediumExtractor:Es,WwwTmzComExtractor:{domain:\"www.tmz.com\",title:{selectors:[\".post-title-breadcrumb\",\"h1\",\".headline\"]},author:\"TMZ STAFF\",date_published:{selectors:[\".article-posted-date\"],timezone:\"America/Los_Angeles\"},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-content\",\".all-post-body\"],transforms:{},clean:[\".lightbox-link\"]}},WwwWashingtonpostComExtractor:{domain:\"www.washingtonpost.com\",title:{selectors:[\"h1\",\"#topper-headline-wrapper\"]},author:{selectors:[\".pb-author-name\"]},date_published:{selectors:[['.author-timestamp[itemprop=\"datePublished\"]',\"content\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-body\"],transforms:{\"div.inline-content\":function(e){return 0<e.has(\"img,iframe,video\").length?\"figure\":(e.remove(),null)},\".pb-caption\":\"figcaption\"},clean:[\".interstitial-link\",\".newsletter-inline-unit\"]}},WwwHuffingtonpostComExtractor:{domain:\"www.huffingtonpost.com\",title:{selectors:[\"h1.headline__title\"]},author:{selectors:[\"span.author-card__details__name\"]},date_published:{selectors:[['meta[name=\"article:modified_time\"]',\"value\"],['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\"h2.headline__subtitle\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.entry__body\"],defaultCleaner:!1,transforms:{},clean:[\".pull-quote\",\".tag-cloud\",\".embed-asset\",\".below-entry\",\".entry-corrections\",\"#suggested-story\"]}},NewrepublicComExtractor:{domain:\"newrepublic.com\",title:{selectors:[\"h1.article-headline\",\".minutes-primary h1.minute-title\"]},author:{selectors:[\"div.author-list\",\".minutes-primary h3.minute-byline\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]],timezone:\"America/New_York\"},dek:{selectors:[\"h2.article-subhead\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".article-cover\",\"div.content-body\"],[\".minute-image\",\".minutes-primary div.content-body\"]],transforms:{},clean:[\"aside\"]}},MoneyCnnComExtractor:{domain:\"money.cnn.com\",title:{selectors:[\".article-title\"]},author:{selectors:[\".byline a\"]},date_published:{selectors:[['meta[name=\"date\"]',\"value\"]],timezone:\"GMT\"},dek:{selectors:[\"#storytext h2\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#storytext\"],transforms:{},clean:[\".inStoryHeading\"]}},WwwThevergeComExtractor:{domain:\"www.theverge.com\",supportedDomains:[\"www.polygon.com\"],title:{selectors:[\"h1\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\"h2.p-dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".c-entry-hero .e-image\",\".c-entry-intro\",\".c-entry-content\"],[\".e-image--hero\",\".c-entry-content\"],\".l-wrapper .l-feature\",\"div.c-entry-content\"],transforms:{noscript:function(e){var t=e.children();return 1===t.length&&\"img\"===t.get(0).tagName?\"span\":null}},clean:[\".aside\",\"img.c-dynamic-image\"]}},WwwCnnComExtractor:{domain:\"www.cnn.com\",title:{selectors:[\"h1.pg-headline\",\"h1\"]},author:{selectors:[\".metadata__byline__author\"]},date_published:{selectors:[['meta[name=\"pubdate\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".media__video--thumbnail\",\".zn-body-text\"],\".zn-body-text\",'div[itemprop=\"articleBody\"]'],transforms:{\".zn-body__paragraph, .el__leafmedia--sourced-paragraph\":function(e){return e.html()?\"p\":null},\".zn-body__paragraph\":function(e){e.has(\"a\")&&e.text().trim()===e.find(\"a\").text().trim()&&e.remove()},\".media__video--thumbnail\":\"figure\"},clean:[]}},WwwAolComExtractor:{domain:\"www.aol.com\",title:{selectors:[\"h1.p-article__title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[\".p-article__byline__date\"],timezone:\"America/New_York\"},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-content\"],transforms:{},clean:[]}},WwwYoutubeComExtractor:{domain:\"www.youtube.com\",title:{selectors:[\".watch-title\",\"h1.watch-title-container\"]},author:{selectors:[\".yt-user-info\"]},date_published:{selectors:[['meta[itemProp=\"datePublished\"]',\"value\"]],timezone:\"GMT\"},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{defaultCleaner:!1,selectors:[[\"#player-api\",\"#eow-description\"]],transforms:{\"#player-api\":function(e,t){var n=t('meta[itemProp=\"videoId\"]').attr(\"value\");e.html('\\n          <iframe src=\"https://www.youtube.com/embed/'.concat(n,'\" frameborder=\"0\" allowfullscreen></iframe>'))}},clean:[]}},WwwTheguardianComExtractor:{domain:\"www.theguardian.com\",title:{selectors:[\".content__headline\"]},author:{selectors:[\"p.byline\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\".content__standfirst\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".content__article-body\"],transforms:{},clean:[\".hide-on-mobile\",\".inline-icon\"]}},WwwSbnationComExtractor:{domain:\"www.sbnation.com\",title:{selectors:[\"h1.c-page-title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\"h2.c-entry-summary.p-dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.c-entry-content\"],transforms:{},clean:[]}},WwwBloombergComExtractor:{domain:\"www.bloomberg.com\",title:{selectors:[\".lede-headline\",\"h1.article-title\",\"h1.lede-text-only__hed\"]},author:{selectors:[['meta[name=\"parsely-author\"]',\"value\"],\".byline-details__link\",\".bydek\",\".author\"]},date_published:{selectors:[[\"time.published-at\",\"datetime\"],[\"time[datetime]\",\"datetime\"],['meta[name=\"date\"]',\"value\"],['meta[name=\"parsely-pub-date\"]',\"value\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-body__content\",[\"section.copy-block\"],\".body-copy\"],transforms:{},clean:[\".inline-newsletter\",\".page-ad\"]}},WwwBustleComExtractor:{domain:\"www.bustle.com\",title:{selectors:[\"h1.post-page__title\"]},author:{selectors:[\"div.content-meta__author\"]},date_published:{selectors:[[\"time.content-meta__published-date[datetime]\",\"datetime\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".post-page__body\"],transforms:{},clean:[]}},WwwNprOrgExtractor:{domain:\"www.npr.org\",title:{selectors:[\"h1\",\".storytitle\"]},author:{selectors:[\"p.byline__name.byline__name--block\"]},date_published:{selectors:[[\".dateblock time[datetime]\",\"datetime\"],['meta[name=\"date\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"],['meta[name=\"twitter:image:src\"]',\"value\"]]},content:{selectors:[\".storytext\"],transforms:{\".bucketwrap.image\":\"figure\",\".bucketwrap.image .credit-caption\":\"figcaption\"},clean:[\"div.enlarge_measure\"]}},WwwRecodeNetExtractor:{domain:\"www.recode.net\",title:{selectors:[\"h1.c-page-title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\"h2.c-entry-summary.p-dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"figure.e-image--hero\",\".c-entry-content\"],\".c-entry-content\"],transforms:{},clean:[]}},QzComExtractor:{domain:\"qz.com\",title:{selectors:[\"header.item-header.content-width-responsive\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[\".timestamp\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"figure.featured-image\",\".item-body\"],\".item-body\"],transforms:{},clean:[\".article-aside\",\".progressive-image-thumbnail\"]}},WwwDmagazineComExtractor:{domain:\"www.dmagazine.com\",title:{selectors:[\"h1.story__title\"]},author:{selectors:[\".story__info .story__info__item:first-child\"]},date_published:{selectors:[\".story__info\"],timezone:\"America/Chicago\"},dek:{selectors:[\".story__subhead\"]},lead_image_url:{selectors:[[\"article figure a:first-child\",\"href\"]]},content:{selectors:[\".story__content\"],transforms:{},clean:[]}},WwwReutersComExtractor:{domain:\"www.reuters.com\",title:{selectors:[\"h1.article-headline\"]},author:{selectors:[\".author\"]},date_published:{selectors:[['meta[name=\"og:article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#article-text\"],transforms:{\".article-subtitle\":\"h4\"},clean:[\"#article-byline .author\"]}},MashableComExtractor:{domain:\"mashable.com\",title:{selectors:[\"h1.title\"]},author:{selectors:[\"span.author_name a\"]},date_published:{selectors:[['meta[name=\"og:article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"section.article-content.blueprint\"],transforms:{\".image-credit\":\"figcaption\"},clean:[]}},WwwChicagotribuneComExtractor:{domain:\"www.chicagotribune.com\",title:{selectors:[\"h1.trb_ar_hl_t\"]},author:{selectors:[\"span.trb_ar_by_nm_au\"]},date_published:{selectors:[['meta[itemprop=\"datePublished\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.trb_ar_page\"],transforms:{},clean:[]}},WwwVoxComExtractor:{domain:\"www.vox.com\",title:{selectors:[\"h1.c-page-title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\".p-dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"figure.e-image--hero\",\".c-entry-content\"],\".c-entry-content\"],transforms:{\"figure .e-image__image noscript\":function(e){var t=e.html();e.parents(\".e-image__image\").find(\".c-dynamic-image\").replaceWith(t)},\"figure .e-image__meta\":\"figcaption\"},clean:[]}},NewsNationalgeographicComExtractor:{domain:\"news.nationalgeographic.com\",title:{selectors:[\"h1\",\"h1.main-title\"]},author:{selectors:[\".byline-component__contributors b span\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]],format:\"ddd MMM DD HH:mm:ss zz YYYY\",timezone:\"EST\"},dek:{selectors:[\".article__deck\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".parsys.content\",\".__image-lead__\"],\".content\"],transforms:{\".parsys.content\":function(e,t){var n=e.find(\".image.parbase.section\").find(\".picturefill\").first().data(\"platform-src\");n&&e.prepend(t('<img class=\"__image-lead__\" src=\"'.concat(n,'\"/>')))}},clean:[\".pull-quote.pull-quote--large\"]}},WwwNationalgeographicComExtractor:{domain:\"www.nationalgeographic.com\",title:{selectors:[\"h1\",\"h1.main-title\"]},author:{selectors:[\".byline-component__contributors b span\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\".article__deck\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".parsys.content\",\".__image-lead__\"],\".content\"],transforms:{\".parsys.content\":function(e,t){var n=e.children().first();if(n.hasClass(\"imageGroup\")){var r=n.find(\".media--medium__container\").children().first(),a=r.data(\"platform-image1-path\"),i=r.data(\"platform-image2-path\");i&&a&&e.prepend(t('<div class=\"__image-lead__\">\\n                <img src=\"'.concat(a,'\"/>\\n                <img src=\"').concat(i,'\"/>\\n              </div>')))}else{var o=e.find(\".image.parbase.section\").find(\".picturefill\").first().data(\"platform-src\");o&&e.prepend(t('<img class=\"__image-lead__\" src=\"'.concat(o,'\"/>')))}}},clean:[\".pull-quote.pull-quote--small\"]}},WwwLatimesComExtractor:{domain:\"www.latimes.com\",title:{selectors:[\".trb_ar_hl\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[itemprop=\"datePublished\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".trb_ar_main\"],transforms:{\".trb_ar_la\":function(e){var t=e.find(\"figure\");e.replaceWith(t)}},clean:[\".trb_ar_by\",\".trb_ar_cr\"]}},PagesixComExtractor:{domain:\"pagesix.com\",supportedDomains:[\"nypost.com\"],title:{selectors:[\"h1 a\"]},author:{selectors:[\".byline\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[['meta[name=\"description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"#featured-image-wrapper\",\".entry-content\"],\".entry-content\"],transforms:{\"#featured-image-wrapper\":\"figure\",\".wp-caption-text\":\"figcaption\"},clean:[\".modal-trigger\"]}},ThefederalistpapersOrgExtractor:{domain:\"thefederalistpapers.org\",title:{selectors:[\"h1.entry-title\"]},author:{selectors:[\"main span.entry-author-name\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-content\"],transforms:{},clean:[[\"p[style]\"]]}},WwwCbssportsComExtractor:{domain:\"www.cbssports.com\",title:{selectors:[\".article-headline\"]},author:{selectors:[\".author-name\"]},date_published:{selectors:[[\".date-original-reading-time time\",\"datetime\"]],timezone:\"UTC\"},dek:{selectors:[\".article-subline\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article\"],transforms:{},clean:[]}},WwwMsnbcComExtractor:Ss,WwwThepoliticalinsiderComExtractor:{domain:\"www.thepoliticalinsider.com\",title:{selectors:[['meta[name=\"sailthru.title\"]',\"value\"]]},author:{selectors:[['meta[name=\"sailthru.author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"sailthru.date\"]',\"value\"]],timezone:\"America/New_York\"},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div#article-body\"],transforms:{},clean:[]}},WwwMentalflossComExtractor:{domain:\"www.mentalfloss.com\",title:{selectors:[\"h1.title\",\".title-group\",\".inner\"]},author:{selectors:[\".field-name-field-enhanced-authors\"]},date_published:{selectors:[\".date-display-single\"],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.field.field-name-body\"],transforms:{},clean:[]}},AbcnewsGoComExtractor:{domain:\"abcnews.go.com\",title:{selectors:[\".article-header h1\"]},author:{selectors:[\".authors\"],clean:[\".author-overlay\",\".by-text\"]},date_published:{selectors:[\".timestamp\"],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-copy\"],transforms:{},clean:[]}},WwwNydailynewsComExtractor:{domain:\"www.nydailynews.com\",title:{selectors:[\"h1#ra-headline\"]},author:{selectors:[['meta[name=\"parsely-author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"sailthru.date\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"article#ra-body\"],transforms:{},clean:[\"dl#ra-tags\",\".ra-related\",\"a.ra-editor\",\"dl#ra-share-bottom\"]}},WwwCnbcComExtractor:{domain:\"www.cnbc.com\",title:{selectors:[\"h1.title\",\"h1.ArticleHeader-headline\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div#article_body.content\",\"div.story\",\"div.ArticleBody-articleBody\"],transforms:{},clean:[]}},WwwPopsugarComExtractor:{domain:\"www.popsugar.com\",title:{selectors:[\"h2.post-title\",\"title-text\"]},author:{selectors:[['meta[name=\"article:author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#content\"],transforms:{},clean:[\".share-copy-title\",\".post-tags\",\".reactions\"]}},ObserverComExtractor:{domain:\"observer.com\",title:{selectors:[\"h1.entry-title\"]},author:{selectors:[\".author\",\".vcard\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\"h2.dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.entry-content\"],transforms:{},clean:[]}},PeopleComExtractor:{domain:\"people.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\"a.author.url.fn\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article-body__inner\"],transforms:{},clean:[]}},WwwUsmagazineComExtractor:{domain:\"www.usmagazine.com\",title:{selectors:[\"header h1\"]},author:{selectors:[\"a.article-byline.tracked-offpage\"]},date_published:{timezone:\"America/New_York\",selectors:[\"time.article-published-date\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article-body-inner\"],transforms:{},clean:[\".module-related\"]}},WwwRollingstoneComExtractor:{domain:\"www.rollingstone.com\",title:{selectors:[\"h1.content-title\"]},author:{selectors:[\"a.content-author.tracked-offpage\"]},date_published:{selectors:[\"time.content-published-date\"],timezone:\"America/New_York\"},dek:{selectors:[\".content-description\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".lead-container\",\".article-content\"],\".article-content\"],transforms:{},clean:[\".module-related\"]}},twofortysevensportsComExtractor:{domain:\"247sports.com\",title:{selectors:[\"title\",\"article header h1\"]},author:{selectors:[\".author\"]},date_published:{selectors:[[\"time[data-published]\",\"data-published\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"section.body.article\"],transforms:{},clean:[]}},UproxxComExtractor:{domain:\"uproxx.com\",title:{selectors:[\"div.post-top h1\"]},author:{selectors:[\".post-top .authorname\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".post-body\"],transforms:{\"div.image\":\"figure\",\"div.image .wp-media-credit\":\"figcaption\"},clean:[]}},WwwEonlineComExtractor:{domain:\"www.eonline.com\",title:{selectors:[\"h1.article__title\"]},author:{selectors:[\".entry-meta__author a\"]},date_published:{selectors:[['meta[itemprop=\"datePublished\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".post-content section, .post-content div.post-content__image\"]],transforms:{\"div.post-content__image\":\"figure\",\"div.post-content__image .image__credits\":\"figcaption\"},clean:[]}},WwwMiamiheraldComExtractor:{domain:\"www.miamiherald.com\",title:{selectors:[\"h1.title\"]},date_published:{selectors:[\"p.published-date\"],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.dateline-storybody\"],transforms:{},clean:[]}},WwwRefinery29ComExtractor:{domain:\"www.refinery29.com\",title:{selectors:[\"h1.title\"]},author:{selectors:[\".contributor\"]},date_published:{selectors:[['meta[name=\"sailthru.date\"]',\"value\"]],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".full-width-opener\",\".article-content\"],\".article-content\",\".body\"],transforms:{\"div.loading noscript\":function(e){var t=e.html();e.parents(\".loading\").replaceWith(t)},\".section-image\":\"figure\",\".section-image .content-caption\":\"figcaption\",\".section-text\":\"p\"},clean:[\".story-share\"]}},WwwMacrumorsComExtractor:{domain:\"www.macrumors.com\",title:{selectors:[\"h1\",\"h1.title\"]},author:{selectors:[\".author-url\"]},date_published:{selectors:[\".article .byline\"],format:\"dddd MMMM D, YYYY h:mm A zz\",timezone:\"America/Los_Angeles\"},dek:{selectors:[['meta[name=\"description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article\"],transforms:{},clean:[]}},WwwAndroidcentralComExtractor:{domain:\"www.androidcentral.com\",title:{selectors:[\"h1\",\"h1.main-title\"]},author:{selectors:[\".meta-by\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[[\".image-large\",\"src\"]]},content:{selectors:[\".article-body\"],transforms:{},clean:[\".intro\",\"blockquote\"]}},WwwSiComExtractor:{domain:\"www.si.com\",title:{selectors:[\"h1\",\"h1.headline\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[\".timestamp\"],timezone:\"America/New_York\"},dek:{selectors:[\".quick-hit ul\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"p\",\".marquee_large_2x\",\".component.image\"]],transforms:{noscript:function(e){var t=e.children();return 1===t.length&&\"img\"===t.get(0).tagName?\"figure\":null}},clean:[[\".inline-thumb\",\".primary-message\",\".description\",\".instructions\"]]}},WwwRawstoryComExtractor:{domain:\"www.rawstory.com\",title:{selectors:[\".blog-title\"]},author:{selectors:[\".blog-author a:first-of-type\"]},date_published:{selectors:[\".blog-author a:last-of-type\"],timezone:\"EST\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".blog-content\"],transforms:{},clean:[]}},WwwCnetComExtractor:{domain:\"www.cnet.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\"a.author\"]},date_published:{selectors:[\"time\"],timezone:\"America/Los_Angeles\"},dek:{selectors:[\".article-dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"img.__image-lead__\",\".article-main-body\"],\".article-main-body\"],transforms:{\"figure.image\":function(e){var t=e.find(\"img\");t.attr(\"width\",\"100%\"),t.attr(\"height\",\"100%\"),t.addClass(\"__image-lead__\"),e.remove(\".imgContainer\").prepend(t)}},clean:[]}},WwwCinemablendComExtractor:{domain:\"www.cinemablend.com\",title:{selectors:[\".story_title\"]},author:{selectors:[\".author\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]],timezone:\"EST\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div#wrap_left_content\"],transforms:{},clean:[]}},WwwTodayComExtractor:{domain:\"www.today.com\",title:{selectors:[\"h1.entry-headline\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"DC.date.issued\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-container\"],transforms:{},clean:[\".label-comment\"]}},WwwHowtogeekComExtractor:{domain:\"www.howtogeek.com\",title:{selectors:[\"title\"]},author:{selectors:[\"#authorinfobox a\"]},date_published:{selectors:[\"#authorinfobox + div li\"],timezone:\"GMT\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".thecontent\"],transforms:{},clean:[]}},WwwAlComExtractor:{domain:\"www.al.com\",title:{selectors:[['meta[name=\"title\"]',\"value\"]]},author:{selectors:[['meta[name=\"article_author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article_date_original\"]',\"value\"]],timezone:\"EST\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-content\"],transforms:{},clean:[]}},WwwThepennyhoarderComExtractor:{domain:\"www.thepennyhoarder.com\",title:{selectors:[['meta[name=\"dcterms.title\"]',\"value\"]]},author:{selectors:[['link[rel=\"author\"]',\"title\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".post-img\",\".post-text\"],\".post-text\"],transforms:{},clean:[]}},WwwWesternjournalismComExtractor:{domain:\"www.westernjournalism.com\",title:{selectors:[\"title\",\"h1.entry-title\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"DC.date.issued\"]',\"value\"]]},dek:{selectors:[\".subtitle\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article-sharing.top + div\"],transforms:{},clean:[\".ad-notice-small\"]}},FusionNetExtractor:{domain:\"fusion.net\",title:{selectors:[\".post-title\",\".single-title\",\".headline\"]},author:{selectors:[\".show-for-medium .byline\"]},date_published:{selectors:[[\"time.local-time\",\"datetime\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".post-featured-media\",\".article-content\"],\".article-content\"],transforms:{\".fusion-youtube-oembed\":\"figure\"},clean:[]}},WwwAmericanowComExtractor:{domain:\"www.americanow.com\",title:{selectors:[\".title\",['meta[name=\"title\"]',\"value\"]]},author:{selectors:[\".byline\"]},date_published:{selectors:[['meta[name=\"publish_date\"]',\"value\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".article-content\",\".image\",\".body\"],\".body\"],transforms:{},clean:[\".article-video-wrapper\",\".show-for-small-only\"]}},ScienceflyComExtractor:{domain:\"sciencefly.com\",title:{selectors:[\".entry-title\",\".cb-entry-title\",\".cb-single-title\"]},author:{selectors:[\"div.cb-author\",\"div.cb-author-title\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[]},lead_image_url:{selectors:[[\"div.theiaPostSlider_slides img\",\"src\"]]},content:{selectors:[\"div.theiaPostSlider_slides\"],transforms:{},clean:[]}},HellogigglesComExtractor:{domain:\"hellogiggles.com\",title:{selectors:[\".title\"]},author:{selectors:[\".author-link\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-content\"],transforms:{},clean:[]}},ThoughtcatalogComExtractor:{domain:\"thoughtcatalog.com\",title:{selectors:[\"h1.title\",['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\"div.col-xs-12.article_header div.writer-container.writer-container-inline.writer-no-avatar h4.writer-name\",\"h1.writer-name\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry.post\"],transforms:{},clean:[\".tc_mark\"]}},WwwNjComExtractor:{domain:\"www.nj.com\",title:{selectors:[['meta[name=\"title\"]',\"value\"]]},author:{selectors:[['meta[name=\"article_author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article_date_original\"]',\"value\"]],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-content\"],transforms:{},clean:[]}},WwwInquisitrComExtractor:{domain:\"www.inquisitr.com\",title:{selectors:[\"h1.entry-title.story--header--title\"]},author:{selectors:[\"div.story--header--author\"]},date_published:{selectors:[['meta[name=\"datePublished\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"article.story\",\".entry-content.\"],transforms:{},clean:[\".post-category\",\".story--header--socials\",\".story--header--content\"]}},WwwNbcnewsComExtractor:{domain:\"www.nbcnews.com\",title:{selectors:[\"div.article-hed h1\"]},author:{selectors:[\"span.byline_author\"]},date_published:{selectors:[[\".flag_article-wrapper time.timestamp_article[datetime]\",\"datetime\"],\".flag_article-wrapper time\"],timezone:\"America/New_York\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article-body\"],transforms:{},clean:[]}},FortuneComExtractor:{domain:\"fortune.com\",title:{selectors:[\"h1\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[\".MblGHNMJ\"],timezone:\"UTC\"},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"picture\",\"article.row\"],\"article.row\"],transforms:{},clean:[]}},WwwLinkedinComExtractor:{domain:\"www.linkedin.com\",title:{selectors:[\".article-title\",\"h1\"]},author:{selectors:[['meta[name=\"article:author\"]',\"value\"],\".entity-name a[rel=author]\"]},date_published:{selectors:[['time[itemprop=\"datePublished\"]',\"datetime\"]],timezone:\"America/Los_Angeles\"},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"header figure\",\".prose\"],\".prose\"],transforms:{},clean:[\".entity-image\"]}},ObamawhitehouseArchivesGovExtractor:{domain:\"obamawhitehouse.archives.gov\",supportedDomains:[\"whitehouse.gov\"],title:{selectors:[\"h1\",\".pane-node-title\"]},author:{selectors:[\".blog-author-link\",\".node-person-name-link\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\".field-name-field-forall-summary\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{defaultCleaner:!1,selectors:[\"div#content-start\",\".pane-node-field-forall-body\"],transforms:{},clean:[\".pane-node-title\",\".pane-custom.pane-1\"]}},WwwOpposingviewsComExtractor:{domain:\"www.opposingviews.com\",title:{selectors:[\"h1.title\"]},author:{selectors:[\"div.date span span a\"]},date_published:{selectors:[['meta[name=\"publish_date\"]',\"value\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-content\"],transforms:{},clean:[\".show-for-small-only\"]}},WwwProspectmagazineCoUkExtractor:{domain:\"www.prospectmagazine.co.uk\",title:{selectors:[\".page-title\"]},author:{selectors:[\".aside_author .title\"]},date_published:{selectors:[\".post-info\"],timezone:\"Europe/London\"},dek:{selectors:[\".page-subtitle\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"article .post_content\"],transforms:{},clean:[]}},ForwardComExtractor:{domain:\"forward.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\".author-name\",['meta[name=\"sailthru.author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"date\"]',\"value\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".post-item-media-wrap\",\".post-item p\"]],transforms:{},clean:[\".donate-box\",\".message\",\".subtitle\"]}},WwwQdailyComExtractor:{domain:\"www.qdaily.com\",title:{selectors:[\"h2\",\"h2.title\"]},author:{selectors:[\".name\"]},date_published:{selectors:[[\".date.smart-date\",\"data-origindate\"]]},dek:{selectors:[\".excerpt\"]},lead_image_url:{selectors:[[\".article-detail-hd img\",\"src\"]]},content:{selectors:[\".detail\"],transforms:{},clean:[\".lazyload\",\".lazylad\",\".lazylood\"]}},GothamistComExtractor:{domain:\"gothamist.com\",supportedDomains:[\"chicagoist.com\",\"laist.com\",\"sfist.com\",\"shanghaiist.com\",\"dcist.com\"],title:{selectors:[\"h1\",\".entry-header h1\"]},author:{selectors:[\".author\"]},date_published:{selectors:[\"abbr\",\"abbr.published\"],timezone:\"America/New_York\"},dek:{selectors:[null]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".entry-body\"],transforms:{\"div.image-none\":\"figure\",\".image-none i\":\"figcaption\",\"div.image-left\":\"figure\",\".image-left i\":\"figcaption\",\"div.image-right\":\"figure\",\".image-right i\":\"figcaption\"},clean:[\".image-none br\",\".image-left br\",\".image-right br\",\".galleryEase\"]}},WwwFoolComExtractor:{domain:\"www.fool.com\",title:{selectors:[\"h1\"]},author:{selectors:[\".author-inline .author-name\"]},date_published:{selectors:[['meta[name=\"date\"]',\"value\"]]},dek:{selectors:[\"header h2\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article-content\"],transforms:{\".caption img\":function(e){var t=e.attr(\"src\");e.parent().replaceWith('<figure><img src=\"'.concat(t,'\"/></figure>'))},\".caption\":\"figcaption\"},clean:[\"#pitch\"]}},WwwSlateComExtractor:{domain:\"www.slate.com\",title:{selectors:[\".hed\",\"h1\"]},author:{selectors:[\"a[rel=author]\"]},date_published:{selectors:[\".pub-date\"],timezone:\"America/New_York\"},dek:{selectors:[\".dek\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".body\"],transforms:{},clean:[\".about-the-author\",\".pullquote\",\".newsletter-signup-component\",\".top-comment\"]}},IciRadioCanadaCaExtractor:{domain:\"ici.radio-canada.ca\",title:{selectors:[\"h1\"]},author:{selectors:[['meta[name=\"dc.creator\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"dc.date.created\"]',\"value\"]],timezone:\"America/New_York\"},dek:{selectors:[\".bunker-component.lead\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\".main-multimedia-item\",\".news-story-content\"]],transforms:{},clean:[]}},WwwFortinetComExtractor:{domain:\"www.fortinet.com\",title:{selectors:[\"h1\"]},author:{selectors:[\".b15-blog-meta__author\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.responsivegrid.aem-GridColumn.aem-GridColumn--default--12\"],transforms:{noscript:function(e){var t=e.children();return 1===t.length&&\"img\"===t.get(0).tagName?\"figure\":null}}}},WwwFastcompanyComExtractor:{domain:\"www.fastcompany.com\",title:{selectors:[\"h1\"]},author:{selectors:[\".post__by\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[\".post__deck\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".post__article\"]}},BlisterreviewComExtractor:{domain:\"blisterreview.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"],\"h1.entry-title\"]},author:{selectors:[\"span.author-name\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"],[\"time.entry-date\",\"datetime\"],['meta[itemprop=\"datePublished\"]',\"content\"]]},dek:{selectors:[]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"],['meta[property=\"og:image\"]',\"content\"],['meta[itemprop=\"image\"]',\"content\"],['meta[name=\"twitter:image\"]',\"content\"],[\"img.attachment-large\",\"src\"]]},content:{selectors:[[\".elementor-section-wrap\",\".elementor-text-editor > p, .elementor-text-editor > ul > li, .attachment-large, .wp-caption-text\"]],transforms:{figcaption:\"p\"},clean:[\".comments-area\"]}},NewsMynaviJpExtractor:{domain:\"news.mynavi.jp\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[\"main div.article-author a.article-author__name\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"main article div\"],transforms:{img:function(e){var t=e.attr(\"data-original\");\"\"!==t&&e.attr(\"src\",t)}},clean:[]}},ClinicaltrialsGovExtractor:{domain:\"clinicaltrials.gov\",title:{selectors:[\"h1.tr-solo_record\"]},author:{selectors:[\"div#sponsor.tr-info-text\"]},date_published:{selectors:['div:has(> span.term[data-term=\"Last Update Posted\"])']},content:{selectors:[\"div#tab-body\"],transforms:{},clean:[\".usa-alert> img\"]}},GithubComExtractor:{domain:\"github.com\",title:{selectors:[['meta[name=\"og:title\"]',\"value\"]]},author:{selectors:[]},date_published:{selectors:[['span[itemprop=\"dateModified\"] relative-time',\"datetime\"]]},dek:{selectors:['span[itemprop=\"about\"]']},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"#readme article\"]],transforms:{},clean:[]}},WwwRedditComExtractor:{domain:\"www.reddit.com\",title:{selectors:['div[data-test-id=\"post-content\"] h2']},author:{selectors:['div[data-test-id=\"post-content\"] a[href*=\"user/\"]']},date_published:{selectors:['div[data-test-id=\"post-content\"] a[data-click-id=\"timestamp\"]']},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[['div[data-test-id=\"post-content\"] p'],['div[data-test-id=\"post-content\"] a[target=\"_blank\"]:not([data-click-id=\"timestamp\"])','div[data-test-id=\"post-content\"] div[data-click-id=\"media\"]'],['div[data-test-id=\"post-content\"] div[data-click-id=\"media\"]'],['div[data-test-id=\"post-content\"] a[target=\"_blank\"]:not([data-click-id=\"timestamp\"])'],'div[data-test-id=\"post-content\"]'],transforms:{'div[role=\"img\"]':function(e){var t=e.find(\"img\"),n=e.css(\"background-image\");return 1===t.length&&n?(t.attr(\"src\",n.match(/\\((.*?)\\)/)[1].replace(/('|\")/g,\"\")),t):e}},clean:[\".icon\"]}},OtrsComExtractor:{domain:\"otrs.com\",title:{selectors:[\"#main article h1\"]},author:{selectors:[\"div.dateplusauthor a\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#main article\"],defaultCleaner:!1,transforms:{},clean:[\"div.dateplusauthor\",\"div.gr-12.push-6.footershare\",\"#atftbx\",\"div.category-modul\"]}},WwwOssnewsJpExtractor:{domain:\"www.ossnews.jp\",title:{selectors:[\"#alpha-block h1.hxnewstitle\"]},author:null,date_published:{selectors:[\"p.fs12\"],format:\"YYYY年MM月DD日 HH:mm\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#alpha-block .section:has(h1.hxnewstitle)\"],defaultCleaner:!1,transforms:{},clean:[]}},BuzzapJpExtractor:{domain:\"buzzap.jp\",title:{selectors:[\"h1.entry-title\"]},author:null,date_published:{selectors:[[\"time.entry-date\",\"datetime\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.ctiframe\"],defaultCleaner:!1,transforms:{},clean:[]}},WwwAsahiComExtractor:{domain:\"www.asahi.com\",title:{selectors:[\".ArticleTitle h1\"]},author:{selectors:[['meta[name=\"article:author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"pubdate\"]',\"value\"]]},dek:null,excerpt:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#MainInner div.ArticleBody\"],defaultCleaner:!1,transforms:{},clean:[\"div.AdMod\",\"div.LoginSelectArea\"]}},WwwSanwaCoJpExtractor:{domain:\"www.sanwa.co.jp\",title:{selectors:[\"#newsContent h1\"]},author:null,date_published:{selectors:[\"p.date\"],format:\"YYYY.MM.DD\",timezone:\"Asia/Tokyo\"},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#newsContent\"],defaultCleaner:!1,transforms:{},clean:[\"#smartphone\",\"div.sns_box\",\"div.contentFoot\"]}},WwwElecomCoJpExtractor:{domain:\"www.elecom.co.jp\",title:{selectors:[\"title\"]},author:null,date_published:{selectors:[\"p.section-last\"],format:\"YYYY.MM.DD\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:null,content:{selectors:[\"td.TableMain2\"],defaultCleaner:!1,transforms:{table:function(e){e.attr(\"width\",\"auto\")}},clean:[]}},ScanNetsecurityNeJpExtractor:{domain:\"scan.netsecurity.ne.jp\",title:{selectors:[\"header.arti-header h1.head\"]},author:null,date_published:{selectors:[['meta[name=\"article:modified_time\"]',\"value\"]]},dek:{selectors:[\"header.arti-header p.arti-summary\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.arti-content.arti-content--thumbnail\"],defaultCleaner:!1,transforms:{},clean:[\"aside.arti-giga\"]}},JvndbJvnJpExtractor:{domain:\"jvndb.jvn.jp\",title:{selectors:[\"title\"]},author:null,date_published:{selectors:[\"div.modifytxt:nth-child(2)\"],format:\"YYYY/MM/DD\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:null,content:{selectors:[\"#news-list\"],defaultCleaner:!1,transforms:{},clean:[]}},GeniusComExtractor:Ms,WwwJnsaOrgExtractor:{domain:\"www.jnsa.org\",title:{selectors:[\"#wgtitle h2\"]},author:null,date_published:null,dek:null,excerpt:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#main_area\"],transforms:{},clean:[\"#pankuzu\",\"#side\"]}},PhpspotOrgExtractor:{domain:\"phpspot.org\",title:{selectors:[\"h3.hl\"]},author:null,date_published:{selectors:[\"h4.hl\"],format:\"YYYY年MM月DD日\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:null,content:{selectors:[\"div.entrybody\"],defaultCleaner:!1,transforms:{},clean:[]}},WwwInfoqComExtractor:{domain:\"www.infoq.com\",title:{selectors:[\"h1.heading\"]},author:{selectors:[\"div.widget.article__authors\"]},date_published:{selectors:[\".article__readTime.date\"],format:\"YYYY年MM月DD日\",timezone:\"Asia/Tokyo\"},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article__data\"],defaultCleaner:!1,transforms:{},clean:[]}},WwwMoongiftJpExtractor:{domain:\"www.moongift.jp\",title:{selectors:[\"h1.title a\"]},author:null,date_published:{selectors:[\"ul.meta li:not(.social):first-of-type\"],timezone:\"Asia/Tokyo\"},dek:{selectors:[['meta[name=\"og:description\"]',\"value\"]]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#main\"],transforms:{},clean:[\"ul.mg_service.cf\"]}},WwwItmediaCoJpExtractor:{domain:\"www.itmedia.co.jp\",supportedDomains:[\"www.atmarkit.co.jp\",\"techtarget.itmedia.co.jp\",\"nlab.itmedia.co.jp\"],title:{selectors:[\"#cmsTitle h1\"]},author:{selectors:[\"#byline\"]},date_published:{selectors:[['meta[name=\"article:modified_time\"]',\"value\"]]},dek:{selectors:[\"#cmsAbstract h2\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#cmsBody\"],defaultCleaner:!1,transforms:{},clean:[\"#snsSharebox\"]}},WwwPublickey1JpExtractor:{domain:\"www.publickey1.jp\",title:{selectors:[\"h1\"]},author:{selectors:[\"#subcol p:has(img)\"]},date_published:{selectors:[\"div.pubdate\"],format:\"YYYY年MM月DD日\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#maincol\"],defaultCleaner:!1,transforms:{},clean:[\"#breadcrumbs\",\"div.sbm\",\"div.ad_footer\"]}},TakagihiromitsuJpExtractor:{domain:\"takagi-hiromitsu.jp\",title:{selectors:[\"h3\"]},author:{selectors:[['meta[name=\"author\"]',\"value\"]]},date_published:{selectors:[['meta[http-equiv=\"Last-Modified\"]',\"value\"]]},dek:null,lead_image_url:null,content:{selectors:[\"div.body\"],defaultCleaner:!1,transforms:{},clean:[]}},BookwalkerJpExtractor:{domain:\"bookwalker.jp\",title:{selectors:[\"h1.main-heading\"]},author:{selectors:[\"div.authors\"]},date_published:{selectors:[\".work-info .work-detail:first-of-type .work-detail-contents:last-of-type\"],timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[[\"div.main-info\",\"div.main-cover-inner\"]],defaultCleaner:!1,transforms:{},clean:[\"span.label.label--trial\",\"dt.info-head.info-head--coin\",\"dd.info-contents.info-contents--coin\",\"div.info-notice.fn-toggleClass\"]}},WwwYomiuriCoJpExtractor:{domain:\"www.yomiuri.co.jp\",title:{selectors:[\"h1.title-article.c-article-title\"]},author:null,date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.p-main-contents\"],transforms:{},clean:[]}},JapanCnetComExtractor:{domain:\"japan.cnet.com\",title:{selectors:[\".leaf-headline-ttl\"]},author:{selectors:[\".writer\"]},date_published:{selectors:[\".date\"],format:\"YYYY年MM月DD日 HH時mm分\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article_body\"],transforms:{},clean:[]}},DeadlineComExtractor:{domain:\"deadline.com\",title:{selectors:[\"h1\"]},author:{selectors:[\"section.author h3\"]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.a-article-grid__main.pmc-a-grid article.pmc-a-grid-item\"],transforms:{\".embed-twitter\":function(e){var t=e.html();e.replaceWith(t)}},clean:[]}},WwwGizmodoJpExtractor:{domain:\"www.gizmodo.jp\",title:{selectors:[\"h1.p-post-title\"]},author:{selectors:[\"li.p-post-AssistAuthor\"]},date_published:{selectors:[[\"li.p-post-AssistTime time\",\"datetime\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"article.p-post\"],transforms:{\"img.p-post-thumbnailImage\":function(e){var t=e.attr(\"src\");e.attr(\"src\",t.replace(/^.*=%27/,\"\").replace(/%27;$/,\"\"))}},clean:[\"h1.p-post-title\",\"ul.p-post-Assist\"]}},GetnewsJpExtractor:{domain:\"getnews.jp\",title:{selectors:[\"article h1\"]},author:{selectors:[\"span.prof\"]},date_published:{selectors:[[\"ul.cattag-top time\",\"datetime\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.post-bodycopy\"],transforms:{},clean:[]}},WwwLifehackerJpExtractor:{domain:\"www.lifehacker.jp\",title:{selectors:[\"h1.lh-summary-title\"]},author:{selectors:[\"p.lh-entryDetailInner--credit\"]},date_published:{selectors:[[\"div.lh-entryDetail-header time\",\"datetime\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.lh-entryDetail-body\"],transforms:{\"img.lazyload\":function(e){var t=e.attr(\"src\");e.attr(\"src\",t.replace(/^.*=%27/,\"\").replace(/%27;$/,\"\"))}},clean:[\"p.lh-entryDetailInner--credit\"]}},SectIijAdJpExtractor:{domain:\"sect.iij.ad.jp\",title:{selectors:[\"h3\"]},author:{selectors:[\"dl.entrydate dd\"]},date_published:{selectors:[\"dl.entrydate dd\"],format:\"YYYY年MM月DD日\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#article\"],transforms:{},clean:[\"dl.entrydate\"]}},WwwOreillyCoJpExtractor:{domain:\"www.oreilly.co.jp\",title:{selectors:[\"h3\"]},author:{selectors:['li[itemprop=\"author\"]']},date_published:{selectors:[['meta[itemprop=\"datePublished\"]',\"value\"]],timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"#content\"],defaultCleaner:!1,transforms:{},clean:[\".social-tools\"]}},WwwIpaGoJpExtractor:{domain:\"www.ipa.go.jp\",title:{selectors:[\"h1\"]},author:null,date_published:{selectors:[\"p.ipar_text_right\"],format:\"YYYY年M月D日\",timezone:\"Asia/Tokyo\"},dek:null,lead_image_url:null,content:{selectors:[\"#ipar_main\"],defaultCleaner:!1,transforms:{},clean:[\"p.ipar_text_right\"]}},WeeklyAsciiJpExtractor:{domain:\"weekly.ascii.jp\",title:{selectors:['h1[itemprop=\"headline\"]']},author:{selectors:[\"p.author\"]},date_published:{selectors:[['meta[name=\"odate\"]',\"value\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article\"],transforms:{},clean:[]}},TechlogIijAdJpExtractor:{domain:\"techlog.iij.ad.jp\",title:{selectors:[\"h1.entry-title\"]},author:{selectors:['a[rel=\"author\"]']},date_published:{selectors:[[\"time.entry-date\",\"datetime\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.entry-content\"],defaultCleaner:!1,transforms:{},clean:[]}},WiredJpExtractor:Ts,JapanZdnetComExtractor:{domain:\"japan.zdnet.com\",title:{selectors:[\"h1\"]},author:{selectors:[['meta[name=\"cXenseParse:author\"]',\"value\"]]},date_published:{selectors:[['meta[name=\"article:published_time\"]',\"value\"]]},dek:null,lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\"div.article_body\"],transforms:{},clean:[]}},WwwRbbtodayComExtractor:{domain:\"www.rbbtoday.com\",title:{selectors:[\"h1\"]},author:{selectors:[\".writer.writer-name\"]},date_published:{selectors:[[\"header time\",\"datetime\"]]},dek:{selectors:[\".arti-summary\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".arti-content\"],transforms:{},clean:[\".arti-giga\"]}},WwwLemondeFrExtractor:{domain:\"www.lemonde.fr\",title:{selectors:[\"h1.article__title\"]},author:{selectors:[\".author__name\"]},date_published:{selectors:[['meta[name=\"og:article:published_time\"]',\"value\"]]},dek:{selectors:[\".article__desc\"]},lead_image_url:{selectors:[['meta[name=\"og:image\"]',\"value\"]]},content:{selectors:[\".article__content\"],transforms:{},clean:[]}},WwwPhoronixComExtractor:{domain:\"www.phoronix.com\",title:{selectors:[\"article header\"]},author:{selectors:[\".author a:first-child\"]},date_published:{selectors:[\".author\"],format:\"D MMMM YYYY at hh:mm\",timezone:\"America/New_York\"},dek:null,lead_image_url:null,content:{selectors:[\".content\"],transforms:{},clean:[]}},PitchforkComExtractor:{domain:\"pitchfork.com\",title:{selectors:[\"title\"]},author:{selectors:[\".authors-detail__display-name\"]},date_published:{selectors:[[\".pub-date\",\"datetime\"]]},dek:{selectors:[\".review-detail__abstract\"]},lead_image_url:{selectors:[[\".single-album-tombstone__art img\",\"src\"]]},content:{selectors:[\".review-detail__text\"]},extend:{score:{selectors:[\".score\"]}}},BiorxivOrgExtractor:{domain:\"biorxiv.org\",title:{selectors:[\"h1#page-title\"]},author:{selectors:[\"div.highwire-citation-biorxiv-article-top > div.highwire-cite-authors\"]},content:{selectors:[\"div#abstract-1\"],transforms:{},clean:[]}},EpaperZeitDeExtractor:{domain:\"epaper.zeit.de\",title:{selectors:[\"p.title\"]},author:{selectors:[\".article__author\"]},date_published:null,excerpt:{selectors:[\"subtitle\"]},lead_image_url:null,content:{selectors:[\".article\"],transforms:{\"p.title\":\"h1\",\".article__author\":\"p\",byline:\"p\",linkbox:\"p\"},clean:[\"image-credits\",\"box[type=citation]\"]}}}),Ds=lt(Cs).reduce(function(e,t){var n=Cs[t];return pt({},e,_s(n))},{}),Os=e(function(e,t){(function(){var r=\"‎\",a=\"‏\",m=\"ltr\",g=\"rtl\",i=\"bidi\",o=\"\",v={Hebrew:[\"0590\",\"05FF\"],Arabic:[\"0600\",\"06FF\"],NKo:[\"07C0\",\"07FF\"],Syriac:[\"0700\",\"074F\"],Thaana:[\"0780\",\"07BF\"],Tifinagh:[\"2D30\",\"2D7F\"]};function e(e){if(void 0===e)throw new Error(\"TypeError missing argument\");if(\"string\"!=typeof e)throw new Error(\"TypeError getDirection expects strings\");if(\"\"===e)return o;if(-1<e.indexOf(r)&&-1<e.indexOf(a))return i;if(-1<e.indexOf(r))return m;if(-1<e.indexOf(a))return g;var t=s(e,g),n=s(e,m);return t&&n?i:n?m:t?g:o}function s(e,t){var n,r,a,i,o,s,u,c,l,f,h,d=!1,p=!1;for(o=-1<e.search(/[0-9]/),e=e.replace(/[\\s\\n\\0\\f\\t\\v\\'\\\"\\-0-9\\+\\?\\!]+/gm,\"\"),n=0;n<e.length;n++){for(a in r=e.charAt(n),i=!1,v)v.hasOwnProperty(a)&&(s=r,u=v[a][0],c=v[a][1],void 0,l=s.charCodeAt(0),f=parseInt(u,16),h=parseInt(c,16),f<l&&l<h&&(i=d=!0));!1===i&&(p=!0)}return t===g?d:t===m?p||!d&&o:void 0}t.getDirection=e,t.patch=function(){String.prototype.getDirection=function(){return e(this.valueOf())}}}).call(this)}),js=(Os.getDirection,Os.patch,/^\\s*(posted |written )?by\\s*:?\\s*(.*)/i),Ns=new RegExp(\"http(s)?://\",\"i\"),zs=/^\\d{13}$/i,Ps=/^\\d{10}$/i,Ls=/^\\s*published\\s*:?\\s*(.*)/i,Rs=/(.*\\d)(am|pm)(.*)/i,Ys=/\\.m\\./i,Ws=/^\\s*(just|right)?\\s*now\\s*/i,qs=[\"seconds?\",\"minutes?\",\"hours?\",\"days?\",\"weeks?\",\"months?\",\"years?\"].join(\"|\"),Is=new RegExp(\"(\\\\d+)\\\\s+(\".concat(qs,\")\\\\s+ago\"),\"i\"),Hs=[\"jan\",\"feb\",\"mar\",\"apr\",\"may\",\"jun\",\"jul\",\"aug\",\"sep\",\"oct\",\"nov\",\"dec\"].join(\"|\"),Fs=new RegExp(\"(\".concat(\"[0-9]{1,2}:[0-9]{2,2}( ?[ap].?m.?)?\",\")|(\").concat(\"[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}\",\")|(\").concat(\"-[0-9]{3,4}$\",\")|([0-9]{1,4})|(\").concat(Hs,\")\"),\"ig\"),Bs=/-\\d{3,4}$/,Gs=/(: | - | \\| )/g,Us=new RegExp(\".com$|.net$|.org$|.co.uk$\",\"g\");function $s(e){return ua(e.replace(js,\"$2\").trim())}var Vs=e(function(e){!function(e){e.exports.is_uri=f,e.exports.is_http_uri=t,e.exports.is_https_uri=n,e.exports.is_web_uri=r,e.exports.isUri=f,e.exports.isHttpUri=t,e.exports.isHttpsUri=n,e.exports.isWebUri=r;var l=function(e){return e.match(/(?:([^:\\/?#]+):)?(?:\\/\\/([^\\/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?/)};function f(e){if(e&&!/[^a-z0-9\\:\\/\\?\\#\\[\\]\\@\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=\\.\\-\\_\\~\\%]/i.test(e)&&!/%[^0-9a-f]/i.test(e)&&!/%[0-9a-f](:?[^0-9a-f]|$)/i.test(e)){var t,n,r,a,i,o=\"\",s=\"\";if(o=(t=l(e))[1],n=t[2],r=t[3],a=t[4],i=t[5],o&&o.length&&0<=r.length){if(n&&n.length){if(0!==r.length&&!/^\\//.test(r))return}else if(/^\\/\\//.test(r))return;if(/^[a-z][a-z0-9\\+\\-\\.]*$/.test(o.toLowerCase()))return s+=o+\":\",n&&n.length&&(s+=\"//\"+n),s+=r,a&&a.length&&(s+=\"?\"+a),i&&i.length&&(s+=\"#\"+i),s}}}function t(e,t){if(f(e)){var n,r,a,i,o=\"\",s=\"\",u=\"\",c=\"\";if(o=(n=l(e))[1],s=n[2],r=n[3],a=n[4],i=n[5],o){if(t){if(\"https\"!=o.toLowerCase())return}else if(\"http\"!=o.toLowerCase())return;if(s)return/:(\\d+)$/.test(s)&&(u=s.match(/:(\\d+)$/)[0],s=s.replace(/:\\d+$/,\"\")),c+=o+\":\",c+=\"//\"+s,u&&(c+=u),c+=r,a&&a.length&&(c+=\"?\"+a),i&&i.length&&(c+=\"#\"+i),c}}}function n(e){return t(e,!0)}function r(e){return t(e)||n(e)}}(e)});function Js(e){return e=e.trim(),Vs.isWebUri(e)?e:null}var Ks=e(function(Un,e){Un.exports=function(){var e,a;function g(){return e.apply(null,arguments)}function s(e){return e instanceof Array||\"[object Array]\"===Object.prototype.toString.call(e)}function u(e){return null!=e&&\"[object Object]\"===Object.prototype.toString.call(e)}function i(e){return void 0===e}function l(e){return\"number\"==typeof e||\"[object Number]\"===Object.prototype.toString.call(e)}function o(e){return e instanceof Date||\"[object Date]\"===Object.prototype.toString.call(e)}function c(e,t){var n,r=[];for(n=0;n<e.length;++n)r.push(t(e[n],n));return r}function v(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function f(e,t){for(var n in t)v(t,n)&&(e[n]=t[n]);return v(t,\"toString\")&&(e.toString=t.toString),v(t,\"valueOf\")&&(e.valueOf=t.valueOf),e}function h(e,t,n,r){return Ct(e,t,n,r,!0).utc()}function y(e){return null==e._pf&&(e._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),e._pf}function d(e){if(null==e._isValid){var t=y(e),n=a.call(t.parsedDateParts,function(e){return null!=e}),r=!isNaN(e._d.getTime())&&t.overflow<0&&!t.empty&&!t.invalidMonth&&!t.invalidWeekday&&!t.weekdayMismatch&&!t.nullInput&&!t.invalidFormat&&!t.userInvalidated&&(!t.meridiem||t.meridiem&&n);if(e._strict&&(r=r&&0===t.charsLeftOver&&0===t.unusedTokens.length&&void 0===t.bigHour),null!=Object.isFrozen&&Object.isFrozen(e))return r;e._isValid=r}return e._isValid}function p(e){var t=h(NaN);return null!=e?f(y(t),e):y(t).userInvalidated=!0,t}a=Array.prototype.some?Array.prototype.some:function(e){for(var t=Object(this),n=t.length>>>0,r=0;r<n;r++)if(r in t&&e.call(this,t[r],r,t))return!0;return!1};var m=g.momentProperties=[];function _(e,t){var n,r,a;if(i(t._isAMomentObject)||(e._isAMomentObject=t._isAMomentObject),i(t._i)||(e._i=t._i),i(t._f)||(e._f=t._f),i(t._l)||(e._l=t._l),i(t._strict)||(e._strict=t._strict),i(t._tzm)||(e._tzm=t._tzm),i(t._isUTC)||(e._isUTC=t._isUTC),i(t._offset)||(e._offset=t._offset),i(t._pf)||(e._pf=y(t)),i(t._locale)||(e._locale=t._locale),0<m.length)for(n=0;n<m.length;n++)r=m[n],i(a=t[r])||(e[r]=a);return e}var t=!1;function b(e){_(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===t&&(t=!0,g.updateOffset(this),t=!1)}function w(e){return e instanceof b||null!=e&&null!=e._isAMomentObject}function A(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function x(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=A(t)),n}function k(e,t,n){var r,a=Math.min(e.length,t.length),i=Math.abs(e.length-t.length),o=0;for(r=0;r<a;r++)(n&&e[r]!==t[r]||!n&&x(e[r])!==x(t[r]))&&o++;return o+i}function E(e){!1===g.suppressDeprecationWarnings&&\"undefined\"!=typeof console&&console.warn&&console.warn(\"Deprecation warning: \"+e)}function n(a,i){var o=!0;return f(function(){if(null!=g.deprecationHandler&&g.deprecationHandler(null,a),o){for(var e,t=[],n=0;n<arguments.length;n++){if(e=\"\",\"object\"==typeof arguments[n]){for(var r in e+=\"\\n[\"+n+\"] \",arguments[0])e+=r+\": \"+arguments[0][r]+\", \";e=e.slice(0,-2)}else e=arguments[n];t.push(e)}E(a+\"\\nArguments: \"+Array.prototype.slice.call(t).join(\"\")+\"\\n\"+(new Error).stack),o=!1}return i.apply(this,arguments)},i)}var r,S={};function M(e,t){null!=g.deprecationHandler&&g.deprecationHandler(e,t),S[e]||(E(t),S[e]=!0)}function T(e){return e instanceof Function||\"[object Function]\"===Object.prototype.toString.call(e)}function C(e,t){var n,r=f({},e);for(n in t)v(t,n)&&(u(e[n])&&u(t[n])?(r[n]={},f(r[n],e[n]),f(r[n],t[n])):null!=t[n]?r[n]=t[n]:delete r[n]);for(n in e)v(e,n)&&!v(t,n)&&u(e[n])&&(r[n]=f({},r[n]));return r}function D(e){null!=e&&this.set(e)}g.suppressDeprecationWarnings=!1,g.deprecationHandler=null,r=Object.keys?Object.keys:function(e){var t,n=[];for(t in e)v(e,t)&&n.push(t);return n};var O={};function j(e,t){var n=e.toLowerCase();O[n]=O[n+\"s\"]=O[t]=e}function N(e){return\"string\"==typeof e?O[e]||O[e.toLowerCase()]:void 0}function z(e){var t,n,r={};for(n in e)v(e,n)&&(t=N(n))&&(r[t]=e[n]);return r}var P={};function L(e,t){P[e]=t}function R(e){var t=[];for(var n in e)t.push({unit:n,priority:P[n]});return t.sort(function(e,t){return e.priority-t.priority}),t}function Y(e,t,n){var r=\"\"+Math.abs(e),a=t-r.length,i=0<=e;return(i?n?\"+\":\"\":\"-\")+Math.pow(10,Math.max(0,a)).toString().substr(1)+r}var W=/(\\[[^\\[]*\\])|(\\\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,q=/(\\[[^\\[]*\\])|(\\\\)?(LTS|LT|LL?L?L?|l{1,4})/g,I={},H={};function F(e,t,n,r){var a=r;\"string\"==typeof r&&(a=function(){return this[r]()}),e&&(H[e]=a),t&&(H[t[0]]=function(){return Y(a.apply(this,arguments),t[1],t[2])}),n&&(H[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),e)})}function B(e,t){return e.isValid()?(t=G(t,e.localeData()),I[t]=I[t]||function(r){var e,a,t,i=r.match(W);for(e=0,a=i.length;e<a;e++)H[i[e]]?i[e]=H[i[e]]:i[e]=(t=i[e]).match(/\\[[\\s\\S]/)?t.replace(/^\\[|\\]$/g,\"\"):t.replace(/\\\\/g,\"\");return function(e){var t,n=\"\";for(t=0;t<a;t++)n+=T(i[t])?i[t].call(e,r):i[t];return n}}(t),I[t](e)):e.localeData().invalidDate()}function G(e,t){var n=5;function r(e){return t.longDateFormat(e)||e}for(q.lastIndex=0;0<=n&&q.test(e);)e=e.replace(q,r),q.lastIndex=0,n-=1;return e}var U=/\\d/,$=/\\d\\d/,V=/\\d{3}/,J=/\\d{4}/,K=/[+-]?\\d{6}/,X=/\\d\\d?/,Z=/\\d\\d\\d\\d?/,Q=/\\d\\d\\d\\d\\d\\d?/,ee=/\\d{1,3}/,te=/\\d{1,4}/,ne=/[+-]?\\d{1,6}/,re=/\\d+/,ae=/[+-]?\\d+/,ie=/Z|[+-]\\d\\d:?\\d\\d/gi,oe=/Z|[+-]\\d\\d(?::?\\d\\d)?/gi,se=/[0-9]{0,256}['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFF07\\uFF10-\\uFFEF]{1,256}|[\\u0600-\\u06FF\\/]{1,256}(\\s*?[\\u0600-\\u06FF]{1,256}){1,2}/i,ue={};function ce(e,n,r){ue[e]=T(n)?n:function(e,t){return e&&r?r:n}}function le(e,t){return v(ue,e)?ue[e](t._strict,t._locale):new RegExp(fe(e.replace(\"\\\\\",\"\").replace(/\\\\(\\[)|\\\\(\\])|\\[([^\\]\\[]*)\\]|\\\\(.)/g,function(e,t,n,r,a){return t||n||r||a})))}function fe(e){return e.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g,\"\\\\$&\")}var he={};function de(e,n){var t,r=n;for(\"string\"==typeof e&&(e=[e]),l(n)&&(r=function(e,t){t[n]=x(e)}),t=0;t<e.length;t++)he[e[t]]=r}function pe(e,a){de(e,function(e,t,n,r){n._w=n._w||{},a(e,n._w,n,r)})}var me=0,ge=1,ve=2,ye=3,_e=4,be=5,we=6,Ae=7,xe=8;function ke(e){return Ee(e)?366:365}function Ee(e){return e%4==0&&e%100!=0||e%400==0}F(\"Y\",0,0,function(){var e=this.year();return e<=9999?\"\"+e:\"+\"+e}),F(0,[\"YY\",2],0,function(){return this.year()%100}),F(0,[\"YYYY\",4],0,\"year\"),F(0,[\"YYYYY\",5],0,\"year\"),F(0,[\"YYYYYY\",6,!0],0,\"year\"),j(\"year\",\"y\"),L(\"year\",1),ce(\"Y\",ae),ce(\"YY\",X,$),ce(\"YYYY\",te,J),ce(\"YYYYY\",ne,K),ce(\"YYYYYY\",ne,K),de([\"YYYYY\",\"YYYYYY\"],me),de(\"YYYY\",function(e,t){t[me]=2===e.length?g.parseTwoDigitYear(e):x(e)}),de(\"YY\",function(e,t){t[me]=g.parseTwoDigitYear(e)}),de(\"Y\",function(e,t){t[me]=parseInt(e,10)}),g.parseTwoDigitYear=function(e){return x(e)+(68<x(e)?1900:2e3)};var Se,Me=Te(\"FullYear\",!0);function Te(t,n){return function(e){return null!=e?(De(this,t,e),g.updateOffset(this,n),this):Ce(this,t)}}function Ce(e,t){return e.isValid()?e._d[\"get\"+(e._isUTC?\"UTC\":\"\")+t]():NaN}function De(e,t,n){e.isValid()&&!isNaN(n)&&(\"FullYear\"===t&&Ee(e.year())&&1===e.month()&&29===e.date()?e._d[\"set\"+(e._isUTC?\"UTC\":\"\")+t](n,e.month(),Oe(n,e.month())):e._d[\"set\"+(e._isUTC?\"UTC\":\"\")+t](n))}function Oe(e,t){if(isNaN(e)||isNaN(t))return NaN;var n,r=(t%(n=12)+n)%n;return e+=(t-r)/12,1===r?Ee(e)?29:28:31-r%7%2}Se=Array.prototype.indexOf?Array.prototype.indexOf:function(e){var t;for(t=0;t<this.length;++t)if(this[t]===e)return t;return-1},F(\"M\",[\"MM\",2],\"Mo\",function(){return this.month()+1}),F(\"MMM\",0,0,function(e){return this.localeData().monthsShort(this,e)}),F(\"MMMM\",0,0,function(e){return this.localeData().months(this,e)}),j(\"month\",\"M\"),L(\"month\",8),ce(\"M\",X),ce(\"MM\",X,$),ce(\"MMM\",function(e,t){return t.monthsShortRegex(e)}),ce(\"MMMM\",function(e,t){return t.monthsRegex(e)}),de([\"M\",\"MM\"],function(e,t){t[ge]=x(e)-1}),de([\"MMM\",\"MMMM\"],function(e,t,n,r){var a=n._locale.monthsParse(e,r,n._strict);null!=a?t[ge]=a:y(n).invalidMonth=e});var je=/D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?/,Ne=\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ze=\"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec\".split(\"_\");function Pe(e,t,n){var r,a,i,o=e.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],r=0;r<12;++r)i=h([2e3,r]),this._shortMonthsParse[r]=this.monthsShort(i,\"\").toLocaleLowerCase(),this._longMonthsParse[r]=this.months(i,\"\").toLocaleLowerCase();return n?\"MMM\"===t?-1!==(a=Se.call(this._shortMonthsParse,o))?a:null:-1!==(a=Se.call(this._longMonthsParse,o))?a:null:\"MMM\"===t?-1!==(a=Se.call(this._shortMonthsParse,o))?a:-1!==(a=Se.call(this._longMonthsParse,o))?a:null:-1!==(a=Se.call(this._longMonthsParse,o))?a:-1!==(a=Se.call(this._shortMonthsParse,o))?a:null}function Le(e,t){var n;if(!e.isValid())return e;if(\"string\"==typeof t)if(/^\\d+$/.test(t))t=x(t);else if(!l(t=e.localeData().monthsParse(t)))return e;return n=Math.min(e.date(),Oe(e.year(),t)),e._d[\"set\"+(e._isUTC?\"UTC\":\"\")+\"Month\"](t,n),e}function Re(e){return null!=e?(Le(this,e),g.updateOffset(this,!0),this):Ce(this,\"Month\")}var Ye=se,We=se;function qe(){function e(e,t){return t.length-e.length}var t,n,r=[],a=[],i=[];for(t=0;t<12;t++)n=h([2e3,t]),r.push(this.monthsShort(n,\"\")),a.push(this.months(n,\"\")),i.push(this.months(n,\"\")),i.push(this.monthsShort(n,\"\"));for(r.sort(e),a.sort(e),i.sort(e),t=0;t<12;t++)r[t]=fe(r[t]),a[t]=fe(a[t]);for(t=0;t<24;t++)i[t]=fe(i[t]);this._monthsRegex=new RegExp(\"^(\"+i.join(\"|\")+\")\",\"i\"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp(\"^(\"+a.join(\"|\")+\")\",\"i\"),this._monthsShortStrictRegex=new RegExp(\"^(\"+r.join(\"|\")+\")\",\"i\")}function Ie(e){var t=new Date(Date.UTC.apply(null,arguments));return e<100&&0<=e&&isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e),t}function He(e,t,n){var r=7+t-n,a=(7+Ie(e,0,r).getUTCDay()-t)%7;return-a+r-1}function Fe(e,t,n,r,a){var i,o,s=(7+n-r)%7,u=He(e,r,a),c=1+7*(t-1)+s+u;return o=c<=0?ke(i=e-1)+c:c>ke(e)?(i=e+1,c-ke(e)):(i=e,c),{year:i,dayOfYear:o}}function Be(e,t,n){var r,a,i=He(e.year(),t,n),o=Math.floor((e.dayOfYear()-i-1)/7)+1;return o<1?(a=e.year()-1,r=o+Ge(a,t,n)):o>Ge(e.year(),t,n)?(r=o-Ge(e.year(),t,n),a=e.year()+1):(a=e.year(),r=o),{week:r,year:a}}function Ge(e,t,n){var r=He(e,t,n),a=He(e+1,t,n);return(ke(e)-r+a)/7}F(\"w\",[\"ww\",2],\"wo\",\"week\"),F(\"W\",[\"WW\",2],\"Wo\",\"isoWeek\"),j(\"week\",\"w\"),j(\"isoWeek\",\"W\"),L(\"week\",5),L(\"isoWeek\",5),ce(\"w\",X),ce(\"ww\",X,$),ce(\"W\",X),ce(\"WW\",X,$),pe([\"w\",\"ww\",\"W\",\"WW\"],function(e,t,n,r){t[r.substr(0,1)]=x(e)}),F(\"d\",0,\"do\",\"day\"),F(\"dd\",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),F(\"ddd\",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),F(\"dddd\",0,0,function(e){return this.localeData().weekdays(this,e)}),F(\"e\",0,0,\"weekday\"),F(\"E\",0,0,\"isoWeekday\"),j(\"day\",\"d\"),j(\"weekday\",\"e\"),j(\"isoWeekday\",\"E\"),L(\"day\",11),L(\"weekday\",11),L(\"isoWeekday\",11),ce(\"d\",X),ce(\"e\",X),ce(\"E\",X),ce(\"dd\",function(e,t){return t.weekdaysMinRegex(e)}),ce(\"ddd\",function(e,t){return t.weekdaysShortRegex(e)}),ce(\"dddd\",function(e,t){return t.weekdaysRegex(e)}),pe([\"dd\",\"ddd\",\"dddd\"],function(e,t,n,r){var a=n._locale.weekdaysParse(e,r,n._strict);null!=a?t.d=a:y(n).invalidWeekday=e}),pe([\"d\",\"e\",\"E\"],function(e,t,n,r){t[r]=x(e)});var Ue=\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),$e=\"Sun_Mon_Tue_Wed_Thu_Fri_Sat\".split(\"_\"),Ve=\"Su_Mo_Tu_We_Th_Fr_Sa\".split(\"_\");function Je(e,t,n){var r,a,i,o=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],r=0;r<7;++r)i=h([2e3,1]).day(r),this._minWeekdaysParse[r]=this.weekdaysMin(i,\"\").toLocaleLowerCase(),this._shortWeekdaysParse[r]=this.weekdaysShort(i,\"\").toLocaleLowerCase(),this._weekdaysParse[r]=this.weekdays(i,\"\").toLocaleLowerCase();return n?\"dddd\"===t?-1!==(a=Se.call(this._weekdaysParse,o))?a:null:\"ddd\"===t?-1!==(a=Se.call(this._shortWeekdaysParse,o))?a:null:-1!==(a=Se.call(this._minWeekdaysParse,o))?a:null:\"dddd\"===t?-1!==(a=Se.call(this._weekdaysParse,o))?a:-1!==(a=Se.call(this._shortWeekdaysParse,o))?a:-1!==(a=Se.call(this._minWeekdaysParse,o))?a:null:\"ddd\"===t?-1!==(a=Se.call(this._shortWeekdaysParse,o))?a:-1!==(a=Se.call(this._weekdaysParse,o))?a:-1!==(a=Se.call(this._minWeekdaysParse,o))?a:null:-1!==(a=Se.call(this._minWeekdaysParse,o))?a:-1!==(a=Se.call(this._weekdaysParse,o))?a:-1!==(a=Se.call(this._shortWeekdaysParse,o))?a:null}var Ke=se,Xe=se,Ze=se;function Qe(){function e(e,t){return t.length-e.length}var t,n,r,a,i,o=[],s=[],u=[],c=[];for(t=0;t<7;t++)n=h([2e3,1]).day(t),r=this.weekdaysMin(n,\"\"),a=this.weekdaysShort(n,\"\"),i=this.weekdays(n,\"\"),o.push(r),s.push(a),u.push(i),c.push(r),c.push(a),c.push(i);for(o.sort(e),s.sort(e),u.sort(e),c.sort(e),t=0;t<7;t++)s[t]=fe(s[t]),u[t]=fe(u[t]),c[t]=fe(c[t]);this._weekdaysRegex=new RegExp(\"^(\"+c.join(\"|\")+\")\",\"i\"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp(\"^(\"+u.join(\"|\")+\")\",\"i\"),this._weekdaysShortStrictRegex=new RegExp(\"^(\"+s.join(\"|\")+\")\",\"i\"),this._weekdaysMinStrictRegex=new RegExp(\"^(\"+o.join(\"|\")+\")\",\"i\")}function et(){return this.hours()%12||12}function tt(e,t){F(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function nt(e,t){return t._meridiemParse}F(\"H\",[\"HH\",2],0,\"hour\"),F(\"h\",[\"hh\",2],0,et),F(\"k\",[\"kk\",2],0,function(){return this.hours()||24}),F(\"hmm\",0,0,function(){return\"\"+et.apply(this)+Y(this.minutes(),2)}),F(\"hmmss\",0,0,function(){return\"\"+et.apply(this)+Y(this.minutes(),2)+Y(this.seconds(),2)}),F(\"Hmm\",0,0,function(){return\"\"+this.hours()+Y(this.minutes(),2)}),F(\"Hmmss\",0,0,function(){return\"\"+this.hours()+Y(this.minutes(),2)+Y(this.seconds(),2)}),tt(\"a\",!0),tt(\"A\",!1),j(\"hour\",\"h\"),L(\"hour\",13),ce(\"a\",nt),ce(\"A\",nt),ce(\"H\",X),ce(\"h\",X),ce(\"k\",X),ce(\"HH\",X,$),ce(\"hh\",X,$),ce(\"kk\",X,$),ce(\"hmm\",Z),ce(\"hmmss\",Q),ce(\"Hmm\",Z),ce(\"Hmmss\",Q),de([\"H\",\"HH\"],ye),de([\"k\",\"kk\"],function(e,t,n){var r=x(e);t[ye]=24===r?0:r}),de([\"a\",\"A\"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),de([\"h\",\"hh\"],function(e,t,n){t[ye]=x(e),y(n).bigHour=!0}),de(\"hmm\",function(e,t,n){var r=e.length-2;t[ye]=x(e.substr(0,r)),t[_e]=x(e.substr(r)),y(n).bigHour=!0}),de(\"hmmss\",function(e,t,n){var r=e.length-4,a=e.length-2;t[ye]=x(e.substr(0,r)),t[_e]=x(e.substr(r,2)),t[be]=x(e.substr(a)),y(n).bigHour=!0}),de(\"Hmm\",function(e,t,n){var r=e.length-2;t[ye]=x(e.substr(0,r)),t[_e]=x(e.substr(r))}),de(\"Hmmss\",function(e,t,n){var r=e.length-4,a=e.length-2;t[ye]=x(e.substr(0,r)),t[_e]=x(e.substr(r,2)),t[be]=x(e.substr(a))});var rt,at=Te(\"Hours\",!0),it={calendar:{sameDay:\"[Today at] LT\",nextDay:\"[Tomorrow at] LT\",nextWeek:\"dddd [at] LT\",lastDay:\"[Yesterday at] LT\",lastWeek:\"[Last] dddd [at] LT\",sameElse:\"L\"},longDateFormat:{LTS:\"h:mm:ss A\",LT:\"h:mm A\",L:\"MM/DD/YYYY\",LL:\"MMMM D, YYYY\",LLL:\"MMMM D, YYYY h:mm A\",LLLL:\"dddd, MMMM D, YYYY h:mm A\"},invalidDate:\"Invalid date\",ordinal:\"%d\",dayOfMonthOrdinalParse:/\\d{1,2}/,relativeTime:{future:\"in %s\",past:\"%s ago\",s:\"a few seconds\",ss:\"%d seconds\",m:\"a minute\",mm:\"%d minutes\",h:\"an hour\",hh:\"%d hours\",d:\"a day\",dd:\"%d days\",M:\"a month\",MM:\"%d months\",y:\"a year\",yy:\"%d years\"},months:Ne,monthsShort:ze,week:{dow:0,doy:6},weekdays:Ue,weekdaysMin:Ve,weekdaysShort:$e,meridiemParse:/[ap]\\.?m?\\.?/i},ot={},st={};function ut(e){return e?e.toLowerCase().replace(\"_\",\"-\"):e}function ct(e){var t=null;if(!ot[e]&&Un&&Un.exports)try{t=rt._abbr;var n=$n;n(\"./locale/\"+e),lt(t)}catch(e){}return ot[e]}function lt(e,t){var n;return e&&((n=i(t)?ht(e):ft(e,t))?rt=n:\"undefined\"!=typeof console&&console.warn&&console.warn(\"Locale \"+e+\" not found. Did you forget to load it?\")),rt._abbr}function ft(e,t){if(null===t)return delete ot[e],null;var n,r=it;if(t.abbr=e,null!=ot[e])M(\"defineLocaleOverride\",\"use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info.\"),r=ot[e]._config;else if(null!=t.parentLocale)if(null!=ot[t.parentLocale])r=ot[t.parentLocale]._config;else{if(null==(n=ct(t.parentLocale)))return st[t.parentLocale]||(st[t.parentLocale]=[]),st[t.parentLocale].push({name:e,config:t}),null;r=n._config}return ot[e]=new D(C(r,t)),st[e]&&st[e].forEach(function(e){ft(e.name,e.config)}),lt(e),ot[e]}function ht(e){var t;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return rt;if(!s(e)){if(t=ct(e))return t;e=[e]}return function(e){for(var t,n,r,a,i=0;i<e.length;){for(a=ut(e[i]).split(\"-\"),t=a.length,n=(n=ut(e[i+1]))?n.split(\"-\"):null;0<t;){if(r=ct(a.slice(0,t).join(\"-\")))return r;if(n&&n.length>=t&&k(a,n,!0)>=t-1)break;t--}i++}return rt}(e)}function dt(e){var t,n=e._a;return n&&-2===y(e).overflow&&(t=n[ge]<0||11<n[ge]?ge:n[ve]<1||n[ve]>Oe(n[me],n[ge])?ve:n[ye]<0||24<n[ye]||24===n[ye]&&(0!==n[_e]||0!==n[be]||0!==n[we])?ye:n[_e]<0||59<n[_e]?_e:n[be]<0||59<n[be]?be:n[we]<0||999<n[we]?we:-1,y(e)._overflowDayOfYear&&(t<me||ve<t)&&(t=ve),y(e)._overflowWeeks&&-1===t&&(t=Ae),y(e)._overflowWeekday&&-1===t&&(t=xe),y(e).overflow=t),e}function pt(e,t,n){return null!=e?e:null!=t?t:n}function mt(e){var t,n,r,a,i,o,s,u=[];if(!e._d){for(o=e,s=void 0,s=new Date(g.now()),r=o._useUTC?[s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate()]:[s.getFullYear(),s.getMonth(),s.getDate()],e._w&&null==e._a[ve]&&null==e._a[ge]&&function(e){var t,n,r,a,i,o,s,u;if(null!=(t=e._w).GG||null!=t.W||null!=t.E)i=1,o=4,n=pt(t.GG,e._a[me],Be(Dt(),1,4).year),r=pt(t.W,1),((a=pt(t.E,1))<1||7<a)&&(u=!0);else{i=e._locale._week.dow,o=e._locale._week.doy;var c=Be(Dt(),i,o);n=pt(t.gg,e._a[me],c.year),r=pt(t.w,c.week),null!=t.d?((a=t.d)<0||6<a)&&(u=!0):null!=t.e?(a=t.e+i,(t.e<0||6<t.e)&&(u=!0)):a=i}r<1||r>Ge(n,i,o)?y(e)._overflowWeeks=!0:null!=u?y(e)._overflowWeekday=!0:(s=Fe(n,r,a,i,o),e._a[me]=s.year,e._dayOfYear=s.dayOfYear)}(e),null!=e._dayOfYear&&(i=pt(e._a[me],r[me]),(e._dayOfYear>ke(i)||0===e._dayOfYear)&&(y(e)._overflowDayOfYear=!0),n=Ie(i,0,e._dayOfYear),e._a[ge]=n.getUTCMonth(),e._a[ve]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=u[t]=r[t];for(;t<7;t++)e._a[t]=u[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[ye]&&0===e._a[_e]&&0===e._a[be]&&0===e._a[we]&&(e._nextDay=!0,e._a[ye]=0),e._d=(e._useUTC?Ie:function(e,t,n,r,a,i,o){var s=new Date(e,t,n,r,a,i,o);return e<100&&0<=e&&isFinite(s.getFullYear())&&s.setFullYear(e),s}).apply(null,u),a=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[ye]=24),e._w&&void 0!==e._w.d&&e._w.d!==a&&(y(e).weekdayMismatch=!0)}}var gt=/^\\s*((?:[+-]\\d{6}|\\d{4})-(?:\\d\\d-\\d\\d|W\\d\\d-\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?::\\d\\d(?::\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?$/,vt=/^\\s*((?:[+-]\\d{6}|\\d{4})(?:\\d\\d\\d\\d|W\\d\\d\\d|W\\d\\d|\\d\\d\\d|\\d\\d))(?:(T| )(\\d\\d(?:\\d\\d(?:\\d\\d(?:[.,]\\d+)?)?)?)([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?$/,yt=/Z|[+-]\\d\\d(?::?\\d\\d)?/,_t=[[\"YYYYYY-MM-DD\",/[+-]\\d{6}-\\d\\d-\\d\\d/],[\"YYYY-MM-DD\",/\\d{4}-\\d\\d-\\d\\d/],[\"GGGG-[W]WW-E\",/\\d{4}-W\\d\\d-\\d/],[\"GGGG-[W]WW\",/\\d{4}-W\\d\\d/,!1],[\"YYYY-DDD\",/\\d{4}-\\d{3}/],[\"YYYY-MM\",/\\d{4}-\\d\\d/,!1],[\"YYYYYYMMDD\",/[+-]\\d{10}/],[\"YYYYMMDD\",/\\d{8}/],[\"GGGG[W]WWE\",/\\d{4}W\\d{3}/],[\"GGGG[W]WW\",/\\d{4}W\\d{2}/,!1],[\"YYYYDDD\",/\\d{7}/]],bt=[[\"HH:mm:ss.SSSS\",/\\d\\d:\\d\\d:\\d\\d\\.\\d+/],[\"HH:mm:ss,SSSS\",/\\d\\d:\\d\\d:\\d\\d,\\d+/],[\"HH:mm:ss\",/\\d\\d:\\d\\d:\\d\\d/],[\"HH:mm\",/\\d\\d:\\d\\d/],[\"HHmmss.SSSS\",/\\d\\d\\d\\d\\d\\d\\.\\d+/],[\"HHmmss,SSSS\",/\\d\\d\\d\\d\\d\\d,\\d+/],[\"HHmmss\",/\\d\\d\\d\\d\\d\\d/],[\"HHmm\",/\\d\\d\\d\\d/],[\"HH\",/\\d\\d/]],wt=/^\\/?Date\\((\\-?\\d+)/i;function At(e){var t,n,r,a,i,o,s=e._i,u=gt.exec(s)||vt.exec(s);if(u){for(y(e).iso=!0,t=0,n=_t.length;t<n;t++)if(_t[t][1].exec(u[1])){a=_t[t][0],r=!1!==_t[t][2];break}if(null==a)return void(e._isValid=!1);if(u[3]){for(t=0,n=bt.length;t<n;t++)if(bt[t][1].exec(u[3])){i=(u[2]||\" \")+bt[t][0];break}if(null==i)return void(e._isValid=!1)}if(!r&&null!=i)return void(e._isValid=!1);if(u[4]){if(!yt.exec(u[4]))return void(e._isValid=!1);o=\"Z\"}e._f=a+(i||\"\")+(o||\"\"),Mt(e)}else e._isValid=!1}var xt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\\s)?(\\d{1,2})\\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s(\\d{2,4})\\s(\\d\\d):(\\d\\d)(?::(\\d\\d))?\\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\\d{4}))$/;function kt(e,t,n,r,a,i){var o,s,u=[(o=e,s=parseInt(o,10),s<=49?2e3+s:s<=999?1900+s:s),ze.indexOf(t),parseInt(n,10),parseInt(r,10),parseInt(a,10)];return i&&u.push(parseInt(i,10)),u}var Et={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function St(e){var t=xt.exec(e._i.replace(/\\([^)]*\\)|[\\n\\t]/g,\" \").replace(/(\\s\\s+)/g,\" \").replace(/^\\s\\s*/,\"\").replace(/\\s\\s*$/,\"\"));if(t){var n=kt(t[4],t[3],t[2],t[5],t[6],t[7]);if(!function(e,t,n){if(e){var r=$e.indexOf(e),a=new Date(t[0],t[1],t[2]).getDay();if(r!==a)return y(n).weekdayMismatch=!0,n._isValid=!1}return!0}(t[1],n,e))return;e._a=n,e._tzm=function(e,t,n){if(e)return Et[e];if(t)return 0;var r=parseInt(n,10),a=r%100,i=(r-a)/100;return 60*i+a}(t[8],t[9],t[10]),e._d=Ie.apply(null,e._a),e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),y(e).rfc2822=!0}else e._isValid=!1}function Mt(e){if(e._f!==g.ISO_8601)if(e._f!==g.RFC_2822){e._a=[],y(e).empty=!0;var t,n,r,a,i,o=\"\"+e._i,s=o.length,u=0;for(r=G(e._f,e._locale).match(W)||[],t=0;t<r.length;t++)a=r[t],(n=(o.match(le(a,e))||[])[0])&&(0<(i=o.substr(0,o.indexOf(n))).length&&y(e).unusedInput.push(i),o=o.slice(o.indexOf(n)+n.length),u+=n.length),H[a]?(n?y(e).empty=!1:y(e).unusedTokens.push(a),d=a,m=e,null!=(p=n)&&v(he,d)&&he[d](p,m._a,m,d)):e._strict&&!n&&y(e).unusedTokens.push(a);y(e).charsLeftOver=s-u,0<o.length&&y(e).unusedInput.push(o),e._a[ye]<=12&&!0===y(e).bigHour&&0<e._a[ye]&&(y(e).bigHour=void 0),y(e).parsedDateParts=e._a.slice(0),y(e).meridiem=e._meridiem,e._a[ye]=(c=e._locale,l=e._a[ye],null==(f=e._meridiem)?l:null!=c.meridiemHour?c.meridiemHour(l,f):(null!=c.isPM&&((h=c.isPM(f))&&l<12&&(l+=12),h||12!==l||(l=0)),l)),mt(e),dt(e)}else St(e);else At(e);var c,l,f,h,d,p,m}function Tt(e){var t,n,r=e._i,a=e._f;return e._locale=e._locale||ht(e._l),null===r||void 0===a&&\"\"===r?p({nullInput:!0}):(\"string\"==typeof r&&(e._i=r=e._locale.preparse(r)),w(r)?new b(dt(r)):(o(r)?e._d=r:s(a)?function(e){var t,n,r,a,i;if(0===e._f.length)return y(e).invalidFormat=!0,e._d=new Date(NaN);for(a=0;a<e._f.length;a++)i=0,t=_({},e),null!=e._useUTC&&(t._useUTC=e._useUTC),t._f=e._f[a],Mt(t),d(t)&&(i+=y(t).charsLeftOver,i+=10*y(t).unusedTokens.length,y(t).score=i,(null==r||i<r)&&(r=i,n=t));f(e,n||t)}(e):a?Mt(e):i(n=(t=e)._i)?t._d=new Date(g.now()):o(n)?t._d=new Date(n.valueOf()):\"string\"==typeof n?function(e){var t=wt.exec(e._i);if(null!==t)return e._d=new Date(+t[1]);At(e),!1===e._isValid&&(delete e._isValid,St(e),!1===e._isValid&&(delete e._isValid,g.createFromInputFallback(e)))}(t):s(n)?(t._a=c(n.slice(0),function(e){return parseInt(e,10)}),mt(t)):u(n)?function(e){if(!e._d){var t=z(e._i);e._a=c([t.year,t.month,t.day||t.date,t.hour,t.minute,t.second,t.millisecond],function(e){return e&&parseInt(e,10)}),mt(e)}}(t):l(n)?t._d=new Date(n):g.createFromInputFallback(t),d(e)||(e._d=null),e))}function Ct(e,t,n,r,a){var i,o={};return!0!==n&&!1!==n||(r=n,n=void 0),(u(e)&&function(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var t;for(t in e)if(e.hasOwnProperty(t))return!1;return!0}(e)||s(e)&&0===e.length)&&(e=void 0),o._isAMomentObject=!0,o._useUTC=o._isUTC=a,o._l=n,o._i=e,o._f=t,o._strict=r,(i=new b(dt(Tt(o))))._nextDay&&(i.add(1,\"d\"),i._nextDay=void 0),i}function Dt(e,t,n,r){return Ct(e,t,n,r,!1)}g.createFromInputFallback=n(\"value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.\",function(e){e._d=new Date(e._i+(e._useUTC?\" UTC\":\"\"))}),g.ISO_8601=function(){},g.RFC_2822=function(){};var Ot=n(\"moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var e=Dt.apply(null,arguments);return this.isValid()&&e.isValid()?e<this?this:e:p()}),jt=n(\"moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/\",function(){var e=Dt.apply(null,arguments);return this.isValid()&&e.isValid()?this<e?this:e:p()});function Nt(e,t){var n,r;if(1===t.length&&s(t[0])&&(t=t[0]),!t.length)return Dt();for(n=t[0],r=1;r<t.length;++r)t[r].isValid()&&!t[r][e](n)||(n=t[r]);return n}var zt=[\"year\",\"quarter\",\"month\",\"week\",\"day\",\"hour\",\"minute\",\"second\",\"millisecond\"];function Pt(e){var t=z(e),n=t.year||0,r=t.quarter||0,a=t.month||0,i=t.week||t.isoWeek||0,o=t.day||0,s=t.hour||0,u=t.minute||0,c=t.second||0,l=t.millisecond||0;this._isValid=function(e){for(var t in e)if(-1===Se.call(zt,t)||null!=e[t]&&isNaN(e[t]))return!1;for(var n=!1,r=0;r<zt.length;++r)if(e[zt[r]]){if(n)return!1;parseFloat(e[zt[r]])!==x(e[zt[r]])&&(n=!0)}return!0}(t),this._milliseconds=+l+1e3*c+6e4*u+1e3*s*60*60,this._days=+o+7*i,this._months=+a+3*r+12*n,this._data={},this._locale=ht(),this._bubble()}function Lt(e){return e instanceof Pt}function Rt(e){return e<0?-1*Math.round(-1*e):Math.round(e)}function Yt(e,n){F(e,0,0,function(){var e=this.utcOffset(),t=\"+\";return e<0&&(e=-e,t=\"-\"),t+Y(~~(e/60),2)+n+Y(~~e%60,2)})}Yt(\"Z\",\":\"),Yt(\"ZZ\",\"\"),ce(\"Z\",oe),ce(\"ZZ\",oe),de([\"Z\",\"ZZ\"],function(e,t,n){n._useUTC=!0,n._tzm=qt(oe,e)});var Wt=/([\\+\\-]|\\d\\d)/gi;function qt(e,t){var n=(t||\"\").match(e);if(null===n)return null;var r=n[n.length-1]||[],a=(r+\"\").match(Wt)||[\"-\",0,0],i=60*a[1]+x(a[2]);return 0===i?0:\"+\"===a[0]?i:-i}function It(e,t){var n,r;return t._isUTC?(n=t.clone(),r=(w(e)||o(e)?e.valueOf():Dt(e).valueOf())-n.valueOf(),n._d.setTime(n._d.valueOf()+r),g.updateOffset(n,!1),n):Dt(e).local()}function Ht(e){return 15*-Math.round(e._d.getTimezoneOffset()/15)}function Ft(){return!!this.isValid()&&this._isUTC&&0===this._offset}g.updateOffset=function(){};var Bt=/^(\\-|\\+)?(?:(\\d*)[. ])?(\\d+)\\:(\\d+)(?:\\:(\\d+)(\\.\\d*)?)?$/,Gt=/^(-|\\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function Ut(e,t){var n,r,a,i,o,s,u=e,c=null;return Lt(e)?u={ms:e._milliseconds,d:e._days,M:e._months}:l(e)?(u={},t?u[t]=e:u.milliseconds=e):(c=Bt.exec(e))?(n=\"-\"===c[1]?-1:1,u={y:0,d:x(c[ve])*n,h:x(c[ye])*n,m:x(c[_e])*n,s:x(c[be])*n,ms:x(Rt(1e3*c[we]))*n}):(c=Gt.exec(e))?(n=\"-\"===c[1]?-1:1,u={y:$t(c[2],n),M:$t(c[3],n),w:$t(c[4],n),d:$t(c[5],n),h:$t(c[6],n),m:$t(c[7],n),s:$t(c[8],n)}):null==u?u={}:\"object\"==typeof u&&(\"from\"in u||\"to\"in u)&&(i=Dt(u.from),o=Dt(u.to),a=i.isValid()&&o.isValid()?(o=It(o,i),i.isBefore(o)?s=Vt(i,o):((s=Vt(o,i)).milliseconds=-s.milliseconds,s.months=-s.months),s):{milliseconds:0,months:0},(u={}).ms=a.milliseconds,u.M=a.months),r=new Pt(u),Lt(e)&&v(e,\"_locale\")&&(r._locale=e._locale),r}function $t(e,t){var n=e&&parseFloat(e.replace(\",\",\".\"));return(isNaN(n)?0:n)*t}function Vt(e,t){var n={milliseconds:0,months:0};return n.months=t.month()-e.month()+12*(t.year()-e.year()),e.clone().add(n.months,\"M\").isAfter(t)&&--n.months,n.milliseconds=+t-+e.clone().add(n.months,\"M\"),n}function Jt(r,a){return function(e,t){var n;return null===t||isNaN(+t)||(M(a,\"moment().\"+a+\"(period, number) is deprecated. Please use moment().\"+a+\"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.\"),n=e,e=t,t=n),Kt(this,Ut(e=\"string\"==typeof e?+e:e,t),r),this}}function Kt(e,t,n,r){var a=t._milliseconds,i=Rt(t._days),o=Rt(t._months);e.isValid()&&(r=null==r||r,o&&Le(e,Ce(e,\"Month\")+o*n),i&&De(e,\"Date\",Ce(e,\"Date\")+i*n),a&&e._d.setTime(e._d.valueOf()+a*n),r&&g.updateOffset(e,i||o))}Ut.fn=Pt.prototype,Ut.invalid=function(){return Ut(NaN)};var Xt=Jt(1,\"add\"),Zt=Jt(-1,\"subtract\");function Qt(e,t){var n,r,a=12*(t.year()-e.year())+(t.month()-e.month()),i=e.clone().add(a,\"months\");return r=t-i<0?(n=e.clone().add(a-1,\"months\"),(t-i)/(i-n)):(n=e.clone().add(a+1,\"months\"),(t-i)/(n-i)),-(a+r)||0}function en(e){var t;return void 0===e?this._locale._abbr:(null!=(t=ht(e))&&(this._locale=t),this)}g.defaultFormat=\"YYYY-MM-DDTHH:mm:ssZ\",g.defaultFormatUtc=\"YYYY-MM-DDTHH:mm:ss[Z]\";var tn=n(\"moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.\",function(e){return void 0===e?this.localeData():this.locale(e)});function nn(){return this._locale}function rn(e,t){F(0,[e,e.length],0,t)}function an(e,t,n,r,a){var i;return null==e?Be(this,r,a).year:((i=Ge(e,r,a))<t&&(t=i),function(e,t,n,r,a){var i=Fe(e,t,n,r,a),o=Ie(i.year,0,i.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}.call(this,e,t,n,r,a))}F(0,[\"gg\",2],0,function(){return this.weekYear()%100}),F(0,[\"GG\",2],0,function(){return this.isoWeekYear()%100}),rn(\"gggg\",\"weekYear\"),rn(\"ggggg\",\"weekYear\"),rn(\"GGGG\",\"isoWeekYear\"),rn(\"GGGGG\",\"isoWeekYear\"),j(\"weekYear\",\"gg\"),j(\"isoWeekYear\",\"GG\"),L(\"weekYear\",1),L(\"isoWeekYear\",1),ce(\"G\",ae),ce(\"g\",ae),ce(\"GG\",X,$),ce(\"gg\",X,$),ce(\"GGGG\",te,J),ce(\"gggg\",te,J),ce(\"GGGGG\",ne,K),ce(\"ggggg\",ne,K),pe([\"gggg\",\"ggggg\",\"GGGG\",\"GGGGG\"],function(e,t,n,r){t[r.substr(0,2)]=x(e)}),pe([\"gg\",\"GG\"],function(e,t,n,r){t[r]=g.parseTwoDigitYear(e)}),F(\"Q\",0,\"Qo\",\"quarter\"),j(\"quarter\",\"Q\"),L(\"quarter\",7),ce(\"Q\",U),de(\"Q\",function(e,t){t[ge]=3*(x(e)-1)}),F(\"D\",[\"DD\",2],\"Do\",\"date\"),j(\"date\",\"D\"),L(\"date\",9),ce(\"D\",X),ce(\"DD\",X,$),ce(\"Do\",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),de([\"D\",\"DD\"],ve),de(\"Do\",function(e,t){t[ve]=x(e.match(X)[0])});var on=Te(\"Date\",!0);F(\"DDD\",[\"DDDD\",3],\"DDDo\",\"dayOfYear\"),j(\"dayOfYear\",\"DDD\"),L(\"dayOfYear\",4),ce(\"DDD\",ee),ce(\"DDDD\",V),de([\"DDD\",\"DDDD\"],function(e,t,n){n._dayOfYear=x(e)}),F(\"m\",[\"mm\",2],0,\"minute\"),j(\"minute\",\"m\"),L(\"minute\",14),ce(\"m\",X),ce(\"mm\",X,$),de([\"m\",\"mm\"],_e);var sn=Te(\"Minutes\",!1);F(\"s\",[\"ss\",2],0,\"second\"),j(\"second\",\"s\"),L(\"second\",15),ce(\"s\",X),ce(\"ss\",X,$),de([\"s\",\"ss\"],be);var un,cn=Te(\"Seconds\",!1);for(F(\"S\",0,0,function(){return~~(this.millisecond()/100)}),F(0,[\"SS\",2],0,function(){return~~(this.millisecond()/10)}),F(0,[\"SSS\",3],0,\"millisecond\"),F(0,[\"SSSS\",4],0,function(){return 10*this.millisecond()}),F(0,[\"SSSSS\",5],0,function(){return 100*this.millisecond()}),F(0,[\"SSSSSS\",6],0,function(){return 1e3*this.millisecond()}),F(0,[\"SSSSSSS\",7],0,function(){return 1e4*this.millisecond()}),F(0,[\"SSSSSSSS\",8],0,function(){return 1e5*this.millisecond()}),F(0,[\"SSSSSSSSS\",9],0,function(){return 1e6*this.millisecond()}),j(\"millisecond\",\"ms\"),L(\"millisecond\",16),ce(\"S\",ee,U),ce(\"SS\",ee,$),ce(\"SSS\",ee,V),un=\"SSSS\";un.length<=9;un+=\"S\")ce(un,re);function ln(e,t){t[we]=x(1e3*(\"0.\"+e))}for(un=\"S\";un.length<=9;un+=\"S\")de(un,ln);var fn=Te(\"Milliseconds\",!1);F(\"z\",0,0,\"zoneAbbr\"),F(\"zz\",0,0,\"zoneName\");var hn=b.prototype;function dn(e){return e}hn.add=Xt,hn.calendar=function(e,t){var n=e||Dt(),r=It(n,this).startOf(\"day\"),a=g.calendarFormat(this,r)||\"sameElse\",i=t&&(T(t[a])?t[a].call(this,n):t[a]);return this.format(i||this.localeData().calendar(a,this,Dt(n)))},hn.clone=function(){return new b(this)},hn.diff=function(e,t,n){var r,a,i;if(!this.isValid())return NaN;if(!(r=It(e,this)).isValid())return NaN;switch(a=6e4*(r.utcOffset()-this.utcOffset()),t=N(t)){case\"year\":i=Qt(this,r)/12;break;case\"month\":i=Qt(this,r);break;case\"quarter\":i=Qt(this,r)/3;break;case\"second\":i=(this-r)/1e3;break;case\"minute\":i=(this-r)/6e4;break;case\"hour\":i=(this-r)/36e5;break;case\"day\":i=(this-r-a)/864e5;break;case\"week\":i=(this-r-a)/6048e5;break;default:i=this-r}return n?i:A(i)},hn.endOf=function(e){return void 0===(e=N(e))||\"millisecond\"===e?this:(\"date\"===e&&(e=\"day\"),this.startOf(e).add(1,\"isoWeek\"===e?\"week\":e).subtract(1,\"ms\"))},hn.format=function(e){e||(e=this.isUtc()?g.defaultFormatUtc:g.defaultFormat);var t=B(this,e);return this.localeData().postformat(t)},hn.from=function(e,t){return this.isValid()&&(w(e)&&e.isValid()||Dt(e).isValid())?Ut({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},hn.fromNow=function(e){return this.from(Dt(),e)},hn.to=function(e,t){return this.isValid()&&(w(e)&&e.isValid()||Dt(e).isValid())?Ut({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},hn.toNow=function(e){return this.to(Dt(),e)},hn.get=function(e){return T(this[e=N(e)])?this[e]():this},hn.invalidAt=function(){return y(this).overflow},hn.isAfter=function(e,t){var n=w(e)?e:Dt(e);return!(!this.isValid()||!n.isValid())&&(\"millisecond\"===(t=N(t)||\"millisecond\")?this.valueOf()>n.valueOf():n.valueOf()<this.clone().startOf(t).valueOf())},hn.isBefore=function(e,t){var n=w(e)?e:Dt(e);return!(!this.isValid()||!n.isValid())&&(\"millisecond\"===(t=N(t)||\"millisecond\")?this.valueOf()<n.valueOf():this.clone().endOf(t).valueOf()<n.valueOf())},hn.isBetween=function(e,t,n,r){var a=w(e)?e:Dt(e),i=w(t)?t:Dt(t);return!!(this.isValid()&&a.isValid()&&i.isValid())&&(\"(\"===(r=r||\"()\")[0]?this.isAfter(a,n):!this.isBefore(a,n))&&(\")\"===r[1]?this.isBefore(i,n):!this.isAfter(i,n))},hn.isSame=function(e,t){var n,r=w(e)?e:Dt(e);return!(!this.isValid()||!r.isValid())&&(\"millisecond\"===(t=N(t)||\"millisecond\")?this.valueOf()===r.valueOf():(n=r.valueOf(),this.clone().startOf(t).valueOf()<=n&&n<=this.clone().endOf(t).valueOf()))},hn.isSameOrAfter=function(e,t){return this.isSame(e,t)||this.isAfter(e,t)},hn.isSameOrBefore=function(e,t){return this.isSame(e,t)||this.isBefore(e,t)},hn.isValid=function(){return d(this)},hn.lang=tn,hn.locale=en,hn.localeData=nn,hn.max=jt,hn.min=Ot,hn.parsingFlags=function(){return f({},y(this))},hn.set=function(e,t){if(\"object\"==typeof e)for(var n=R(e=z(e)),r=0;r<n.length;r++)this[n[r].unit](e[n[r].unit]);else if(T(this[e=N(e)]))return this[e](t);return this},hn.startOf=function(e){switch(e=N(e)){case\"year\":this.month(0);case\"quarter\":case\"month\":this.date(1);case\"week\":case\"isoWeek\":case\"day\":case\"date\":this.hours(0);case\"hour\":this.minutes(0);case\"minute\":this.seconds(0);case\"second\":this.milliseconds(0)}return\"week\"===e&&this.weekday(0),\"isoWeek\"===e&&this.isoWeekday(1),\"quarter\"===e&&this.month(3*Math.floor(this.month()/3)),this},hn.subtract=Zt,hn.toArray=function(){return[this.year(),this.month(),this.date(),this.hour(),this.minute(),this.second(),this.millisecond()]},hn.toObject=function(){return{years:this.year(),months:this.month(),date:this.date(),hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()}},hn.toDate=function(){return new Date(this.valueOf())},hn.toISOString=function(e){if(!this.isValid())return null;var t=!0!==e,n=t?this.clone().utc():this;return n.year()<0||9999<n.year()?B(n,t?\"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]\":\"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ\"):T(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace(\"Z\",B(n,\"Z\")):B(n,t?\"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]\":\"YYYY-MM-DD[T]HH:mm:ss.SSSZ\")},hn.inspect=function(){if(!this.isValid())return\"moment.invalid(/* \"+this._i+\" */)\";var e=\"moment\",t=\"\";this.isLocal()||(e=0===this.utcOffset()?\"moment.utc\":\"moment.parseZone\",t=\"Z\");var n=\"[\"+e+'(\"]',r=0<=this.year()&&this.year()<=9999?\"YYYY\":\"YYYYYY\",a=t+'[\")]';return this.format(n+r+\"-MM-DD[T]HH:mm:ss.SSS\"+a)},hn.toJSON=function(){return this.isValid()?this.toISOString():null},hn.toString=function(){return this.clone().locale(\"en\").format(\"ddd MMM DD YYYY HH:mm:ss [GMT]ZZ\")},hn.unix=function(){return Math.floor(this.valueOf()/1e3)},hn.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},hn.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},hn.year=Me,hn.isLeapYear=function(){return Ee(this.year())},hn.weekYear=function(e){return an.call(this,e,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)},hn.isoWeekYear=function(e){return an.call(this,e,this.isoWeek(),this.isoWeekday(),1,4)},hn.quarter=hn.quarters=function(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)},hn.month=Re,hn.daysInMonth=function(){return Oe(this.year(),this.month())},hn.week=hn.weeks=function(e){var t=this.localeData().week(this);return null==e?t:this.add(7*(e-t),\"d\")},hn.isoWeek=hn.isoWeeks=function(e){var t=Be(this,1,4).week;return null==e?t:this.add(7*(e-t),\"d\")},hn.weeksInYear=function(){var e=this.localeData()._week;return Ge(this.year(),e.dow,e.doy)},hn.isoWeeksInYear=function(){return Ge(this.year(),1,4)},hn.date=on,hn.day=hn.days=function(e){if(!this.isValid())return null!=e?this:NaN;var t,n,r=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=e?(t=e,n=this.localeData(),e=\"string\"==typeof t?isNaN(t)?\"number\"!=typeof(t=n.weekdaysParse(t))?null:t:parseInt(t,10):t,this.add(e-r,\"d\")):r},hn.weekday=function(e){if(!this.isValid())return null!=e?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return null==e?t:this.add(e-t,\"d\")},hn.isoWeekday=function(e){if(!this.isValid())return null!=e?this:NaN;if(null==e)return this.day()||7;var t,n,r=(t=e,n=this.localeData(),\"string\"!=typeof t?isNaN(t)?null:t:n.weekdaysParse(t)%7||7);return this.day(this.day()%7?r:r-7)},hn.dayOfYear=function(e){var t=Math.round((this.clone().startOf(\"day\")-this.clone().startOf(\"year\"))/864e5)+1;return null==e?t:this.add(e-t,\"d\")},hn.hour=hn.hours=at,hn.minute=hn.minutes=sn,hn.second=hn.seconds=cn,hn.millisecond=hn.milliseconds=fn,hn.utcOffset=function(e,t,n){var r,a=this._offset||0;if(!this.isValid())return null!=e?this:NaN;if(null==e)return this._isUTC?a:Ht(this);if(\"string\"==typeof e){if(null===(e=qt(oe,e)))return this}else Math.abs(e)<16&&!n&&(e*=60);return!this._isUTC&&t&&(r=Ht(this)),this._offset=e,this._isUTC=!0,null!=r&&this.add(r,\"m\"),a!==e&&(!t||this._changeInProgress?Kt(this,Ut(e-a,\"m\"),1,!1):this._changeInProgress||(this._changeInProgress=!0,g.updateOffset(this,!0),this._changeInProgress=null)),this},hn.utc=function(e){return this.utcOffset(0,e)},hn.local=function(e){return this._isUTC&&(this.utcOffset(0,e),this._isUTC=!1,e&&this.subtract(Ht(this),\"m\")),this},hn.parseZone=function(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if(\"string\"==typeof this._i){var e=qt(ie,this._i);null!=e?this.utcOffset(e):this.utcOffset(0,!0)}return this},hn.hasAlignedHourOffset=function(e){return!!this.isValid()&&(e=e?Dt(e).utcOffset():0,(this.utcOffset()-e)%60==0)},hn.isDST=function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},hn.isLocal=function(){return!!this.isValid()&&!this._isUTC},hn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},hn.isUtc=Ft,hn.isUTC=Ft,hn.zoneAbbr=function(){return this._isUTC?\"UTC\":\"\"},hn.zoneName=function(){return this._isUTC?\"Coordinated Universal Time\":\"\"},hn.dates=n(\"dates accessor is deprecated. Use date instead.\",on),hn.months=n(\"months accessor is deprecated. Use month instead\",Re),hn.years=n(\"years accessor is deprecated. Use year instead\",Me),hn.zone=n(\"moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/\",function(e,t){return null!=e?(\"string\"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),hn.isDSTShifted=n(\"isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information\",function(){if(!i(this._isDSTShifted))return this._isDSTShifted;var e={};if(_(e,this),(e=Tt(e))._a){var t=e._isUTC?h(e._a):Dt(e._a);this._isDSTShifted=this.isValid()&&0<k(e._a,t.toArray())}else this._isDSTShifted=!1;return this._isDSTShifted});var pn=D.prototype;function mn(e,t,n,r){var a=ht(),i=h().set(r,t);return a[n](i,e)}function gn(e,t,n){if(l(e)&&(t=e,e=void 0),e=e||\"\",null!=t)return mn(e,t,n,\"month\");var r,a=[];for(r=0;r<12;r++)a[r]=mn(e,r,n,\"month\");return a}function vn(e,t,n,r){\"boolean\"==typeof e?l(t)&&(n=t,t=void 0):(t=e,e=!1,l(n=t)&&(n=t,t=void 0)),t=t||\"\";var a,i=ht(),o=e?i._week.dow:0;if(null!=n)return mn(t,(n+o)%7,r,\"day\");var s=[];for(a=0;a<7;a++)s[a]=mn(t,(a+o)%7,r,\"day\");return s}pn.calendar=function(e,t,n){var r=this._calendar[e]||this._calendar.sameElse;return T(r)?r.call(t,n):r},pn.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return!t&&n?(this._longDateFormat[e]=n.replace(/MMMM|MM|DD|dddd/g,function(e){return e.slice(1)}),this._longDateFormat[e]):t},pn.invalidDate=function(){return this._invalidDate},pn.ordinal=function(e){return this._ordinal.replace(\"%d\",e)},pn.preparse=dn,pn.postformat=dn,pn.relativeTime=function(e,t,n,r){var a=this._relativeTime[n];return T(a)?a(e,t,n,r):a.replace(/%d/i,e)},pn.pastFuture=function(e,t){var n=this._relativeTime[0<e?\"future\":\"past\"];return T(n)?n(t):n.replace(/%s/i,t)},pn.set=function(e){var t,n;for(n in e)T(t=e[n])?this[n]=t:this[\"_\"+n]=t;this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+\"|\"+/\\d{1,2}/.source)},pn.months=function(e,t){return e?s(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||je).test(t)?\"format\":\"standalone\"][e.month()]:s(this._months)?this._months:this._months.standalone},pn.monthsShort=function(e,t){return e?s(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[je.test(t)?\"format\":\"standalone\"][e.month()]:s(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},pn.monthsParse=function(e,t,n){var r,a,i;if(this._monthsParseExact)return Pe.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),r=0;r<12;r++){if(a=h([2e3,r]),n&&!this._longMonthsParse[r]&&(this._longMonthsParse[r]=new RegExp(\"^\"+this.months(a,\"\").replace(\".\",\"\")+\"$\",\"i\"),this._shortMonthsParse[r]=new RegExp(\"^\"+this.monthsShort(a,\"\").replace(\".\",\"\")+\"$\",\"i\")),n||this._monthsParse[r]||(i=\"^\"+this.months(a,\"\")+\"|^\"+this.monthsShort(a,\"\"),this._monthsParse[r]=new RegExp(i.replace(\".\",\"\"),\"i\")),n&&\"MMMM\"===t&&this._longMonthsParse[r].test(e))return r;if(n&&\"MMM\"===t&&this._shortMonthsParse[r].test(e))return r;if(!n&&this._monthsParse[r].test(e))return r}},pn.monthsRegex=function(e){return this._monthsParseExact?(v(this,\"_monthsRegex\")||qe.call(this),e?this._monthsStrictRegex:this._monthsRegex):(v(this,\"_monthsRegex\")||(this._monthsRegex=We),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},pn.monthsShortRegex=function(e){return this._monthsParseExact?(v(this,\"_monthsRegex\")||qe.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(v(this,\"_monthsShortRegex\")||(this._monthsShortRegex=Ye),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},pn.week=function(e){return Be(e,this._week.dow,this._week.doy).week},pn.firstDayOfYear=function(){return this._week.doy},pn.firstDayOfWeek=function(){return this._week.dow},pn.weekdays=function(e,t){return e?s(this._weekdays)?this._weekdays[e.day()]:this._weekdays[this._weekdays.isFormat.test(t)?\"format\":\"standalone\"][e.day()]:s(this._weekdays)?this._weekdays:this._weekdays.standalone},pn.weekdaysMin=function(e){return e?this._weekdaysMin[e.day()]:this._weekdaysMin},pn.weekdaysShort=function(e){return e?this._weekdaysShort[e.day()]:this._weekdaysShort},pn.weekdaysParse=function(e,t,n){var r,a,i;if(this._weekdaysParseExact)return Je.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),r=0;r<7;r++){if(a=h([2e3,1]).day(r),n&&!this._fullWeekdaysParse[r]&&(this._fullWeekdaysParse[r]=new RegExp(\"^\"+this.weekdays(a,\"\").replace(\".\",\"\\\\.?\")+\"$\",\"i\"),this._shortWeekdaysParse[r]=new RegExp(\"^\"+this.weekdaysShort(a,\"\").replace(\".\",\"\\\\.?\")+\"$\",\"i\"),this._minWeekdaysParse[r]=new RegExp(\"^\"+this.weekdaysMin(a,\"\").replace(\".\",\"\\\\.?\")+\"$\",\"i\")),this._weekdaysParse[r]||(i=\"^\"+this.weekdays(a,\"\")+\"|^\"+this.weekdaysShort(a,\"\")+\"|^\"+this.weekdaysMin(a,\"\"),this._weekdaysParse[r]=new RegExp(i.replace(\".\",\"\"),\"i\")),n&&\"dddd\"===t&&this._fullWeekdaysParse[r].test(e))return r;if(n&&\"ddd\"===t&&this._shortWeekdaysParse[r].test(e))return r;if(n&&\"dd\"===t&&this._minWeekdaysParse[r].test(e))return r;if(!n&&this._weekdaysParse[r].test(e))return r}},pn.weekdaysRegex=function(e){return this._weekdaysParseExact?(v(this,\"_weekdaysRegex\")||Qe.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(v(this,\"_weekdaysRegex\")||(this._weekdaysRegex=Ke),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},pn.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(v(this,\"_weekdaysRegex\")||Qe.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(v(this,\"_weekdaysShortRegex\")||(this._weekdaysShortRegex=Xe),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},pn.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(v(this,\"_weekdaysRegex\")||Qe.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(v(this,\"_weekdaysMinRegex\")||(this._weekdaysMinRegex=Ze),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},pn.isPM=function(e){return\"p\"===(e+\"\").toLowerCase().charAt(0)},pn.meridiem=function(e,t,n){return 11<e?n?\"pm\":\"PM\":n?\"am\":\"AM\"},lt(\"en\",{dayOfMonthOrdinalParse:/\\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10,n=1===x(e%100/10)?\"th\":1===t?\"st\":2===t?\"nd\":3===t?\"rd\":\"th\";return e+n}}),g.lang=n(\"moment.lang is deprecated. Use moment.locale instead.\",lt),g.langData=n(\"moment.langData is deprecated. Use moment.localeData instead.\",ht);var yn=Math.abs;function _n(e,t,n,r){var a=Ut(t,n);return e._milliseconds+=r*a._milliseconds,e._days+=r*a._days,e._months+=r*a._months,e._bubble()}function bn(e){return e<0?Math.floor(e):Math.ceil(e)}function wn(e){return 4800*e/146097}function An(e){return 146097*e/4800}function xn(e){return function(){return this.as(e)}}var kn=xn(\"ms\"),En=xn(\"s\"),Sn=xn(\"m\"),Mn=xn(\"h\"),Tn=xn(\"d\"),Cn=xn(\"w\"),Dn=xn(\"M\"),On=xn(\"y\");function jn(e){return function(){return this.isValid()?this._data[e]:NaN}}var Nn=jn(\"milliseconds\"),zn=jn(\"seconds\"),Pn=jn(\"minutes\"),Ln=jn(\"hours\"),Rn=jn(\"days\"),Yn=jn(\"months\"),Wn=jn(\"years\"),qn=Math.round,In={ss:44,s:45,m:45,h:22,d:26,M:11},Hn=Math.abs;function Fn(e){return(0<e)-(e<0)||+e}function Bn(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n=Hn(this._milliseconds)/1e3,r=Hn(this._days),a=Hn(this._months);e=A(n/60),t=A(e/60),n%=60,e%=60;var i=A(a/12),o=a%=12,s=r,u=t,c=e,l=n?n.toFixed(3).replace(/\\.?0+$/,\"\"):\"\",f=this.asSeconds();if(!f)return\"P0D\";var h=f<0?\"-\":\"\",d=Fn(this._months)!==Fn(f)?\"-\":\"\",p=Fn(this._days)!==Fn(f)?\"-\":\"\",m=Fn(this._milliseconds)!==Fn(f)?\"-\":\"\";return h+\"P\"+(i?d+i+\"Y\":\"\")+(o?d+o+\"M\":\"\")+(s?p+s+\"D\":\"\")+(u||c||l?\"T\":\"\")+(u?m+u+\"H\":\"\")+(c?m+c+\"M\":\"\")+(l?m+l+\"S\":\"\")}var Gn=Pt.prototype;return Gn.isValid=function(){return this._isValid},Gn.abs=function(){var e=this._data;return this._milliseconds=yn(this._milliseconds),this._days=yn(this._days),this._months=yn(this._months),e.milliseconds=yn(e.milliseconds),e.seconds=yn(e.seconds),e.minutes=yn(e.minutes),e.hours=yn(e.hours),e.months=yn(e.months),e.years=yn(e.years),this},Gn.add=function(e,t){return _n(this,e,t,1)},Gn.subtract=function(e,t){return _n(this,e,t,-1)},Gn.as=function(e){if(!this.isValid())return NaN;var t,n,r=this._milliseconds;if(\"month\"===(e=N(e))||\"year\"===e)return t=this._days+r/864e5,n=this._months+wn(t),\"month\"===e?n:n/12;switch(t=this._days+Math.round(An(this._months)),e){case\"week\":return t/7+r/6048e5;case\"day\":return t+r/864e5;case\"hour\":return 24*t+r/36e5;case\"minute\":return 1440*t+r/6e4;case\"second\":return 86400*t+r/1e3;case\"millisecond\":return Math.floor(864e5*t)+r;default:throw new Error(\"Unknown unit \"+e)}},Gn.asMilliseconds=kn,Gn.asSeconds=En,Gn.asMinutes=Sn,Gn.asHours=Mn,Gn.asDays=Tn,Gn.asWeeks=Cn,Gn.asMonths=Dn,Gn.asYears=On,Gn.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*x(this._months/12):NaN},Gn._bubble=function(){var e,t,n,r,a,i=this._milliseconds,o=this._days,s=this._months,u=this._data;return 0<=i&&0<=o&&0<=s||i<=0&&o<=0&&s<=0||(i+=864e5*bn(An(s)+o),s=o=0),u.milliseconds=i%1e3,e=A(i/1e3),u.seconds=e%60,t=A(e/60),u.minutes=t%60,n=A(t/60),u.hours=n%24,o+=A(n/24),a=A(wn(o)),s+=a,o-=bn(An(a)),r=A(s/12),s%=12,u.days=o,u.months=s,u.years=r,this},Gn.clone=function(){return Ut(this)},Gn.get=function(e){return e=N(e),this.isValid()?this[e+\"s\"]():NaN},Gn.milliseconds=Nn,Gn.seconds=zn,Gn.minutes=Pn,Gn.hours=Ln,Gn.days=Rn,Gn.weeks=function(){return A(this.days()/7)},Gn.months=Yn,Gn.years=Wn,Gn.humanize=function(e){if(!this.isValid())return this.localeData().invalidDate();var t,n,r,a,i,o,s,u,c,l,f,h=this.localeData(),d=(n=!e,r=h,a=Ut(t=this).abs(),i=qn(a.as(\"s\")),o=qn(a.as(\"m\")),s=qn(a.as(\"h\")),u=qn(a.as(\"d\")),c=qn(a.as(\"M\")),l=qn(a.as(\"y\")),(f=i<=In.ss&&[\"s\",i]||i<In.s&&[\"ss\",i]||o<=1&&[\"m\"]||o<In.m&&[\"mm\",o]||s<=1&&[\"h\"]||s<In.h&&[\"hh\",s]||u<=1&&[\"d\"]||u<In.d&&[\"dd\",u]||c<=1&&[\"M\"]||c<In.M&&[\"MM\",c]||l<=1&&[\"y\"]||[\"yy\",l])[2]=n,f[3]=0<+t,f[4]=r,function(e,t,n,r,a){return a.relativeTime(t||1,!!n,e,r)}.apply(null,f));return e&&(d=h.pastFuture(+this,d)),h.postformat(d)},Gn.toISOString=Bn,Gn.toString=Bn,Gn.toJSON=Bn,Gn.locale=en,Gn.localeData=nn,Gn.toIsoString=n(\"toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)\",Bn),Gn.lang=tn,F(\"X\",0,0,\"unix\"),F(\"x\",0,0,\"valueOf\"),ce(\"x\",ae),ce(\"X\",/[+-]?\\d+(\\.\\d{1,3})?/),de(\"X\",function(e,t,n){n._d=new Date(1e3*parseFloat(e,10))}),de(\"x\",function(e,t,n){n._d=new Date(x(e))}),g.version=\"2.23.0\",e=Dt,g.fn=hn,g.min=function(){return Nt(\"isBefore\",[].slice.call(arguments,0))},g.max=function(){return Nt(\"isAfter\",[].slice.call(arguments,0))},g.now=function(){return Date.now?Date.now():+new Date},g.utc=h,g.unix=function(e){return Dt(1e3*e)},g.months=function(e,t){return gn(e,t,\"months\")},g.isDate=o,g.locale=lt,g.invalid=p,g.duration=Ut,g.isMoment=w,g.weekdays=function(e,t,n){return vn(e,t,n,\"weekdays\")},g.parseZone=function(){return Dt.apply(null,arguments).parseZone()},g.localeData=ht,g.isDuration=Lt,g.monthsShort=function(e,t){return gn(e,t,\"monthsShort\")},g.weekdaysMin=function(e,t,n){return vn(e,t,n,\"weekdaysMin\")},g.defineLocale=ft,g.updateLocale=function(e,t){if(null!=t){var n,r,a=it;null!=(r=ct(e))&&(a=r._config),t=C(a,t),(n=new D(t)).parentLocale=ot[e],ot[e]=n,lt(e)}else null!=ot[e]&&(null!=ot[e].parentLocale?ot[e]=ot[e].parentLocale:null!=ot[e]&&delete ot[e]);return ot[e]},g.locales=function(){return r(ot)},g.weekdaysShort=function(e,t,n){return vn(e,t,n,\"weekdaysShort\")},g.normalizeUnits=N,g.relativeTimeRounding=function(e){return void 0!==e?\"function\"==typeof e&&(qn=e,!0):qn},g.relativeTimeThreshold=function(e,t){return void 0!==In[e]&&(void 0===t?In[e]:(In[e]=t,\"s\"===e&&(In.ss=t-1),!0))},g.calendarFormat=function(e,t){var n=e.diff(t,\"days\",!0);return n<-6?\"sameElse\":n<-1?\"lastWeek\":n<0?\"lastDay\":n<1?\"sameDay\":n<2?\"nextDay\":n<7?\"nextWeek\":\"sameElse\"},g.prototype=hn,g.HTML5_FMT={DATETIME_LOCAL:\"YYYY-MM-DDTHH:mm\",DATETIME_LOCAL_SECONDS:\"YYYY-MM-DDTHH:mm:ss\",DATETIME_LOCAL_MS:\"YYYY-MM-DDTHH:mm:ss.SSS\",DATE:\"YYYY-MM-DD\",TIME:\"HH:mm\",TIME_SECONDS:\"HH:mm:ss\",TIME_MS:\"HH:mm:ss.SSS\",WEEK:\"GGGG-[W]WW\",MONTH:\"YYYY-MM\"},g}()}),Xs=e(function(e){var t,n;t=this,n=function(i){var t,o={},s={},c={},l={};i&&\"string\"==typeof i.version||S(\"Moment Timezone requires Moment.js. See https://momentjs.com/timezone/docs/#/use-it/browser/\");var e=i.version.split(\".\"),n=+e[0],r=+e[1];function u(e){return 96<e?e-87:64<e?e-29:e-48}function a(e){var t=0,n=e.split(\".\"),r=n[0],a=n[1]||\"\",i=1,o=0,s=1;for(45===e.charCodeAt(0)&&(s=-(t=1));t<r.length;t++)o=60*o+u(r.charCodeAt(t));for(t=0;t<a.length;t++)i/=60,o+=u(a.charCodeAt(t))*i;return o*s}function f(e){for(var t=0;t<e.length;t++)e[t]=a(e[t])}function h(e,t){var n,r=[];for(n=0;n<t.length;n++)r[n]=e[t[n]];return r}function d(e){var t=e.split(\"|\"),n=t[2].split(\" \"),r=t[3].split(\"\"),a=t[4].split(\" \");return f(n),f(r),f(a),function(e,t){for(var n=0;n<t;n++)e[n]=Math.round((e[n-1]||0)+6e4*e[n]);e[t-1]=1/0}(a,r.length),{name:t[0],abbrs:h(t[1].split(\" \"),r),offsets:h(n,r),untils:a,population:0|t[5]}}function p(e){e&&this._set(d(e))}function m(e){var t=e.toTimeString(),n=t.match(/\\([a-z ]+\\)/i);\"GMT\"===(n=n&&n[0]?(n=n[0].match(/[A-Z]/g))?n.join(\"\"):void 0:(n=t.match(/[A-Z]{3,5}/g))?n[0]:void 0)&&(n=void 0),this.at=+e,this.abbr=n,this.offset=e.getTimezoneOffset()}function g(e){this.zone=e,this.offsetScore=0,this.abbrScore=0}function v(e,t){for(var n,r;r=6e4*((t.at-e.at)/12e4|0);)(n=new m(new Date(e.at+r))).offset===e.offset?e=n:t=n;return e}function y(e,t){return e.offsetScore!==t.offsetScore?e.offsetScore-t.offsetScore:e.abbrScore!==t.abbrScore?e.abbrScore-t.abbrScore:t.zone.population-e.zone.population}function _(e,t){var n,r;for(f(t),n=0;n<t.length;n++)r=t[n],l[r]=l[r]||{},l[r][e]=!0}function b(e){return(e||\"\").toLowerCase().replace(/\\//g,\"_\")}function w(e){var t,n,r,a;for(\"string\"==typeof e&&(e=[e]),t=0;t<e.length;t++)a=b(n=(r=e[t].split(\"|\"))[0]),o[a]=e[t],c[a]=n,_(a,r[2].split(\" \"))}function A(e,t){e=b(e);var n,r=o[e];return r instanceof p?r:\"string\"==typeof r?(r=new p(r),o[e]=r):s[e]&&t!==A&&(n=A(s[e],A))?((r=o[e]=new p)._set(n),r.name=c[e],r):null}function x(e){var t,n,r,a;for(\"string\"==typeof e&&(e=[e]),t=0;t<e.length;t++)r=b((n=e[t].split(\"|\"))[0]),a=b(n[1]),s[r]=a,c[r]=n[0],s[a]=r,c[a]=n[1]}function k(e){w(e.zones),x(e.links),M.dataVersion=e.version}function E(e){var t=\"X\"===e._f||\"x\"===e._f;return!(!e._a||void 0!==e._tzm||t)}function S(e){\"undefined\"!=typeof console&&\"function\"==typeof console.error&&console.error(e)}function M(e){var t=Array.prototype.slice.call(arguments,0,-1),n=arguments[arguments.length-1],r=A(n),a=i.utc.apply(null,t);return r&&!i.isMoment(e)&&E(a)&&a.add(r.parse(a),\"minutes\"),a.tz(n),a}(n<2||2==n&&r<6)&&S(\"Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js \"+i.version+\". See momentjs.com\"),p.prototype={_set:function(e){this.name=e.name,this.abbrs=e.abbrs,this.untils=e.untils,this.offsets=e.offsets,this.population=e.population},_index:function(e){var t,n=+e,r=this.untils;for(t=0;t<r.length;t++)if(n<r[t])return t},parse:function(e){var t,n,r,a,i=+e,o=this.offsets,s=this.untils,u=s.length-1;for(a=0;a<u;a++)if(t=o[a],n=o[a+1],r=o[a?a-1:a],t<n&&M.moveAmbiguousForward?t=n:r<t&&M.moveInvalidForward&&(t=r),i<s[a]-6e4*t)return o[a];return o[u]},abbr:function(e){return this.abbrs[this._index(e)]},offset:function(e){return S(\"zone.offset has been deprecated in favor of zone.utcOffset\"),this.offsets[this._index(e)]},utcOffset:function(e){return this.offsets[this._index(e)]}},g.prototype.scoreOffsetAt=function(e){this.offsetScore+=Math.abs(this.zone.utcOffset(e.at)-e.offset),this.zone.abbr(e.at).replace(/[^A-Z]/g,\"\")!==e.abbr&&this.abbrScore++},M.version=\"0.5.26\",M.dataVersion=\"\",M._zones=o,M._links=s,M._names=c,M.add=w,M.link=x,M.load=k,M.zone=A,M.zoneExists=function e(t){return e.didShowError||(e.didShowError=!0,S(\"moment.tz.zoneExists('\"+t+\"') has been deprecated in favor of !moment.tz.zone('\"+t+\"')\")),!!A(t)},M.guess=function(e){return t&&!e||(t=function(){try{var e=Intl.DateTimeFormat().resolvedOptions().timeZone;if(e&&3<e.length){var t=c[b(e)];if(t)return t;S(\"Moment Timezone found \"+e+\" from the Intl api, but did not have that data loaded.\")}}catch(e){}var n,r,a,i=function(){var e,t,n,r=(new Date).getFullYear()-2,a=new m(new Date(r,0,1)),i=[a];for(n=1;n<48;n++)(t=new m(new Date(r,n,1))).offset!==a.offset&&(e=v(a,t),i.push(e),i.push(new m(new Date(e.at+6e4)))),a=t;for(n=0;n<4;n++)i.push(new m(new Date(r+n,0,1))),i.push(new m(new Date(r+n,6,1)));return i}(),o=i.length,s=function(e){var t,n,r,a=e.length,i={},o=[];for(t=0;t<a;t++)for(n in r=l[e[t].offset]||{})r.hasOwnProperty(n)&&(i[n]=!0);for(t in i)i.hasOwnProperty(t)&&o.push(c[t]);return o}(i),u=[];for(r=0;r<s.length;r++){for(n=new g(A(s[r]),o),a=0;a<o;a++)n.scoreOffsetAt(i[a]);u.push(n)}return u.sort(y),0<u.length?u[0].zone.name:void 0}()),t},M.names=function(){var e,t=[];for(e in c)c.hasOwnProperty(e)&&(o[e]||o[s[e]])&&c[e]&&t.push(c[e]);return t.sort()},M.Zone=p,M.unpack=d,M.unpackBase60=a,M.needsOffset=E,M.moveInvalidForward=!0,M.moveAmbiguousForward=!1;var T,C=i.fn;function D(e){return function(){return this._z?this._z.abbr(this):e.call(this)}}function O(e){return function(){return this._z=null,e.apply(this,arguments)}}i.tz=M,i.defaultZone=null,i.updateOffset=function(e,t){var n,r=i.defaultZone;if(void 0===e._z&&(r&&E(e)&&!e._isUTC&&(e._d=i.utc(e._a)._d,e.utc().add(r.parse(e),\"minutes\")),e._z=r),e._z)if(n=e._z.utcOffset(e),Math.abs(n)<16&&(n/=60),void 0!==e.utcOffset){var a=e._z;e.utcOffset(-n,t),e._z=a}else e.zone(n,t)},C.tz=function(e,t){if(e){if(\"string\"!=typeof e)throw new Error(\"Time zone name must be a string, got \"+e+\" [\"+typeof e+\"]\");return this._z=A(e),this._z?i.updateOffset(this,t):S(\"Moment Timezone has no data for \"+e+\". See http://momentjs.com/timezone/docs/#/data-loading/.\"),this}if(this._z)return this._z.name},C.zoneName=D(C.zoneName),C.zoneAbbr=D(C.zoneAbbr),C.utc=O(C.utc),C.local=O(C.local),C.utcOffset=(T=C.utcOffset,function(){return 0<arguments.length&&(this._z=null),T.apply(this,arguments)}),i.tz.setDefault=function(e){return(n<2||2==n&&r<9)&&S(\"Moment Timezone setDefault() requires Moment.js >= 2.9.0. You are using Moment.js \"+i.version+\".\"),i.defaultZone=e?A(e):null,i};var j=i.momentProperties;return\"[object Array]\"===Object.prototype.toString.call(j)?(j.push(\"_z\"),j.push(\"_a\")):j&&(j._z=null),k({version:\"2019b\",zones:[\"Africa/Abidjan|GMT|0|0||48e5\",\"Africa/Nairobi|EAT|-30|0||47e5\",\"Africa/Algiers|CET|-10|0||26e5\",\"Africa/Lagos|WAT|-10|0||17e6\",\"Africa/Maputo|CAT|-20|0||26e5\",\"Africa/Cairo|EET EEST|-20 -30|01010|1M2m0 gL0 e10 mn0|15e6\",\"Africa/Casablanca|+00 +01|0 -10|010101010101010101010101010101010101|1H3C0 wM0 co0 go0 1o00 s00 dA0 vc0 11A0 A00 e00 y00 11A0 uM0 e00 Dc0 11A0 s00 e00 IM0 WM0 mo0 gM0 LA0 WM0 jA0 e00 28M0 e00 2600 e00 28M0 e00 2600 gM0|32e5\",\"Europe/Paris|CET CEST|-10 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|11e6\",\"Africa/Johannesburg|SAST|-20|0||84e5\",\"Africa/Khartoum|EAT CAT|-30 -20|01|1Usl0|51e5\",\"Africa/Sao_Tome|GMT WAT|0 -10|010|1UQN0 2q00\",\"Africa/Tripoli|EET CET CEST|-20 -10 -20|0120|1IlA0 TA0 1o00|11e5\",\"Africa/Windhoek|CAT WAT|-20 -10|0101010101010|1GQo0 11B0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|32e4\",\"America/Adak|HST HDT|a0 90|01010101010101010101010|1GIc0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|326\",\"America/Anchorage|AKST AKDT|90 80|01010101010101010101010|1GIb0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|30e4\",\"America/Santo_Domingo|AST|40|0||29e5\",\"America/Araguaina|-03 -02|30 20|010|1IdD0 Lz0|14e4\",\"America/Fortaleza|-03|30|0||34e5\",\"America/Asuncion|-03 -04|30 40|01010101010101010101010|1GTf0 1cN0 17b0 1ip0 17b0 1ip0 17b0 1ip0 19X0 1fB0 19X0 1fB0 19X0 1ip0 17b0 1ip0 17b0 1ip0 19X0 1fB0 19X0 1fB0|28e5\",\"America/Panama|EST|50|0||15e5\",\"America/Mexico_City|CST CDT|60 50|01010101010101010101010|1GQw0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0|20e6\",\"America/Bahia|-02 -03|20 30|01|1GCq0|27e5\",\"America/Managua|CST|60|0||22e5\",\"America/La_Paz|-04|40|0||19e5\",\"America/Lima|-05|50|0||11e6\",\"America/Denver|MST MDT|70 60|01010101010101010101010|1GI90 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|26e5\",\"America/Campo_Grande|-03 -04|30 40|0101010101010101|1GCr0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1HB0 FX0|77e4\",\"America/Cancun|CST CDT EST|60 50 50|01010102|1GQw0 1nX0 14p0 1lb0 14p0 1lb0 Dd0|63e4\",\"America/Caracas|-0430 -04|4u 40|01|1QMT0|29e5\",\"America/Chicago|CST CDT|60 50|01010101010101010101010|1GI80 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|92e5\",\"America/Chihuahua|MST MDT|70 60|01010101010101010101010|1GQx0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0|81e4\",\"America/Phoenix|MST|70|0||42e5\",\"America/Los_Angeles|PST PDT|80 70|01010101010101010101010|1GIa0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|15e6\",\"America/New_York|EST EDT|50 40|01010101010101010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|21e6\",\"America/Rio_Branco|-04 -05|40 50|01|1KLE0|31e4\",\"America/Fort_Nelson|PST PDT MST|80 70 70|01010102|1GIa0 1zb0 Op0 1zb0 Op0 1zb0 Op0|39e2\",\"America/Halifax|AST ADT|40 30|01010101010101010101010|1GI60 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|39e4\",\"America/Godthab|-03 -02|30 20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|17e3\",\"America/Grand_Turk|EST EDT AST|50 40 40|0101010121010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 5Ip0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|37e2\",\"America/Havana|CST CDT|50 40|01010101010101010101010|1GQt0 1qM0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0|21e5\",\"America/Metlakatla|PST AKST AKDT|80 90 80|01212120121212121|1PAa0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 uM0 jB0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|14e2\",\"America/Miquelon|-03 -02|30 20|01010101010101010101010|1GI50 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|61e2\",\"America/Montevideo|-02 -03|20 30|01010101|1GI40 1o10 11z0 1o10 11z0 1o10 11z0|17e5\",\"America/Noronha|-02|20|0||30e2\",\"America/Port-au-Prince|EST EDT|50 40|010101010101010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 3iN0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|23e5\",\"Antarctica/Palmer|-03 -04|30 40|010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0|40\",\"America/Santiago|-03 -04|30 40|010101010101010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1zb0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|62e5\",\"America/Sao_Paulo|-02 -03|20 30|0101010101010101|1GCq0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1HB0 FX0|20e6\",\"Atlantic/Azores|-01 +00|10 0|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|25e4\",\"America/St_Johns|NST NDT|3u 2u|01010101010101010101010|1GI5u 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|11e4\",\"Antarctica/Casey|+11 +08|-b0 -80|0101|1GAF0 blz0 3m10|10\",\"Antarctica/Davis|+05 +07|-50 -70|01|1GAI0|70\",\"Pacific/Port_Moresby|+10|-a0|0||25e4\",\"Pacific/Guadalcanal|+11|-b0|0||11e4\",\"Asia/Tashkent|+05|-50|0||23e5\",\"Pacific/Auckland|NZDT NZST|-d0 -c0|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|14e5\",\"Asia/Baghdad|+03|-30|0||66e5\",\"Antarctica/Troll|+00 +02|0 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|40\",\"Asia/Dhaka|+06|-60|0||16e6\",\"Asia/Amman|EET EEST|-20 -30|010101010101010101010|1GPy0 4bX0 Dd0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00|25e5\",\"Asia/Kamchatka|+12|-c0|0||18e4\",\"Asia/Baku|+04 +05|-40 -50|010101010|1GNA0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00|27e5\",\"Asia/Bangkok|+07|-70|0||15e6\",\"Asia/Barnaul|+07 +06|-70 -60|010|1N7v0 3rd0\",\"Asia/Beirut|EET EEST|-20 -30|01010101010101010101010|1GNy0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0|22e5\",\"Asia/Kuala_Lumpur|+08|-80|0||71e5\",\"Asia/Kolkata|IST|-5u|0||15e6\",\"Asia/Chita|+10 +08 +09|-a0 -80 -90|012|1N7s0 3re0|33e4\",\"Asia/Ulaanbaatar|+08 +09|-80 -90|01010|1O8G0 1cJ0 1cP0 1cJ0|12e5\",\"Asia/Shanghai|CST|-80|0||23e6\",\"Asia/Colombo|+0530|-5u|0||22e5\",\"Asia/Damascus|EET EEST|-20 -30|01010101010101010101010|1GPy0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0|26e5\",\"Asia/Dili|+09|-90|0||19e4\",\"Asia/Dubai|+04|-40|0||39e5\",\"Asia/Famagusta|EET EEST +03|-20 -30 -30|0101010101201010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 15U0 2Ks0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0\",\"Asia/Gaza|EET EEST|-20 -30|01010101010101010101010|1GPy0 1a00 1fA0 1cL0 1cN0 1nX0 1210 1nz0 1220 1qL0 WN0 1qL0 WN0 1qL0 11c0 1oo0 11c0 1rc0 Wo0 1rc0 Wo0 1rc0|18e5\",\"Asia/Hong_Kong|HKT|-80|0||73e5\",\"Asia/Hovd|+07 +08|-70 -80|01010|1O8H0 1cJ0 1cP0 1cJ0|81e3\",\"Asia/Irkutsk|+09 +08|-90 -80|01|1N7t0|60e4\",\"Europe/Istanbul|EET EEST +03|-20 -30 -30|01010101012|1GNB0 1qM0 11A0 1o00 1200 1nA0 11A0 1tA0 U00 15w0|13e6\",\"Asia/Jakarta|WIB|-70|0||31e6\",\"Asia/Jayapura|WIT|-90|0||26e4\",\"Asia/Jerusalem|IST IDT|-20 -30|01010101010101010101010|1GPA0 1aL0 1eN0 1oL0 10N0 1oL0 10N0 1oL0 10N0 1rz0 W10 1rz0 W10 1rz0 10N0 1oL0 10N0 1oL0 10N0 1rz0 W10 1rz0|81e4\",\"Asia/Kabul|+0430|-4u|0||46e5\",\"Asia/Karachi|PKT|-50|0||24e6\",\"Asia/Kathmandu|+0545|-5J|0||12e5\",\"Asia/Yakutsk|+10 +09|-a0 -90|01|1N7s0|28e4\",\"Asia/Krasnoyarsk|+08 +07|-80 -70|01|1N7u0|10e5\",\"Asia/Magadan|+12 +10 +11|-c0 -a0 -b0|012|1N7q0 3Cq0|95e3\",\"Asia/Makassar|WITA|-80|0||15e5\",\"Asia/Manila|PST|-80|0||24e6\",\"Europe/Athens|EET EEST|-20 -30|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|35e5\",\"Asia/Novosibirsk|+07 +06|-70 -60|010|1N7v0 4eN0|15e5\",\"Asia/Omsk|+07 +06|-70 -60|01|1N7v0|12e5\",\"Asia/Pyongyang|KST KST|-90 -8u|010|1P4D0 6BA0|29e5\",\"Asia/Qyzylorda|+06 +05|-60 -50|01|1Xei0|73e4\",\"Asia/Rangoon|+0630|-6u|0||48e5\",\"Asia/Sakhalin|+11 +10|-b0 -a0|010|1N7r0 3rd0|58e4\",\"Asia/Seoul|KST|-90|0||23e6\",\"Asia/Srednekolymsk|+12 +11|-c0 -b0|01|1N7q0|35e2\",\"Asia/Tehran|+0330 +0430|-3u -4u|01010101010101010101010|1GLUu 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0|14e6\",\"Asia/Tokyo|JST|-90|0||38e6\",\"Asia/Tomsk|+07 +06|-70 -60|010|1N7v0 3Qp0|10e5\",\"Asia/Vladivostok|+11 +10|-b0 -a0|01|1N7r0|60e4\",\"Asia/Yekaterinburg|+06 +05|-60 -50|01|1N7w0|14e5\",\"Europe/Lisbon|WET WEST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|27e5\",\"Atlantic/Cape_Verde|-01|10|0||50e4\",\"Australia/Sydney|AEDT AEST|-b0 -a0|01010101010101010101010|1GQg0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0|40e5\",\"Australia/Adelaide|ACDT ACST|-au -9u|01010101010101010101010|1GQgu 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0|11e5\",\"Australia/Brisbane|AEST|-a0|0||20e5\",\"Australia/Darwin|ACST|-9u|0||12e4\",\"Australia/Eucla|+0845|-8J|0||368\",\"Australia/Lord_Howe|+11 +1030|-b0 -au|01010101010101010101010|1GQf0 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu|347\",\"Australia/Perth|AWST|-80|0||18e5\",\"Pacific/Easter|-05 -06|50 60|010101010101010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1zb0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|30e2\",\"Europe/Dublin|GMT IST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|12e5\",\"Etc/GMT-1|+01|-10|0|\",\"Pacific/Fakaofo|+13|-d0|0||483\",\"Pacific/Kiritimati|+14|-e0|0||51e2\",\"Etc/GMT-2|+02|-20|0|\",\"Pacific/Tahiti|-10|a0|0||18e4\",\"Pacific/Niue|-11|b0|0||12e2\",\"Etc/GMT+12|-12|c0|0|\",\"Pacific/Galapagos|-06|60|0||25e3\",\"Etc/GMT+7|-07|70|0|\",\"Pacific/Pitcairn|-08|80|0||56\",\"Pacific/Gambier|-09|90|0||125\",\"Etc/UTC|UTC|0|0|\",\"Europe/Ulyanovsk|+04 +03|-40 -30|010|1N7y0 3rd0|13e5\",\"Europe/London|GMT BST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|10e6\",\"Europe/Chisinau|EET EEST|-20 -30|01010101010101010101010|1GNA0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|67e4\",\"Europe/Kaliningrad|+03 EET|-30 -20|01|1N7z0|44e4\",\"Europe/Kirov|+04 +03|-40 -30|01|1N7y0|48e4\",\"Europe/Moscow|MSK MSK|-40 -30|01|1N7y0|16e6\",\"Europe/Saratov|+04 +03|-40 -30|010|1N7y0 5810\",\"Europe/Simferopol|EET EEST MSK MSK|-20 -30 -40 -30|0101023|1GNB0 1qM0 11A0 1o00 11z0 1nW0|33e4\",\"Europe/Volgograd|+04 +03|-40 -30|010|1N7y0 9Jd0|10e5\",\"Pacific/Honolulu|HST|a0|0||37e4\",\"MET|MET MEST|-10 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0\",\"Pacific/Chatham|+1345 +1245|-dJ -cJ|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|600\",\"Pacific/Apia|+14 +13|-e0 -d0|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|37e3\",\"Pacific/Bougainville|+10 +11|-a0 -b0|01|1NwE0|18e4\",\"Pacific/Fiji|+13 +12|-d0 -c0|01010101010101010101010|1Goe0 1Nc0 Ao0 1Q00 xz0 1SN0 uM0 1SM0 uM0 1VA0 s00 1VA0 s00 1VA0 s00 1VA0 uM0 1SM0 uM0 1VA0 s00 1VA0|88e4\",\"Pacific/Guam|ChST|-a0|0||17e4\",\"Pacific/Marquesas|-0930|9u|0||86e2\",\"Pacific/Pago_Pago|SST|b0|0||37e2\",\"Pacific/Norfolk|+1130 +11|-bu -b0|01|1PoCu|25e4\",\"Pacific/Tongatapu|+13 +14|-d0 -e0|010|1S4d0 s00|75e3\"],links:[\"Africa/Abidjan|Africa/Accra\",\"Africa/Abidjan|Africa/Bamako\",\"Africa/Abidjan|Africa/Banjul\",\"Africa/Abidjan|Africa/Bissau\",\"Africa/Abidjan|Africa/Conakry\",\"Africa/Abidjan|Africa/Dakar\",\"Africa/Abidjan|Africa/Freetown\",\"Africa/Abidjan|Africa/Lome\",\"Africa/Abidjan|Africa/Monrovia\",\"Africa/Abidjan|Africa/Nouakchott\",\"Africa/Abidjan|Africa/Ouagadougou\",\"Africa/Abidjan|Africa/Timbuktu\",\"Africa/Abidjan|America/Danmarkshavn\",\"Africa/Abidjan|Atlantic/Reykjavik\",\"Africa/Abidjan|Atlantic/St_Helena\",\"Africa/Abidjan|Etc/GMT\",\"Africa/Abidjan|Etc/GMT+0\",\"Africa/Abidjan|Etc/GMT-0\",\"Africa/Abidjan|Etc/GMT0\",\"Africa/Abidjan|Etc/Greenwich\",\"Africa/Abidjan|GMT\",\"Africa/Abidjan|GMT+0\",\"Africa/Abidjan|GMT-0\",\"Africa/Abidjan|GMT0\",\"Africa/Abidjan|Greenwich\",\"Africa/Abidjan|Iceland\",\"Africa/Algiers|Africa/Tunis\",\"Africa/Cairo|Egypt\",\"Africa/Casablanca|Africa/El_Aaiun\",\"Africa/Johannesburg|Africa/Maseru\",\"Africa/Johannesburg|Africa/Mbabane\",\"Africa/Lagos|Africa/Bangui\",\"Africa/Lagos|Africa/Brazzaville\",\"Africa/Lagos|Africa/Douala\",\"Africa/Lagos|Africa/Kinshasa\",\"Africa/Lagos|Africa/Libreville\",\"Africa/Lagos|Africa/Luanda\",\"Africa/Lagos|Africa/Malabo\",\"Africa/Lagos|Africa/Ndjamena\",\"Africa/Lagos|Africa/Niamey\",\"Africa/Lagos|Africa/Porto-Novo\",\"Africa/Maputo|Africa/Blantyre\",\"Africa/Maputo|Africa/Bujumbura\",\"Africa/Maputo|Africa/Gaborone\",\"Africa/Maputo|Africa/Harare\",\"Africa/Maputo|Africa/Kigali\",\"Africa/Maputo|Africa/Lubumbashi\",\"Africa/Maputo|Africa/Lusaka\",\"Africa/Nairobi|Africa/Addis_Ababa\",\"Africa/Nairobi|Africa/Asmara\",\"Africa/Nairobi|Africa/Asmera\",\"Africa/Nairobi|Africa/Dar_es_Salaam\",\"Africa/Nairobi|Africa/Djibouti\",\"Africa/Nairobi|Africa/Juba\",\"Africa/Nairobi|Africa/Kampala\",\"Africa/Nairobi|Africa/Mogadishu\",\"Africa/Nairobi|Indian/Antananarivo\",\"Africa/Nairobi|Indian/Comoro\",\"Africa/Nairobi|Indian/Mayotte\",\"Africa/Tripoli|Libya\",\"America/Adak|America/Atka\",\"America/Adak|US/Aleutian\",\"America/Anchorage|America/Juneau\",\"America/Anchorage|America/Nome\",\"America/Anchorage|America/Sitka\",\"America/Anchorage|America/Yakutat\",\"America/Anchorage|US/Alaska\",\"America/Campo_Grande|America/Cuiaba\",\"America/Chicago|America/Indiana/Knox\",\"America/Chicago|America/Indiana/Tell_City\",\"America/Chicago|America/Knox_IN\",\"America/Chicago|America/Matamoros\",\"America/Chicago|America/Menominee\",\"America/Chicago|America/North_Dakota/Beulah\",\"America/Chicago|America/North_Dakota/Center\",\"America/Chicago|America/North_Dakota/New_Salem\",\"America/Chicago|America/Rainy_River\",\"America/Chicago|America/Rankin_Inlet\",\"America/Chicago|America/Resolute\",\"America/Chicago|America/Winnipeg\",\"America/Chicago|CST6CDT\",\"America/Chicago|Canada/Central\",\"America/Chicago|US/Central\",\"America/Chicago|US/Indiana-Starke\",\"America/Chihuahua|America/Mazatlan\",\"America/Chihuahua|Mexico/BajaSur\",\"America/Denver|America/Boise\",\"America/Denver|America/Cambridge_Bay\",\"America/Denver|America/Edmonton\",\"America/Denver|America/Inuvik\",\"America/Denver|America/Ojinaga\",\"America/Denver|America/Shiprock\",\"America/Denver|America/Yellowknife\",\"America/Denver|Canada/Mountain\",\"America/Denver|MST7MDT\",\"America/Denver|Navajo\",\"America/Denver|US/Mountain\",\"America/Fortaleza|America/Argentina/Buenos_Aires\",\"America/Fortaleza|America/Argentina/Catamarca\",\"America/Fortaleza|America/Argentina/ComodRivadavia\",\"America/Fortaleza|America/Argentina/Cordoba\",\"America/Fortaleza|America/Argentina/Jujuy\",\"America/Fortaleza|America/Argentina/La_Rioja\",\"America/Fortaleza|America/Argentina/Mendoza\",\"America/Fortaleza|America/Argentina/Rio_Gallegos\",\"America/Fortaleza|America/Argentina/Salta\",\"America/Fortaleza|America/Argentina/San_Juan\",\"America/Fortaleza|America/Argentina/San_Luis\",\"America/Fortaleza|America/Argentina/Tucuman\",\"America/Fortaleza|America/Argentina/Ushuaia\",\"America/Fortaleza|America/Belem\",\"America/Fortaleza|America/Buenos_Aires\",\"America/Fortaleza|America/Catamarca\",\"America/Fortaleza|America/Cayenne\",\"America/Fortaleza|America/Cordoba\",\"America/Fortaleza|America/Jujuy\",\"America/Fortaleza|America/Maceio\",\"America/Fortaleza|America/Mendoza\",\"America/Fortaleza|America/Paramaribo\",\"America/Fortaleza|America/Recife\",\"America/Fortaleza|America/Rosario\",\"America/Fortaleza|America/Santarem\",\"America/Fortaleza|Antarctica/Rothera\",\"America/Fortaleza|Atlantic/Stanley\",\"America/Fortaleza|Etc/GMT+3\",\"America/Halifax|America/Glace_Bay\",\"America/Halifax|America/Goose_Bay\",\"America/Halifax|America/Moncton\",\"America/Halifax|America/Thule\",\"America/Halifax|Atlantic/Bermuda\",\"America/Halifax|Canada/Atlantic\",\"America/Havana|Cuba\",\"America/La_Paz|America/Boa_Vista\",\"America/La_Paz|America/Guyana\",\"America/La_Paz|America/Manaus\",\"America/La_Paz|America/Porto_Velho\",\"America/La_Paz|Brazil/West\",\"America/La_Paz|Etc/GMT+4\",\"America/Lima|America/Bogota\",\"America/Lima|America/Guayaquil\",\"America/Lima|Etc/GMT+5\",\"America/Los_Angeles|America/Dawson\",\"America/Los_Angeles|America/Ensenada\",\"America/Los_Angeles|America/Santa_Isabel\",\"America/Los_Angeles|America/Tijuana\",\"America/Los_Angeles|America/Vancouver\",\"America/Los_Angeles|America/Whitehorse\",\"America/Los_Angeles|Canada/Pacific\",\"America/Los_Angeles|Canada/Yukon\",\"America/Los_Angeles|Mexico/BajaNorte\",\"America/Los_Angeles|PST8PDT\",\"America/Los_Angeles|US/Pacific\",\"America/Los_Angeles|US/Pacific-New\",\"America/Managua|America/Belize\",\"America/Managua|America/Costa_Rica\",\"America/Managua|America/El_Salvador\",\"America/Managua|America/Guatemala\",\"America/Managua|America/Regina\",\"America/Managua|America/Swift_Current\",\"America/Managua|America/Tegucigalpa\",\"America/Managua|Canada/Saskatchewan\",\"America/Mexico_City|America/Bahia_Banderas\",\"America/Mexico_City|America/Merida\",\"America/Mexico_City|America/Monterrey\",\"America/Mexico_City|Mexico/General\",\"America/New_York|America/Detroit\",\"America/New_York|America/Fort_Wayne\",\"America/New_York|America/Indiana/Indianapolis\",\"America/New_York|America/Indiana/Marengo\",\"America/New_York|America/Indiana/Petersburg\",\"America/New_York|America/Indiana/Vevay\",\"America/New_York|America/Indiana/Vincennes\",\"America/New_York|America/Indiana/Winamac\",\"America/New_York|America/Indianapolis\",\"America/New_York|America/Iqaluit\",\"America/New_York|America/Kentucky/Louisville\",\"America/New_York|America/Kentucky/Monticello\",\"America/New_York|America/Louisville\",\"America/New_York|America/Montreal\",\"America/New_York|America/Nassau\",\"America/New_York|America/Nipigon\",\"America/New_York|America/Pangnirtung\",\"America/New_York|America/Thunder_Bay\",\"America/New_York|America/Toronto\",\"America/New_York|Canada/Eastern\",\"America/New_York|EST5EDT\",\"America/New_York|US/East-Indiana\",\"America/New_York|US/Eastern\",\"America/New_York|US/Michigan\",\"America/Noronha|Atlantic/South_Georgia\",\"America/Noronha|Brazil/DeNoronha\",\"America/Noronha|Etc/GMT+2\",\"America/Panama|America/Atikokan\",\"America/Panama|America/Cayman\",\"America/Panama|America/Coral_Harbour\",\"America/Panama|America/Jamaica\",\"America/Panama|EST\",\"America/Panama|Jamaica\",\"America/Phoenix|America/Creston\",\"America/Phoenix|America/Dawson_Creek\",\"America/Phoenix|America/Hermosillo\",\"America/Phoenix|MST\",\"America/Phoenix|US/Arizona\",\"America/Rio_Branco|America/Eirunepe\",\"America/Rio_Branco|America/Porto_Acre\",\"America/Rio_Branco|Brazil/Acre\",\"America/Santiago|Chile/Continental\",\"America/Santo_Domingo|America/Anguilla\",\"America/Santo_Domingo|America/Antigua\",\"America/Santo_Domingo|America/Aruba\",\"America/Santo_Domingo|America/Barbados\",\"America/Santo_Domingo|America/Blanc-Sablon\",\"America/Santo_Domingo|America/Curacao\",\"America/Santo_Domingo|America/Dominica\",\"America/Santo_Domingo|America/Grenada\",\"America/Santo_Domingo|America/Guadeloupe\",\"America/Santo_Domingo|America/Kralendijk\",\"America/Santo_Domingo|America/Lower_Princes\",\"America/Santo_Domingo|America/Marigot\",\"America/Santo_Domingo|America/Martinique\",\"America/Santo_Domingo|America/Montserrat\",\"America/Santo_Domingo|America/Port_of_Spain\",\"America/Santo_Domingo|America/Puerto_Rico\",\"America/Santo_Domingo|America/St_Barthelemy\",\"America/Santo_Domingo|America/St_Kitts\",\"America/Santo_Domingo|America/St_Lucia\",\"America/Santo_Domingo|America/St_Thomas\",\"America/Santo_Domingo|America/St_Vincent\",\"America/Santo_Domingo|America/Tortola\",\"America/Santo_Domingo|America/Virgin\",\"America/Sao_Paulo|Brazil/East\",\"America/St_Johns|Canada/Newfoundland\",\"Antarctica/Palmer|America/Punta_Arenas\",\"Asia/Baghdad|Antarctica/Syowa\",\"Asia/Baghdad|Asia/Aden\",\"Asia/Baghdad|Asia/Bahrain\",\"Asia/Baghdad|Asia/Kuwait\",\"Asia/Baghdad|Asia/Qatar\",\"Asia/Baghdad|Asia/Riyadh\",\"Asia/Baghdad|Etc/GMT-3\",\"Asia/Baghdad|Europe/Minsk\",\"Asia/Bangkok|Asia/Ho_Chi_Minh\",\"Asia/Bangkok|Asia/Novokuznetsk\",\"Asia/Bangkok|Asia/Phnom_Penh\",\"Asia/Bangkok|Asia/Saigon\",\"Asia/Bangkok|Asia/Vientiane\",\"Asia/Bangkok|Etc/GMT-7\",\"Asia/Bangkok|Indian/Christmas\",\"Asia/Dhaka|Antarctica/Vostok\",\"Asia/Dhaka|Asia/Almaty\",\"Asia/Dhaka|Asia/Bishkek\",\"Asia/Dhaka|Asia/Dacca\",\"Asia/Dhaka|Asia/Kashgar\",\"Asia/Dhaka|Asia/Qostanay\",\"Asia/Dhaka|Asia/Thimbu\",\"Asia/Dhaka|Asia/Thimphu\",\"Asia/Dhaka|Asia/Urumqi\",\"Asia/Dhaka|Etc/GMT-6\",\"Asia/Dhaka|Indian/Chagos\",\"Asia/Dili|Etc/GMT-9\",\"Asia/Dili|Pacific/Palau\",\"Asia/Dubai|Asia/Muscat\",\"Asia/Dubai|Asia/Tbilisi\",\"Asia/Dubai|Asia/Yerevan\",\"Asia/Dubai|Etc/GMT-4\",\"Asia/Dubai|Europe/Samara\",\"Asia/Dubai|Indian/Mahe\",\"Asia/Dubai|Indian/Mauritius\",\"Asia/Dubai|Indian/Reunion\",\"Asia/Gaza|Asia/Hebron\",\"Asia/Hong_Kong|Hongkong\",\"Asia/Jakarta|Asia/Pontianak\",\"Asia/Jerusalem|Asia/Tel_Aviv\",\"Asia/Jerusalem|Israel\",\"Asia/Kamchatka|Asia/Anadyr\",\"Asia/Kamchatka|Etc/GMT-12\",\"Asia/Kamchatka|Kwajalein\",\"Asia/Kamchatka|Pacific/Funafuti\",\"Asia/Kamchatka|Pacific/Kwajalein\",\"Asia/Kamchatka|Pacific/Majuro\",\"Asia/Kamchatka|Pacific/Nauru\",\"Asia/Kamchatka|Pacific/Tarawa\",\"Asia/Kamchatka|Pacific/Wake\",\"Asia/Kamchatka|Pacific/Wallis\",\"Asia/Kathmandu|Asia/Katmandu\",\"Asia/Kolkata|Asia/Calcutta\",\"Asia/Kuala_Lumpur|Asia/Brunei\",\"Asia/Kuala_Lumpur|Asia/Kuching\",\"Asia/Kuala_Lumpur|Asia/Singapore\",\"Asia/Kuala_Lumpur|Etc/GMT-8\",\"Asia/Kuala_Lumpur|Singapore\",\"Asia/Makassar|Asia/Ujung_Pandang\",\"Asia/Rangoon|Asia/Yangon\",\"Asia/Rangoon|Indian/Cocos\",\"Asia/Seoul|ROK\",\"Asia/Shanghai|Asia/Chongqing\",\"Asia/Shanghai|Asia/Chungking\",\"Asia/Shanghai|Asia/Harbin\",\"Asia/Shanghai|Asia/Macao\",\"Asia/Shanghai|Asia/Macau\",\"Asia/Shanghai|Asia/Taipei\",\"Asia/Shanghai|PRC\",\"Asia/Shanghai|ROC\",\"Asia/Tashkent|Antarctica/Mawson\",\"Asia/Tashkent|Asia/Aqtau\",\"Asia/Tashkent|Asia/Aqtobe\",\"Asia/Tashkent|Asia/Ashgabat\",\"Asia/Tashkent|Asia/Ashkhabad\",\"Asia/Tashkent|Asia/Atyrau\",\"Asia/Tashkent|Asia/Dushanbe\",\"Asia/Tashkent|Asia/Oral\",\"Asia/Tashkent|Asia/Samarkand\",\"Asia/Tashkent|Etc/GMT-5\",\"Asia/Tashkent|Indian/Kerguelen\",\"Asia/Tashkent|Indian/Maldives\",\"Asia/Tehran|Iran\",\"Asia/Tokyo|Japan\",\"Asia/Ulaanbaatar|Asia/Choibalsan\",\"Asia/Ulaanbaatar|Asia/Ulan_Bator\",\"Asia/Vladivostok|Asia/Ust-Nera\",\"Asia/Yakutsk|Asia/Khandyga\",\"Atlantic/Azores|America/Scoresbysund\",\"Atlantic/Cape_Verde|Etc/GMT+1\",\"Australia/Adelaide|Australia/Broken_Hill\",\"Australia/Adelaide|Australia/South\",\"Australia/Adelaide|Australia/Yancowinna\",\"Australia/Brisbane|Australia/Lindeman\",\"Australia/Brisbane|Australia/Queensland\",\"Australia/Darwin|Australia/North\",\"Australia/Lord_Howe|Australia/LHI\",\"Australia/Perth|Australia/West\",\"Australia/Sydney|Australia/ACT\",\"Australia/Sydney|Australia/Canberra\",\"Australia/Sydney|Australia/Currie\",\"Australia/Sydney|Australia/Hobart\",\"Australia/Sydney|Australia/Melbourne\",\"Australia/Sydney|Australia/NSW\",\"Australia/Sydney|Australia/Tasmania\",\"Australia/Sydney|Australia/Victoria\",\"Etc/UTC|Etc/UCT\",\"Etc/UTC|Etc/Universal\",\"Etc/UTC|Etc/Zulu\",\"Etc/UTC|UCT\",\"Etc/UTC|UTC\",\"Etc/UTC|Universal\",\"Etc/UTC|Zulu\",\"Europe/Athens|Asia/Nicosia\",\"Europe/Athens|EET\",\"Europe/Athens|Europe/Bucharest\",\"Europe/Athens|Europe/Helsinki\",\"Europe/Athens|Europe/Kiev\",\"Europe/Athens|Europe/Mariehamn\",\"Europe/Athens|Europe/Nicosia\",\"Europe/Athens|Europe/Riga\",\"Europe/Athens|Europe/Sofia\",\"Europe/Athens|Europe/Tallinn\",\"Europe/Athens|Europe/Uzhgorod\",\"Europe/Athens|Europe/Vilnius\",\"Europe/Athens|Europe/Zaporozhye\",\"Europe/Chisinau|Europe/Tiraspol\",\"Europe/Dublin|Eire\",\"Europe/Istanbul|Asia/Istanbul\",\"Europe/Istanbul|Turkey\",\"Europe/Lisbon|Atlantic/Canary\",\"Europe/Lisbon|Atlantic/Faeroe\",\"Europe/Lisbon|Atlantic/Faroe\",\"Europe/Lisbon|Atlantic/Madeira\",\"Europe/Lisbon|Portugal\",\"Europe/Lisbon|WET\",\"Europe/London|Europe/Belfast\",\"Europe/London|Europe/Guernsey\",\"Europe/London|Europe/Isle_of_Man\",\"Europe/London|Europe/Jersey\",\"Europe/London|GB\",\"Europe/London|GB-Eire\",\"Europe/Moscow|W-SU\",\"Europe/Paris|Africa/Ceuta\",\"Europe/Paris|Arctic/Longyearbyen\",\"Europe/Paris|Atlantic/Jan_Mayen\",\"Europe/Paris|CET\",\"Europe/Paris|Europe/Amsterdam\",\"Europe/Paris|Europe/Andorra\",\"Europe/Paris|Europe/Belgrade\",\"Europe/Paris|Europe/Berlin\",\"Europe/Paris|Europe/Bratislava\",\"Europe/Paris|Europe/Brussels\",\"Europe/Paris|Europe/Budapest\",\"Europe/Paris|Europe/Busingen\",\"Europe/Paris|Europe/Copenhagen\",\"Europe/Paris|Europe/Gibraltar\",\"Europe/Paris|Europe/Ljubljana\",\"Europe/Paris|Europe/Luxembourg\",\"Europe/Paris|Europe/Madrid\",\"Europe/Paris|Europe/Malta\",\"Europe/Paris|Europe/Monaco\",\"Europe/Paris|Europe/Oslo\",\"Europe/Paris|Europe/Podgorica\",\"Europe/Paris|Europe/Prague\",\"Europe/Paris|Europe/Rome\",\"Europe/Paris|Europe/San_Marino\",\"Europe/Paris|Europe/Sarajevo\",\"Europe/Paris|Europe/Skopje\",\"Europe/Paris|Europe/Stockholm\",\"Europe/Paris|Europe/Tirane\",\"Europe/Paris|Europe/Vaduz\",\"Europe/Paris|Europe/Vatican\",\"Europe/Paris|Europe/Vienna\",\"Europe/Paris|Europe/Warsaw\",\"Europe/Paris|Europe/Zagreb\",\"Europe/Paris|Europe/Zurich\",\"Europe/Paris|Poland\",\"Europe/Ulyanovsk|Europe/Astrakhan\",\"Pacific/Auckland|Antarctica/McMurdo\",\"Pacific/Auckland|Antarctica/South_Pole\",\"Pacific/Auckland|NZ\",\"Pacific/Chatham|NZ-CHAT\",\"Pacific/Easter|Chile/EasterIsland\",\"Pacific/Fakaofo|Etc/GMT-13\",\"Pacific/Fakaofo|Pacific/Enderbury\",\"Pacific/Galapagos|Etc/GMT+6\",\"Pacific/Gambier|Etc/GMT+9\",\"Pacific/Guadalcanal|Antarctica/Macquarie\",\"Pacific/Guadalcanal|Etc/GMT-11\",\"Pacific/Guadalcanal|Pacific/Efate\",\"Pacific/Guadalcanal|Pacific/Kosrae\",\"Pacific/Guadalcanal|Pacific/Noumea\",\"Pacific/Guadalcanal|Pacific/Pohnpei\",\"Pacific/Guadalcanal|Pacific/Ponape\",\"Pacific/Guam|Pacific/Saipan\",\"Pacific/Honolulu|HST\",\"Pacific/Honolulu|Pacific/Johnston\",\"Pacific/Honolulu|US/Hawaii\",\"Pacific/Kiritimati|Etc/GMT-14\",\"Pacific/Niue|Etc/GMT+11\",\"Pacific/Pago_Pago|Pacific/Midway\",\"Pacific/Pago_Pago|Pacific/Samoa\",\"Pacific/Pago_Pago|US/Samoa\",\"Pacific/Pitcairn|Etc/GMT+8\",\"Pacific/Port_Moresby|Antarctica/DumontDUrville\",\"Pacific/Port_Moresby|Etc/GMT-10\",\"Pacific/Port_Moresby|Pacific/Chuuk\",\"Pacific/Port_Moresby|Pacific/Truk\",\"Pacific/Port_Moresby|Pacific/Yap\",\"Pacific/Tahiti|Etc/GMT+10\",\"Pacific/Tahiti|Pacific/Rarotonga\"]}),i},e.exports?e.exports=n(Ks):n(t.moment)}),Zs=function(e,t){var n=e.toString();function r(r){return function(e,t,n){return r+t+(n[0].toUpperCase()===n[0]?\"A\":\"a\")}}if((t=t||{}).preferredOrder=t.preferredOrder||Yu,(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=(n=n.replace(Lu,\"x\")).replace(Ru,\"X\")).replace(Pu,\"[$1]\")).replace(Qs,\"dddd\")).replace(eu,\"ddd\")).replace(tu,\"dd\")).replace(au,\"Do\")).replace(nu,\"MMMM\")).replace(ru,\"MMM\")).replace(iu,function(e,t,n,r,a,i){var o,s=1===Math.min(n.length,a.length,i.length),u=4===Math.max(n.length,a.length,i.length),c=\"string\"==typeof e.preferredOrder?e.preferredOrder:e.preferredOrder[r];return n=parseInt(n,10),a=parseInt(a,10),i=parseInt(i,10),o=[n,a,i],c=c.toUpperCase(),31<n?(o[0]=u?\"YYYY\":\"YY\",o[1]=s?\"M\":\"MM\",o[2]=s?\"D\":\"DD\"):12<a?(o[0]=s?\"M\":\"MM\",o[1]=s?\"D\":\"DD\",o[2]=u?\"YYYY\":\"YY\"):31<i?(o[2]=u?\"YYYY\":\"YY\",\"M\"===c[0]&&n<13?(o[0]=s?\"M\":\"MM\",o[1]=s?\"D\":\"DD\"):(o[0]=s?\"D\":\"DD\",o[1]=s?\"M\":\"MM\")):(o[c.indexOf(\"D\")]=s?\"D\":\"DD\",o[c.indexOf(\"M\")]=s?\"M\":\"MM\",o[c.indexOf(\"Y\")]=u?\"YYYY\":\"YY\"),o.join(r)}.bind(null,t))).replace(ou,\"Z\")).replace(pu,\"HH:mm:ss.SSS\")).replace(mu,\"HH:mm:ss.SS\")).replace(gu,\"HH:mm:ss.S\")).replace(uu,r(\"hh:mm:ss\"))).replace(fu,r(\"h:mm:ss\"))).replace(cu,r(\"hh:mm\"))).replace(hu,r(\"h:mm\"))).replace(lu,r(\"hh\"))).replace(du,r(\"h\"))).replace(vu,\"HH:mm:ss\")).replace(bu,\"H:mm:ss.SSS\")).replace(wu,\"H:mm:ss.SS\")).replace(Au,\"H:mm:ss.S\")).replace(_u,\"H:mm:ss\")).replace(yu,\"HH:mm\")).replace(xu,\"H:mm\")).replace(ku,\"YYYY\")).replace(Tu,\"D/M\")).replace(Cu,\"D/MM\")).replace(Du,\"DD/M\")).replace(Ou,\"DD/MM\")).replace(ju,\"M/YY\")).replace(Nu,\"MM/YY\")).match(zu)){n=(n=n.replace(/0\\d.\\d{2}|\\d{2}.\\d{2}/,\"H.mm\")).replace(/\\d{1}.\\d{2}/,\"h.mm\")}(n=(n=(n=n.replace(Eu,\"DD\")).replace(Su,\"D\")).replace(Mu,\"YY\")).length<1&&(n=void 0);return n},Qs=new RegExp([\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"].join(\"|\"),\"i\"),eu=new RegExp([\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"].join(\"|\"),\"i\"),tu=new RegExp(\"\\\\b(\"+[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"].join(\"|\")+\")\\\\b\",\"i\"),nu=new RegExp([\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"].join(\"|\"),\"i\"),ru=new RegExp([\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"].join(\"|\"),\"i\"),au=/(\\d+)(st|nd|rd|th)\\b/i,iu=/(\\d{1,4})([/.-])(\\d{1,2})[/.-](\\d{1,4})/,ou=/((\\+|-)\\d\\d:?\\d\\d)$/,su=\"(\"+[\"AM?\",\"PM?\"].join(\"|\")+\")\",uu=new RegExp(\"0\\\\d\\\\:\\\\d{1,2}\\\\:\\\\d{1,2}(\\\\s*)\"+su,\"i\"),cu=new RegExp(\"0\\\\d\\\\:\\\\d{1,2}(\\\\s*)\"+su,\"i\"),lu=new RegExp(\"0\\\\d(\\\\s*)\"+su,\"i\"),fu=new RegExp(\"\\\\d{1,2}\\\\:\\\\d{1,2}\\\\:\\\\d{1,2}(\\\\s*)\"+su,\"i\"),hu=new RegExp(\"\\\\d{1,2}\\\\:\\\\d{1,2}(\\\\s*)\"+su,\"i\"),du=new RegExp(\"\\\\d{1,2}(\\\\s*)\"+su,\"i\"),pu=/\\d{2}:\\d{2}:\\d{2}\\.\\d{3}/,mu=/\\d{2}:\\d{2}:\\d{2}\\.\\d{2}/,gu=/\\d{2}:\\d{2}:\\d{2}\\.\\d{1}/,vu=/0\\d:\\d{2}:\\d{2}/,yu=/0\\d:\\d{2}/,_u=/\\d{1,2}:\\d{2}:\\d{2}/,bu=/\\d{1,2}:\\d{2}:\\d{2}\\.\\d{3}/,wu=/\\d{1,2}:\\d{2}:\\d{2}\\.\\d{2}/,Au=/\\d{1,2}:\\d{2}:\\d{2}\\.\\d{1}/,xu=/\\d{1,2}:\\d{2}/,ku=/\\d{4}/,Eu=/0\\d/,Su=/\\d{1,2}/,Mu=/\\d{2}/,Tu=/^([1-9])\\/([1-9]|0[1-9])$/,Cu=/^([1-9])\\/(1[012])$/,Du=/^(0[1-9]|[12][0-9]|3[01])\\/([1-9])$/,Ou=/^(0[1-9]|[12][0-9]|3[01])\\/(1[012]|0[1-9])$/,ju=/^([1-9])\\/([1-9][0-9])$/,Nu=/^(0[1-9]|1[012])\\/([1-9][0-9])$/,zu=/([/][M]|[M][/]|[MM]|[MMMM])/,Pu=/\\b(at)\\b/i,Lu=/\\d{13}/,Ru=/\\d{10}/,Yu={\"/\":\"MDY\",\".\":\"DMY\",\"-\":\"YMD\"};var Wu=Zs;function qu(e,t,n){if(Bs.test(e))return Xs(new Date(e));if(Is.test(e)){var r=Is.exec(e);return Xs().subtract(r[1],r[2])}return Ws.test(e)?Xs():t?Xs.tz(e,n||Wu(e),t):Xs(e,n||Wu(e))}function Iu(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=t.timezone,r=t.format;if(zs.test(e)||Ps.test(e))return new Date(ba(e,10)).toISOString();var a=qu(e,n,r);return a.isValid()||(a=qu(e=(e.match(Fs)||[]).join(\" \").replace(Ys,\"m\").replace(Rs,\"$1 $2 $3\").replace(Ls,\"$1\").trim(),n,r)),a.isValid()?a.toISOString():null}function Hu(e,t){var n,r,a,i,o,s,u=t.$,c=(t.cleanConditionally,t.title),l=void 0===c?\"\":c,f=t.url,h=void 0===f?\"\":f,d=t.defaultCleaner,p=void 0===d||d;return n=Mi((n=Mi((n=u)(\"html\"),n,\"div\"))(\"body\"),n,\"div\"),p&&Ti(e,u),Go(e,u,h),function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:[];if(0===r.length&&(r=li),n){var a=Mr.parse(n),i=a.protocol,o=a.hostname;r=[].concat(Li(r),['iframe[src^=\"'.concat(i,\"//\").concat(o,'\"]')])}t(r.join(\",\"),e).addClass(ci)}(e,u,h),function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:[];0===n.length&&(n=fi),t(n.join(\",\"),e).not(\".\".concat(ci)).remove()}(e,u),(a=(r=u)(\"h1\",e)).length<3?a.each(function(e,t){return r(t).remove()}):a.each(function(e,t){Mi(r(t),r,\"h2\")}),function(r,a){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:\"\";a(pi,r).each(function(e,t){var n=a(t);return 0===a(n,r).prevAll(\"p\").length?n.remove():ua(a(t).text())===i?n.remove():$i(a(t))<0?n.remove():n})}(e,u,l),p&&co(e,u),i=u,e.find(\"p\").each(function(e,t){var n=i(t);0===n.find(\"iframe, img\").length&&\"\"===n.text().trim()&&n.remove()}),s=u,Ri((o=e).parent().length?o.parent():o,s),e}function Fu(e,t){var n=t.url,r=t.$;if(Gs.test(e)&&(e=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:\"\",n=e.split(Gs);if(1===n.length)return e;var r=function(e,t){if(6<=e.length){var n=e.reduce(function(e,t){return e[t]=e[t]?e[t]+1:1,e},{}),r=si(n).reduce(function(e,t){return e[1]<n[t]?[t,n[t]]:e},[0,0]),a=ja(r,2),i=a[0],o=a[1];2<=o&&i.length<=4&&(e=t.split(i));var s=[e[0],e.slice(-1)],u=s.reduce(function(e,t){return e.length>t.length?e:t},\"\");return 10<u.length?u:t}return null}(n,e);return r||(r=function(e,t){var n=Mr.parse(t).host.replace(Us,\"\"),r=e[0].toLowerCase().replace(\" \",\"\");if(.4<$u.levenshtein(r,n)&&5<r.length)return e.slice(2).join(\"\");var a=e.slice(-1)[0].toLowerCase().replace(\" \",\"\");return.4<$u.levenshtein(a,n)&&5<=a.length?e.slice(0,-2).join(\"\"):null}(n,t))||e}(e,n)),150<e.length){var a=r(\"h1\");1===a.length&&(e=a.text())}return ua(es(e,r).trim())}\"undefined\"!=typeof window&&window.moment&&(window.moment.parseFormat=Zs);var Bu=e(function(W,q){(function(){var to,no=\"Expected a function\",ro=\"__lodash_hash_undefined__\",ao=\"__lodash_placeholder__\",io=9007199254740991,oo=NaN,so=4294967295,uo=[[\"ary\",128],[\"bind\",1],[\"bindKey\",2],[\"curry\",8],[\"curryRight\",16],[\"flip\",512],[\"partial\",32],[\"partialRight\",64],[\"rearg\",256]],co=\"[object Arguments]\",lo=\"[object Array]\",fo=\"[object Boolean]\",ho=\"[object Date]\",po=\"[object Error]\",mo=\"[object Function]\",go=\"[object GeneratorFunction]\",vo=\"[object Map]\",yo=\"[object Number]\",_o=\"[object Object]\",bo=\"[object Promise]\",wo=\"[object RegExp]\",Ao=\"[object Set]\",xo=\"[object String]\",ko=\"[object Symbol]\",Eo=\"[object WeakMap]\",So=\"[object ArrayBuffer]\",Mo=\"[object DataView]\",To=\"[object Float32Array]\",Co=\"[object Float64Array]\",Do=\"[object Int8Array]\",Oo=\"[object Int16Array]\",jo=\"[object Int32Array]\",No=\"[object Uint8Array]\",zo=\"[object Uint8ClampedArray]\",Po=\"[object Uint16Array]\",Lo=\"[object Uint32Array]\",Ro=/\\b__p \\+= '';/g,Yo=/\\b(__p \\+=) '' \\+/g,Wo=/(__e\\(.*?\\)|\\b__t\\)) \\+\\n'';/g,qo=/&(?:amp|lt|gt|quot|#39);/g,Io=/[&<>\"']/g,Ho=RegExp(qo.source),Fo=RegExp(Io.source),Bo=/<%-([\\s\\S]+?)%>/g,Go=/<%([\\s\\S]+?)%>/g,Uo=/<%=([\\s\\S]+?)%>/g,$o=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,Vo=/^\\w*$/,Jo=/[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g,Ko=/[\\\\^$.*+?()[\\]{}|]/g,Xo=RegExp(Ko.source),Zo=/^\\s+|\\s+$/g,Qo=/^\\s+/,es=/\\s+$/,ts=/\\{(?:\\n\\/\\* \\[wrapped with .+\\] \\*\\/)?\\n?/,ns=/\\{\\n\\/\\* \\[wrapped with (.+)\\] \\*/,rs=/,? & /,as=/[^\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]+/g,is=/\\\\(\\\\)?/g,os=/\\$\\{([^\\\\}]*(?:\\\\.[^\\\\}]*)*)\\}/g,ss=/\\w*$/,us=/^[-+]0x[0-9a-f]+$/i,cs=/^0b[01]+$/i,ls=/^\\[object .+?Constructor\\]$/,fs=/^0o[0-7]+$/i,hs=/^(?:0|[1-9]\\d*)$/,ds=/[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g,ps=/($^)/,ms=/['\\n\\r\\u2028\\u2029\\\\]/g,e=\"\\\\ud800-\\\\udfff\",t=\"\\\\u0300-\\\\u036f\\\\ufe20-\\\\ufe2f\\\\u20d0-\\\\u20ff\",n=\"\\\\u2700-\\\\u27bf\",r=\"a-z\\\\xdf-\\\\xf6\\\\xf8-\\\\xff\",a=\"A-Z\\\\xc0-\\\\xd6\\\\xd8-\\\\xde\",i=\"\\\\ufe0e\\\\ufe0f\",o=\"\\\\xac\\\\xb1\\\\xd7\\\\xf7\\\\x00-\\\\x2f\\\\x3a-\\\\x40\\\\x5b-\\\\x60\\\\x7b-\\\\xbf\\\\u2000-\\\\u206f \\\\t\\\\x0b\\\\f\\\\xa0\\\\ufeff\\\\n\\\\r\\\\u2028\\\\u2029\\\\u1680\\\\u180e\\\\u2000\\\\u2001\\\\u2002\\\\u2003\\\\u2004\\\\u2005\\\\u2006\\\\u2007\\\\u2008\\\\u2009\\\\u200a\\\\u202f\\\\u205f\\\\u3000\",s=\"[\"+e+\"]\",u=\"[\"+o+\"]\",c=\"[\"+t+\"]\",l=\"\\\\d+\",f=\"[\"+n+\"]\",h=\"[\"+r+\"]\",d=\"[^\"+e+o+l+n+r+a+\"]\",p=\"\\\\ud83c[\\\\udffb-\\\\udfff]\",m=\"[^\"+e+\"]\",g=\"(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}\",v=\"[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]\",y=\"[\"+a+\"]\",_=\"(?:\"+h+\"|\"+d+\")\",b=\"(?:\"+y+\"|\"+d+\")\",w=\"(?:['’](?:d|ll|m|re|s|t|ve))?\",A=\"(?:['’](?:D|LL|M|RE|S|T|VE))?\",x=\"(?:\"+c+\"|\"+p+\")\"+\"?\",k=\"[\"+i+\"]?\",E=k+x+(\"(?:\\\\u200d(?:\"+[m,g,v].join(\"|\")+\")\"+k+x+\")*\"),S=\"(?:\"+[f,g,v].join(\"|\")+\")\"+E,M=\"(?:\"+[m+c+\"?\",c,g,v,s].join(\"|\")+\")\",gs=RegExp(\"['’]\",\"g\"),vs=RegExp(c,\"g\"),T=RegExp(p+\"(?=\"+p+\")|\"+M+E,\"g\"),ys=RegExp([y+\"?\"+h+\"+\"+w+\"(?=\"+[u,y,\"$\"].join(\"|\")+\")\",b+\"+\"+A+\"(?=\"+[u,y+_,\"$\"].join(\"|\")+\")\",y+\"?\"+_+\"+\"+w,y+\"+\"+A,\"\\\\d*(?:1ST|2ND|3RD|(?![123])\\\\dTH)(?=\\\\b|[a-z_])\",\"\\\\d*(?:1st|2nd|3rd|(?![123])\\\\dth)(?=\\\\b|[A-Z_])\",l,S].join(\"|\"),\"g\"),C=RegExp(\"[\\\\u200d\"+e+t+i+\"]\"),_s=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,bs=[\"Array\",\"Buffer\",\"DataView\",\"Date\",\"Error\",\"Float32Array\",\"Float64Array\",\"Function\",\"Int8Array\",\"Int16Array\",\"Int32Array\",\"Map\",\"Math\",\"Object\",\"Promise\",\"RegExp\",\"Set\",\"String\",\"Symbol\",\"TypeError\",\"Uint8Array\",\"Uint8ClampedArray\",\"Uint16Array\",\"Uint32Array\",\"WeakMap\",\"_\",\"clearTimeout\",\"isFinite\",\"parseInt\",\"setTimeout\"],ws=-1,As={};As[To]=As[Co]=As[Do]=As[Oo]=As[jo]=As[No]=As[zo]=As[Po]=As[Lo]=!0,As[co]=As[lo]=As[So]=As[fo]=As[Mo]=As[ho]=As[po]=As[mo]=As[vo]=As[yo]=As[_o]=As[wo]=As[Ao]=As[xo]=As[Eo]=!1;var xs={};xs[co]=xs[lo]=xs[So]=xs[Mo]=xs[fo]=xs[ho]=xs[To]=xs[Co]=xs[Do]=xs[Oo]=xs[jo]=xs[vo]=xs[yo]=xs[_o]=xs[wo]=xs[Ao]=xs[xo]=xs[ko]=xs[No]=xs[zo]=xs[Po]=xs[Lo]=!0,xs[po]=xs[mo]=xs[Eo]=!1;var D={\"\\\\\":\"\\\\\",\"'\":\"'\",\"\\n\":\"n\",\"\\r\":\"r\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},ks=parseFloat,Es=parseInt,O=\"object\"==typeof er&&er&&er.Object===Object&&er,j=\"object\"==typeof self&&self&&self.Object===Object&&self,Ss=O||j||Function(\"return this\")(),N=q&&!q.nodeType&&q,z=N&&W&&!W.nodeType&&W,Ms=z&&z.exports===N,P=Ms&&O.process,L=function(){try{var e=z&&z.require&&z.require(\"util\").types;return e||P&&P.binding&&P.binding(\"util\")}catch(e){}}(),Ts=L&&L.isArrayBuffer,Cs=L&&L.isDate,Ds=L&&L.isMap,Os=L&&L.isRegExp,js=L&&L.isSet,Ns=L&&L.isTypedArray;function zs(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function Ps(e,t,n,r){for(var a=-1,i=null==e?0:e.length;++a<i;){var o=e[a];t(r,o,n(o),e)}return r}function Ls(e,t){for(var n=-1,r=null==e?0:e.length;++n<r&&!1!==t(e[n],n,e););return e}function Rs(e,t){for(var n=null==e?0:e.length;n--&&!1!==t(e[n],n,e););return e}function Ys(e,t){for(var n=-1,r=null==e?0:e.length;++n<r;)if(!t(e[n],n,e))return!1;return!0}function Ws(e,t){for(var n=-1,r=null==e?0:e.length,a=0,i=[];++n<r;){var o=e[n];t(o,n,e)&&(i[a++]=o)}return i}function qs(e,t){return!!(null==e?0:e.length)&&-1<Js(e,t,0)}function Is(e,t,n){for(var r=-1,a=null==e?0:e.length;++r<a;)if(n(t,e[r]))return!0;return!1}function Hs(e,t){for(var n=-1,r=null==e?0:e.length,a=Array(r);++n<r;)a[n]=t(e[n],n,e);return a}function Fs(e,t){for(var n=-1,r=t.length,a=e.length;++n<r;)e[a+n]=t[n];return e}function Bs(e,t,n,r){var a=-1,i=null==e?0:e.length;for(r&&i&&(n=e[++a]);++a<i;)n=t(n,e[a],a,e);return n}function Gs(e,t,n,r){var a=null==e?0:e.length;for(r&&a&&(n=e[--a]);a--;)n=t(n,e[a],a,e);return n}function Us(e,t){for(var n=-1,r=null==e?0:e.length;++n<r;)if(t(e[n],n,e))return!0;return!1}var R=Qs(\"length\");function $s(e,r,t){var a;return t(e,function(e,t,n){if(r(e,t,n))return a=t,!1}),a}function Vs(e,t,n,r){for(var a=e.length,i=n+(r?1:-1);r?i--:++i<a;)if(t(e[i],i,e))return i;return-1}function Js(e,t,n){return t==t?function(e,t,n){var r=n-1,a=e.length;for(;++r<a;)if(e[r]===t)return r;return-1}(e,t,n):Vs(e,Xs,n)}function Ks(e,t,n,r){for(var a=n-1,i=e.length;++a<i;)if(r(e[a],t))return a;return-1}function Xs(e){return e!=e}function Zs(e,t){var n=null==e?0:e.length;return n?tu(e,t)/n:oo}function Qs(t){return function(e){return null==e?to:e[t]}}function Y(t){return function(e){return null==t?to:t[e]}}function eu(e,r,a,i,t){return t(e,function(e,t,n){a=i?(i=!1,e):r(a,e,t,n)}),a}function tu(e,t){for(var n,r=-1,a=e.length;++r<a;){var i=t(e[r]);i!==to&&(n=n===to?i:n+i)}return n}function nu(e,t){for(var n=-1,r=Array(e);++n<e;)r[n]=t(n);return r}function ru(t){return function(e){return t(e)}}function au(t,e){return Hs(e,function(e){return t[e]})}function iu(e,t){return e.has(t)}function ou(e,t){for(var n=-1,r=e.length;++n<r&&-1<Js(t,e[n],0););return n}function su(e,t){for(var n=e.length;n--&&-1<Js(t,e[n],0););return n}var uu=Y({\"À\":\"A\",\"Á\":\"A\",\"Â\":\"A\",\"Ã\":\"A\",\"Ä\":\"A\",\"Å\":\"A\",\"à\":\"a\",\"á\":\"a\",\"â\":\"a\",\"ã\":\"a\",\"ä\":\"a\",\"å\":\"a\",\"Ç\":\"C\",\"ç\":\"c\",\"Ð\":\"D\",\"ð\":\"d\",\"È\":\"E\",\"É\":\"E\",\"Ê\":\"E\",\"Ë\":\"E\",\"è\":\"e\",\"é\":\"e\",\"ê\":\"e\",\"ë\":\"e\",\"Ì\":\"I\",\"Í\":\"I\",\"Î\":\"I\",\"Ï\":\"I\",\"ì\":\"i\",\"í\":\"i\",\"î\":\"i\",\"ï\":\"i\",\"Ñ\":\"N\",\"ñ\":\"n\",\"Ò\":\"O\",\"Ó\":\"O\",\"Ô\":\"O\",\"Õ\":\"O\",\"Ö\":\"O\",\"Ø\":\"O\",\"ò\":\"o\",\"ó\":\"o\",\"ô\":\"o\",\"õ\":\"o\",\"ö\":\"o\",\"ø\":\"o\",\"Ù\":\"U\",\"Ú\":\"U\",\"Û\":\"U\",\"Ü\":\"U\",\"ù\":\"u\",\"ú\":\"u\",\"û\":\"u\",\"ü\":\"u\",\"Ý\":\"Y\",\"ý\":\"y\",\"ÿ\":\"y\",\"Æ\":\"Ae\",\"æ\":\"ae\",\"Þ\":\"Th\",\"þ\":\"th\",\"ß\":\"ss\",\"Ā\":\"A\",\"Ă\":\"A\",\"Ą\":\"A\",\"ā\":\"a\",\"ă\":\"a\",\"ą\":\"a\",\"Ć\":\"C\",\"Ĉ\":\"C\",\"Ċ\":\"C\",\"Č\":\"C\",\"ć\":\"c\",\"ĉ\":\"c\",\"ċ\":\"c\",\"č\":\"c\",\"Ď\":\"D\",\"Đ\":\"D\",\"ď\":\"d\",\"đ\":\"d\",\"Ē\":\"E\",\"Ĕ\":\"E\",\"Ė\":\"E\",\"Ę\":\"E\",\"Ě\":\"E\",\"ē\":\"e\",\"ĕ\":\"e\",\"ė\":\"e\",\"ę\":\"e\",\"ě\":\"e\",\"Ĝ\":\"G\",\"Ğ\":\"G\",\"Ġ\":\"G\",\"Ģ\":\"G\",\"ĝ\":\"g\",\"ğ\":\"g\",\"ġ\":\"g\",\"ģ\":\"g\",\"Ĥ\":\"H\",\"Ħ\":\"H\",\"ĥ\":\"h\",\"ħ\":\"h\",\"Ĩ\":\"I\",\"Ī\":\"I\",\"Ĭ\":\"I\",\"Į\":\"I\",\"İ\":\"I\",\"ĩ\":\"i\",\"ī\":\"i\",\"ĭ\":\"i\",\"į\":\"i\",\"ı\":\"i\",\"Ĵ\":\"J\",\"ĵ\":\"j\",\"Ķ\":\"K\",\"ķ\":\"k\",\"ĸ\":\"k\",\"Ĺ\":\"L\",\"Ļ\":\"L\",\"Ľ\":\"L\",\"Ŀ\":\"L\",\"Ł\":\"L\",\"ĺ\":\"l\",\"ļ\":\"l\",\"ľ\":\"l\",\"ŀ\":\"l\",\"ł\":\"l\",\"Ń\":\"N\",\"Ņ\":\"N\",\"Ň\":\"N\",\"Ŋ\":\"N\",\"ń\":\"n\",\"ņ\":\"n\",\"ň\":\"n\",\"ŋ\":\"n\",\"Ō\":\"O\",\"Ŏ\":\"O\",\"Ő\":\"O\",\"ō\":\"o\",\"ŏ\":\"o\",\"ő\":\"o\",\"Ŕ\":\"R\",\"Ŗ\":\"R\",\"Ř\":\"R\",\"ŕ\":\"r\",\"ŗ\":\"r\",\"ř\":\"r\",\"Ś\":\"S\",\"Ŝ\":\"S\",\"Ş\":\"S\",\"Š\":\"S\",\"ś\":\"s\",\"ŝ\":\"s\",\"ş\":\"s\",\"š\":\"s\",\"Ţ\":\"T\",\"Ť\":\"T\",\"Ŧ\":\"T\",\"ţ\":\"t\",\"ť\":\"t\",\"ŧ\":\"t\",\"Ũ\":\"U\",\"Ū\":\"U\",\"Ŭ\":\"U\",\"Ů\":\"U\",\"Ű\":\"U\",\"Ų\":\"U\",\"ũ\":\"u\",\"ū\":\"u\",\"ŭ\":\"u\",\"ů\":\"u\",\"ű\":\"u\",\"ų\":\"u\",\"Ŵ\":\"W\",\"ŵ\":\"w\",\"Ŷ\":\"Y\",\"ŷ\":\"y\",\"Ÿ\":\"Y\",\"Ź\":\"Z\",\"Ż\":\"Z\",\"Ž\":\"Z\",\"ź\":\"z\",\"ż\":\"z\",\"ž\":\"z\",\"Ĳ\":\"IJ\",\"ĳ\":\"ij\",\"Œ\":\"Oe\",\"œ\":\"oe\",\"ŉ\":\"'n\",\"ſ\":\"s\"}),cu=Y({\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#39;\"});function lu(e){return\"\\\\\"+D[e]}function fu(e){return C.test(e)}function hu(e){var n=-1,r=Array(e.size);return e.forEach(function(e,t){r[++n]=[t,e]}),r}function du(t,n){return function(e){return t(n(e))}}function pu(e,t){for(var n=-1,r=e.length,a=0,i=[];++n<r;){var o=e[n];o!==t&&o!==ao||(e[n]=ao,i[a++]=n)}return i}function mu(e){var t=-1,n=Array(e.size);return e.forEach(function(e){n[++t]=e}),n}function gu(e){return fu(e)?function(e){var t=T.lastIndex=0;for(;T.test(e);)++t;return t}(e):R(e)}function vu(e){return fu(e)?e.match(T)||[]:e.split(\"\")}var yu=Y({\"&amp;\":\"&\",\"&lt;\":\"<\",\"&gt;\":\">\",\"&quot;\":'\"',\"&#39;\":\"'\"});var _u=function e(t){var n,T=(t=null==t?Ss:_u.defaults(Ss.Object(),t,_u.pick(Ss,bs))).Array,r=t.Date,a=t.Error,g=t.Function,i=t.Math,k=t.Object,v=t.RegExp,l=t.String,C=t.TypeError,o=T.prototype,s=g.prototype,f=k.prototype,u=t[\"__core-js_shared__\"],c=s.toString,E=f.hasOwnProperty,h=0,d=(n=/[^.]+$/.exec(u&&u.keys&&u.keys.IE_PROTO||\"\"))?\"Symbol(src)_1.\"+n:\"\",p=f.toString,m=c.call(k),y=Ss._,_=v(\"^\"+c.call(E).replace(Ko,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\"),b=Ms?t.Buffer:to,w=t.Symbol,A=t.Uint8Array,x=b?b.allocUnsafe:to,S=du(k.getPrototypeOf,k),M=k.create,D=f.propertyIsEnumerable,O=o.splice,j=w?w.isConcatSpreadable:to,N=w?w.iterator:to,z=w?w.toStringTag:to,P=function(){try{var e=qn(k,\"defineProperty\");return e({},\"\",{}),e}catch(e){}}(),L=t.clearTimeout!==Ss.clearTimeout&&t.clearTimeout,R=r&&r.now!==Ss.Date.now&&r.now,Y=t.setTimeout!==Ss.setTimeout&&t.setTimeout,W=i.ceil,q=i.floor,I=k.getOwnPropertySymbols,H=b?b.isBuffer:to,F=t.isFinite,B=o.join,G=du(k.keys,k),U=i.max,$=i.min,V=r.now,J=t.parseInt,K=i.random,X=o.reverse,Z=qn(t,\"DataView\"),Q=qn(t,\"Map\"),ee=qn(t,\"Promise\"),te=qn(t,\"Set\"),ne=qn(t,\"WeakMap\"),re=qn(k,\"create\"),ae=ne&&new ne,ie={},oe=pr(Z),se=pr(Q),ue=pr(ee),ce=pr(te),le=pr(ne),fe=w?w.prototype:to,he=fe?fe.valueOf:to,de=fe?fe.toString:to;function pe(e){if(Oa(e)&&!ba(e)&&!(e instanceof ye)){if(e instanceof ve)return e;if(E.call(e,\"__wrapped__\"))return mr(e)}return new ve(e)}var me=function(){function n(){}return function(e){if(!Da(e))return{};if(M)return M(e);n.prototype=e;var t=new n;return n.prototype=to,t}}();function ge(){}function ve(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=to}function ye(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=so,this.__views__=[]}function _e(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function be(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function we(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}function Ae(e){var t=-1,n=null==e?0:e.length;for(this.__data__=new we;++t<n;)this.add(e[t])}function xe(e){var t=this.__data__=new be(e);this.size=t.size}function ke(e,t){var n=ba(e),r=!n&&_a(e),a=!n&&!r&&ka(e),i=!n&&!r&&!a&&Wa(e),o=n||r||a||i,s=o?nu(e.length,l):[],u=s.length;for(var c in e)!t&&!E.call(e,c)||o&&(\"length\"==c||a&&(\"offset\"==c||\"parent\"==c)||i&&(\"buffer\"==c||\"byteLength\"==c||\"byteOffset\"==c)||$n(c,u))||s.push(c);return s}function Ee(e){var t=e.length;return t?e[At(0,t-1)]:to}function Se(e,t){return cr(rn(e),Pe(t,0,e.length))}function Me(e){return cr(rn(e))}function Te(e,t,n){(n===to||ga(e[t],n))&&(n!==to||t in e)||Ne(e,t,n)}function Ce(e,t,n){var r=e[t];E.call(e,t)&&ga(r,n)&&(n!==to||t in e)||Ne(e,t,n)}function De(e,t){for(var n=e.length;n--;)if(ga(e[n][0],t))return n;return-1}function Oe(e,r,a,i){return qe(e,function(e,t,n){r(i,e,a(e),n)}),i}function je(e,t){return e&&an(t,si(t),e)}function Ne(e,t,n){\"__proto__\"==t&&P?P(e,t,{configurable:!0,enumerable:!0,value:n,writable:!0}):e[t]=n}function ze(e,t){for(var n=-1,r=t.length,a=T(r),i=null==e;++n<r;)a[n]=i?to:ni(e,t[n]);return a}function Pe(e,t,n){return e==e&&(n!==to&&(e=e<=n?e:n),t!==to&&(e=t<=e?e:t)),e}function Le(n,r,a,e,t,i){var o,s=1&r,u=2&r,c=4&r;if(a&&(o=t?a(n,e,t,i):a(n)),o!==to)return o;if(!Da(n))return n;var l,f,h,d,p,m,g,v,y,_=ba(n);if(_){if(v=(g=n).length,y=new g.constructor(v),v&&\"string\"==typeof g[0]&&E.call(g,\"index\")&&(y.index=g.index,y.input=g.input),o=y,!s)return rn(n,o)}else{var b=Fn(n),w=b==mo||b==go;if(ka(n))return Xt(n,s);if(b==_o||b==co||w&&!t){if(o=u||w?{}:Gn(n),!s)return u?(m=h=n,d=(p=o)&&an(m,ui(m),p),an(h,Hn(h),d)):(f=je(o,l=n),an(l,In(l),f))}else{if(!xs[b])return t?n:{};o=function(e,t,n){var r,a,i,o,s,u=e.constructor;switch(t){case So:return Zt(e);case fo:case ho:return new u(+e);case Mo:return o=e,s=n?Zt(o.buffer):o.buffer,new o.constructor(s,o.byteOffset,o.byteLength);case To:case Co:case Do:case Oo:case jo:case No:case zo:case Po:case Lo:return Qt(e,n);case vo:return new u;case yo:case xo:return new u(e);case wo:return(i=new(a=e).constructor(a.source,ss.exec(a))).lastIndex=a.lastIndex,i;case Ao:return new u;case ko:return r=e,he?k(he.call(r)):{}}}(n,b,s)}}i||(i=new xe);var A=i.get(n);if(A)return A;i.set(n,o),La(n)?n.forEach(function(e){o.add(Le(e,r,a,e,n,i))}):ja(n)&&n.forEach(function(e,t){o.set(t,Le(e,r,a,t,n,i))});var x=_?to:(c?u?Nn:jn:u?ui:si)(n);return Ls(x||n,function(e,t){x&&(e=n[t=e]),Ce(o,t,Le(e,r,a,t,n,i))}),o}function Re(e,t,n){var r=n.length;if(null==e)return!r;for(e=k(e);r--;){var a=n[r],i=t[a],o=e[a];if(o===to&&!(a in e)||!i(o))return!1}return!0}function Ye(e,t,n){if(\"function\"!=typeof e)throw new C(no);return ir(function(){e.apply(to,n)},t)}function We(e,t,n,r){var a=-1,i=qs,o=!0,s=e.length,u=[],c=t.length;if(!s)return u;n&&(t=Hs(t,ru(n))),r?(i=Is,o=!1):200<=t.length&&(i=iu,o=!1,t=new Ae(t));e:for(;++a<s;){var l=e[a],f=null==n?l:n(l);if(l=r||0!==l?l:0,o&&f==f){for(var h=c;h--;)if(t[h]===f)continue e;u.push(l)}else i(t,f,r)||u.push(l)}return u}pe.templateSettings={escape:Bo,evaluate:Go,interpolate:Uo,variable:\"\",imports:{_:pe}},(pe.prototype=ge.prototype).constructor=pe,(ve.prototype=me(ge.prototype)).constructor=ve,(ye.prototype=me(ge.prototype)).constructor=ye,_e.prototype.clear=function(){this.__data__=re?re(null):{},this.size=0},_e.prototype.delete=function(e){var t=this.has(e)&&delete this.__data__[e];return this.size-=t?1:0,t},_e.prototype.get=function(e){var t=this.__data__;if(re){var n=t[e];return n===ro?to:n}return E.call(t,e)?t[e]:to},_e.prototype.has=function(e){var t=this.__data__;return re?t[e]!==to:E.call(t,e)},_e.prototype.set=function(e,t){var n=this.__data__;return this.size+=this.has(e)?0:1,n[e]=re&&t===to?ro:t,this},be.prototype.clear=function(){this.__data__=[],this.size=0},be.prototype.delete=function(e){var t=this.__data__,n=De(t,e);return!(n<0||(n==t.length-1?t.pop():O.call(t,n,1),--this.size,0))},be.prototype.get=function(e){var t=this.__data__,n=De(t,e);return n<0?to:t[n][1]},be.prototype.has=function(e){return-1<De(this.__data__,e)},be.prototype.set=function(e,t){var n=this.__data__,r=De(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this},we.prototype.clear=function(){this.size=0,this.__data__={hash:new _e,map:new(Q||be),string:new _e}},we.prototype.delete=function(e){var t=Yn(this,e).delete(e);return this.size-=t?1:0,t},we.prototype.get=function(e){return Yn(this,e).get(e)},we.prototype.has=function(e){return Yn(this,e).has(e)},we.prototype.set=function(e,t){var n=Yn(this,e),r=n.size;return n.set(e,t),this.size+=n.size==r?0:1,this},Ae.prototype.add=Ae.prototype.push=function(e){return this.__data__.set(e,ro),this},Ae.prototype.has=function(e){return this.__data__.has(e)},xe.prototype.clear=function(){this.__data__=new be,this.size=0},xe.prototype.delete=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n},xe.prototype.get=function(e){return this.__data__.get(e)},xe.prototype.has=function(e){return this.__data__.has(e)},xe.prototype.set=function(e,t){var n=this.__data__;if(n instanceof be){var r=n.__data__;if(!Q||r.length<199)return r.push([e,t]),this.size=++n.size,this;n=this.__data__=new we(r)}return n.set(e,t),this.size=n.size,this};var qe=un(Ve),Ie=un(Je,!0);function He(e,r){var a=!0;return qe(e,function(e,t,n){return a=!!r(e,t,n)}),a}function Fe(e,t,n){for(var r=-1,a=e.length;++r<a;){var i=e[r],o=t(i);if(null!=o&&(s===to?o==o&&!Ya(o):n(o,s)))var s=o,u=i}return u}function Be(e,r){var a=[];return qe(e,function(e,t,n){r(e,t,n)&&a.push(e)}),a}function Ge(e,t,n,r,a){var i=-1,o=e.length;for(n||(n=Un),a||(a=[]);++i<o;){var s=e[i];0<t&&n(s)?1<t?Ge(s,t-1,n,r,a):Fs(a,s):r||(a[a.length]=s)}return a}var Ue=cn(),$e=cn(!0);function Ve(e,t){return e&&Ue(e,t,si)}function Je(e,t){return e&&$e(e,t,si)}function Ke(t,e){return Ws(e,function(e){return Ma(t[e])})}function Xe(e,t){for(var n=0,r=(t=$t(t,e)).length;null!=e&&n<r;)e=e[dr(t[n++])];return n&&n==r?e:to}function Ze(e,t,n){var r=t(e);return ba(e)?r:Fs(r,n(e))}function Qe(e){return null==e?e===to?\"[object Undefined]\":\"[object Null]\":z&&z in k(e)?function(e){var t=E.call(e,z),n=e[z];try{e[z]=to;var r=!0}catch(e){}var a=p.call(e);return r&&(t?e[z]=n:delete e[z]),a}(e):(t=e,p.call(t));var t}function et(e,t){return t<e}function tt(e,t){return null!=e&&E.call(e,t)}function nt(e,t){return null!=e&&t in k(e)}function rt(e,t,n){for(var r=n?Is:qs,a=e[0].length,i=e.length,o=i,s=T(i),u=1/0,c=[];o--;){var l=e[o];o&&t&&(l=Hs(l,ru(t))),u=$(l.length,u),s[o]=!n&&(t||120<=a&&120<=l.length)?new Ae(o&&l):to}l=e[0];var f=-1,h=s[0];e:for(;++f<a&&c.length<u;){var d=l[f],p=t?t(d):d;if(d=n||0!==d?d:0,!(h?iu(h,p):r(c,p,n))){for(o=i;--o;){var m=s[o];if(!(m?iu(m,p):r(e[o],p,n)))continue e}h&&h.push(p),c.push(d)}}return c}function at(e,t,n){var r=null==(e=nr(e,t=$t(t,e)))?e:e[dr(Sr(t))];return null==r?to:zs(r,e,n)}function it(e){return Oa(e)&&Qe(e)==co}function ot(e,t,n,r,a){return e===t||(null==e||null==t||!Oa(e)&&!Oa(t)?e!=e&&t!=t:function(e,t,n,r,a,i){var o=ba(e),s=ba(t),u=o?lo:Fn(e),c=s?lo:Fn(t),l=(u=u==co?_o:u)==_o,f=(c=c==co?_o:c)==_o,h=u==c;if(h&&ka(e)){if(!ka(t))return!1;l=!(o=!0)}if(h&&!l)return i||(i=new xe),o||Wa(e)?Dn(e,t,n,r,a,i):function(e,t,n,r,a,i,o){switch(n){case Mo:if(e.byteLength!=t.byteLength||e.byteOffset!=t.byteOffset)return!1;e=e.buffer,t=t.buffer;case So:return!(e.byteLength!=t.byteLength||!i(new A(e),new A(t)));case fo:case ho:case yo:return ga(+e,+t);case po:return e.name==t.name&&e.message==t.message;case wo:case xo:return e==t+\"\";case vo:var s=hu;case Ao:var u=1&r;if(s||(s=mu),e.size!=t.size&&!u)return!1;var c=o.get(e);if(c)return c==t;r|=2,o.set(e,t);var l=Dn(s(e),s(t),r,a,i,o);return o.delete(e),l;case ko:if(he)return he.call(e)==he.call(t)}return!1}(e,t,u,n,r,a,i);if(!(1&n)){var d=l&&E.call(e,\"__wrapped__\"),p=f&&E.call(t,\"__wrapped__\");if(d||p){var m=d?e.value():e,g=p?t.value():t;return i||(i=new xe),a(m,g,n,r,i)}}return!!h&&(i||(i=new xe),function(e,t,n,r,a,i){var o=1&n,s=jn(e),u=s.length,c=jn(t).length;if(u!=c&&!o)return!1;for(var l=u;l--;){var f=s[l];if(!(o?f in t:E.call(t,f)))return!1}var h=i.get(e);if(h&&i.get(t))return h==t;var d=!0;i.set(e,t),i.set(t,e);for(var p=o;++l<u;){f=s[l];var m=e[f],g=t[f];if(r)var v=o?r(g,m,f,t,e,i):r(m,g,f,e,t,i);if(!(v===to?m===g||a(m,g,n,r,i):v)){d=!1;break}p||(p=\"constructor\"==f)}if(d&&!p){var y=e.constructor,_=t.constructor;y!=_&&\"constructor\"in e&&\"constructor\"in t&&!(\"function\"==typeof y&&y instanceof y&&\"function\"==typeof _&&_ instanceof _)&&(d=!1)}return i.delete(e),i.delete(t),d}(e,t,n,r,a,i))}(e,t,n,r,ot,a))}function st(e,t,n,r){var a=n.length,i=a,o=!r;if(null==e)return!i;for(e=k(e);a--;){var s=n[a];if(o&&s[2]?s[1]!==e[s[0]]:!(s[0]in e))return!1}for(;++a<i;){var u=(s=n[a])[0],c=e[u],l=s[1];if(o&&s[2]){if(c===to&&!(u in e))return!1}else{var f=new xe;if(r)var h=r(c,l,u,e,t,f);if(!(h===to?ot(l,c,3,r,f):h))return!1}}return!0}function ut(e){return!(!Da(e)||(t=e,d&&d in t))&&(Ma(e)?_:ls).test(pr(e));var t}function ct(e){return\"function\"==typeof e?e:null==e?Ni:\"object\"==typeof e?ba(e)?mt(e[0],e[1]):pt(e):Hi(e)}function lt(e){if(!Zn(e))return G(e);var t=[];for(var n in k(e))E.call(e,n)&&\"constructor\"!=n&&t.push(n);return t}function ft(e){if(!Da(e))return function(e){var t=[];if(null!=e)for(var n in k(e))t.push(n);return t}(e);var t=Zn(e),n=[];for(var r in e)(\"constructor\"!=r||!t&&E.call(e,r))&&n.push(r);return n}function ht(e,t){return e<t}function dt(e,r){var a=-1,i=Aa(e)?T(e.length):[];return qe(e,function(e,t,n){i[++a]=r(e,t,n)}),i}function pt(t){var n=Wn(t);return 1==n.length&&n[0][2]?er(n[0][0],n[0][1]):function(e){return e===t||st(e,t,n)}}function mt(n,r){return Jn(n)&&Qn(r)?er(dr(n),r):function(e){var t=ni(e,n);return t===to&&t===r?ri(e,n):ot(r,t,3)}}function gt(r,a,i,o,s){r!==a&&Ue(a,function(e,t){if(s||(s=new xe),Da(e))!function(e,t,n,r,a,i,o){var s=rr(e,n),u=rr(t,n),c=o.get(u);if(c)return Te(e,n,c);var l=i?i(s,u,n+\"\",e,t,o):to,f=l===to;if(f){var h=ba(u),d=!h&&ka(u),p=!h&&!d&&Wa(u);l=u,h||d||p?l=ba(s)?s:xa(s)?rn(s):d?Xt(u,!(f=!1)):p?Qt(u,!(f=!1)):[]:za(u)||_a(u)?_a(l=s)?l=$a(s):Da(s)&&!Ma(s)||(l=Gn(u)):f=!1}f&&(o.set(u,l),a(l,u,r,i,o),o.delete(u)),Te(e,n,l)}(r,a,t,i,gt,o,s);else{var n=o?o(rr(r,t),e,t+\"\",r,a,s):to;n===to&&(n=e),Te(r,t,n)}},ui)}function vt(e,t){var n=e.length;if(n)return $n(t+=t<0?n:0,n)?e[t]:to}function yt(e,r,n){var a=-1;return r=Hs(r.length?r:[Ni],ru(Rn())),function(e,t){var n=e.length;for(e.sort(t);n--;)e[n]=e[n].value;return e}(dt(e,function(t,e,n){return{criteria:Hs(r,function(e){return e(t)}),index:++a,value:t}}),function(e,t){return function(e,t,n){for(var r=-1,a=e.criteria,i=t.criteria,o=a.length,s=n.length;++r<o;){var u=en(a[r],i[r]);if(u){if(s<=r)return u;var c=n[r];return u*(\"desc\"==c?-1:1)}}return e.index-t.index}(e,t,n)})}function _t(e,t,n){for(var r=-1,a=t.length,i={};++r<a;){var o=t[r],s=Xe(e,o);n(s,o)&&Mt(i,$t(o,e),s)}return i}function bt(e,t,n,r){var a=r?Ks:Js,i=-1,o=t.length,s=e;for(e===t&&(t=rn(t)),n&&(s=Hs(e,ru(n)));++i<o;)for(var u=0,c=t[i],l=n?n(c):c;-1<(u=a(s,l,u,r));)s!==e&&O.call(s,u,1),O.call(e,u,1);return e}function wt(e,t){for(var n=e?t.length:0,r=n-1;n--;){var a=t[n];if(n==r||a!==i){var i=a;$n(a)?O.call(e,a,1):Wt(e,a)}}return e}function At(e,t){return e+q(K()*(t-e+1))}function xt(e,t){var n=\"\";if(!e||t<1||io<t)return n;for(;t%2&&(n+=e),(t=q(t/2))&&(e+=e),t;);return n}function kt(e,t){return or(tr(e,t,Ni),e+\"\")}function Et(e){return Ee(gi(e))}function St(e,t){var n=gi(e);return cr(n,Pe(t,0,n.length))}function Mt(e,t,n,r){if(!Da(e))return e;for(var a=-1,i=(t=$t(t,e)).length,o=i-1,s=e;null!=s&&++a<i;){var u=dr(t[a]),c=n;if(a!=o){var l=s[u];(c=r?r(l,u,s):to)===to&&(c=Da(l)?l:$n(t[a+1])?[]:{})}Ce(s,u,c),s=s[u]}return e}var Tt=ae?function(e,t){return ae.set(e,t),e}:Ni,Ct=P?function(e,t){return P(e,\"toString\",{configurable:!0,enumerable:!1,value:Di(t),writable:!0})}:Ni;function Dt(e){return cr(gi(e))}function Ot(e,t,n){var r=-1,a=e.length;t<0&&(t=a<-t?0:a+t),(n=a<n?a:n)<0&&(n+=a),a=n<t?0:n-t>>>0,t>>>=0;for(var i=T(a);++r<a;)i[r]=e[r+t];return i}function jt(e,r){var a;return qe(e,function(e,t,n){return!(a=r(e,t,n))}),!!a}function Nt(e,t,n){var r=0,a=null==e?r:e.length;if(\"number\"==typeof t&&t==t&&a<=2147483647){for(;r<a;){var i=r+a>>>1,o=e[i];null!==o&&!Ya(o)&&(n?o<=t:o<t)?r=i+1:a=i}return a}return zt(e,t,Ni,n)}function zt(e,t,n,r){t=n(t);for(var a=0,i=null==e?0:e.length,o=t!=t,s=null===t,u=Ya(t),c=t===to;a<i;){var l=q((a+i)/2),f=n(e[l]),h=f!==to,d=null===f,p=f==f,m=Ya(f);if(o)var g=r||p;else g=c?p&&(r||h):s?p&&h&&(r||!d):u?p&&h&&!d&&(r||!m):!d&&!m&&(r?f<=t:f<t);g?a=l+1:i=l}return $(i,4294967294)}function Pt(e,t){for(var n=-1,r=e.length,a=0,i=[];++n<r;){var o=e[n],s=t?t(o):o;if(!n||!ga(s,u)){var u=s;i[a++]=0===o?0:o}}return i}function Lt(e){return\"number\"==typeof e?e:Ya(e)?oo:+e}function Rt(e){if(\"string\"==typeof e)return e;if(ba(e))return Hs(e,Rt)+\"\";if(Ya(e))return de?de.call(e):\"\";var t=e+\"\";return\"0\"==t&&1/e==-1/0?\"-0\":t}function Yt(e,t,n){var r=-1,a=qs,i=e.length,o=!0,s=[],u=s;if(n)o=!1,a=Is;else if(200<=i){var c=t?null:kn(e);if(c)return mu(c);o=!1,a=iu,u=new Ae}else u=t?[]:s;e:for(;++r<i;){var l=e[r],f=t?t(l):l;if(l=n||0!==l?l:0,o&&f==f){for(var h=u.length;h--;)if(u[h]===f)continue e;t&&u.push(f),s.push(l)}else a(u,f,n)||(u!==s&&u.push(f),s.push(l))}return s}function Wt(e,t){return null==(e=nr(e,t=$t(t,e)))||delete e[dr(Sr(t))]}function qt(e,t,n,r){return Mt(e,t,n(Xe(e,t)),r)}function It(e,t,n,r){for(var a=e.length,i=r?a:-1;(r?i--:++i<a)&&t(e[i],i,e););return n?Ot(e,r?0:i,r?i+1:a):Ot(e,r?i+1:0,r?a:i)}function Ht(e,t){var n=e;return n instanceof ye&&(n=n.value()),Bs(t,function(e,t){return t.func.apply(t.thisArg,Fs([e],t.args))},n)}function Ft(e,t,n){var r=e.length;if(r<2)return r?Yt(e[0]):[];for(var a=-1,i=T(r);++a<r;)for(var o=e[a],s=-1;++s<r;)s!=a&&(i[a]=We(i[a]||o,e[s],t,n));return Yt(Ge(i,1),t,n)}function Bt(e,t,n){for(var r=-1,a=e.length,i=t.length,o={};++r<a;){var s=r<i?t[r]:to;n(o,e[r],s)}return o}function Gt(e){return xa(e)?e:[]}function Ut(e){return\"function\"==typeof e?e:Ni}function $t(e,t){return ba(e)?e:Jn(e,t)?[e]:hr(Va(e))}var Vt=kt;function Jt(e,t,n){var r=e.length;return n=n===to?r:n,!t&&r<=n?e:Ot(e,t,n)}var Kt=L||function(e){return Ss.clearTimeout(e)};function Xt(e,t){if(t)return e.slice();var n=e.length,r=x?x(n):new e.constructor(n);return e.copy(r),r}function Zt(e){var t=new e.constructor(e.byteLength);return new A(t).set(new A(e)),t}function Qt(e,t){var n=t?Zt(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function en(e,t){if(e!==t){var n=e!==to,r=null===e,a=e==e,i=Ya(e),o=t!==to,s=null===t,u=t==t,c=Ya(t);if(!s&&!c&&!i&&t<e||i&&o&&u&&!s&&!c||r&&o&&u||!n&&u||!a)return 1;if(!r&&!i&&!c&&e<t||c&&n&&a&&!r&&!i||s&&n&&a||!o&&a||!u)return-1}return 0}function tn(e,t,n,r){for(var a=-1,i=e.length,o=n.length,s=-1,u=t.length,c=U(i-o,0),l=T(u+c),f=!r;++s<u;)l[s]=t[s];for(;++a<o;)(f||a<i)&&(l[n[a]]=e[a]);for(;c--;)l[s++]=e[a++];return l}function nn(e,t,n,r){for(var a=-1,i=e.length,o=-1,s=n.length,u=-1,c=t.length,l=U(i-s,0),f=T(l+c),h=!r;++a<l;)f[a]=e[a];for(var d=a;++u<c;)f[d+u]=t[u];for(;++o<s;)(h||a<i)&&(f[d+n[o]]=e[a++]);return f}function rn(e,t){var n=-1,r=e.length;for(t||(t=T(r));++n<r;)t[n]=e[n];return t}function an(e,t,n,r){var a=!n;n||(n={});for(var i=-1,o=t.length;++i<o;){var s=t[i],u=r?r(n[s],e[s],s,n,e):to;u===to&&(u=e[s]),a?Ne(n,s,u):Ce(n,s,u)}return n}function on(a,i){return function(e,t){var n=ba(e)?Ps:Oe,r=i?i():{};return n(e,a,Rn(t,2),r)}}function sn(s){return kt(function(e,t){var n=-1,r=t.length,a=1<r?t[r-1]:to,i=2<r?t[2]:to;for(a=3<s.length&&\"function\"==typeof a?(r--,a):to,i&&Vn(t[0],t[1],i)&&(a=r<3?to:a,r=1),e=k(e);++n<r;){var o=t[n];o&&s(e,o,n,a)}return e})}function un(i,o){return function(e,t){if(null==e)return e;if(!Aa(e))return i(e,t);for(var n=e.length,r=o?n:-1,a=k(e);(o?r--:++r<n)&&!1!==t(a[r],r,a););return e}}function cn(u){return function(e,t,n){for(var r=-1,a=k(e),i=n(e),o=i.length;o--;){var s=i[u?o:++r];if(!1===t(a[s],s,a))break}return e}}function ln(a){return function(e){var t=fu(e=Va(e))?vu(e):to,n=t?t[0]:e.charAt(0),r=t?Jt(t,1).join(\"\"):e.slice(1);return n[a]()+r}}function fn(t){return function(e){return Bs(Mi(_i(e).replace(gs,\"\")),t,\"\")}}function hn(r){return function(){var e=arguments;switch(e.length){case 0:return new r;case 1:return new r(e[0]);case 2:return new r(e[0],e[1]);case 3:return new r(e[0],e[1],e[2]);case 4:return new r(e[0],e[1],e[2],e[3]);case 5:return new r(e[0],e[1],e[2],e[3],e[4]);case 6:return new r(e[0],e[1],e[2],e[3],e[4],e[5]);case 7:return new r(e[0],e[1],e[2],e[3],e[4],e[5],e[6])}var t=me(r.prototype),n=r.apply(t,e);return Da(n)?n:t}}function dn(o){return function(e,t,n){var r=k(e);if(!Aa(e)){var a=Rn(t,3);e=si(e),t=function(e){return a(r[e],e,r)}}var i=o(e,t,n);return-1<i?r[a?e[i]:i]:to}}function pn(u){return On(function(a){var i=a.length,e=i,t=ve.prototype.thru;for(u&&a.reverse();e--;){var n=a[e];if(\"function\"!=typeof n)throw new C(no);if(t&&!o&&\"wrapper\"==Pn(n))var o=new ve([],!0)}for(e=o?e:i;++e<i;){var r=Pn(n=a[e]),s=\"wrapper\"==r?zn(n):to;o=s&&Kn(s[0])&&424==s[1]&&!s[4].length&&1==s[9]?o[Pn(s[0])].apply(o,s[3]):1==n.length&&Kn(n)?o[r]():o.thru(n)}return function(){var e=arguments,t=e[0];if(o&&1==e.length&&ba(t))return o.plant(t).value();for(var n=0,r=i?a[n].apply(this,e):t;++n<i;)r=a[n].call(this,r);return r}})}function mn(c,l,f,h,d,p,m,g,v,y){var _=128&l,b=1&l,w=2&l,A=24&l,x=512&l,k=w?to:hn(c);return function e(){for(var t=arguments.length,n=T(t),r=t;r--;)n[r]=arguments[r];if(A)var a=Ln(e),i=function(e,t){for(var n=e.length,r=0;n--;)e[n]===t&&++r;return r}(n,a);if(h&&(n=tn(n,h,d,A)),p&&(n=nn(n,p,m,A)),t-=i,A&&t<y){var o=pu(n,a);return An(c,l,mn,e.placeholder,f,n,o,g,v,y-t)}var s=b?f:this,u=w?s[c]:c;return t=n.length,g?n=function(e,t){for(var n=e.length,r=$(t.length,n),a=rn(e);r--;){var i=t[r];e[r]=$n(i,n)?a[i]:to}return e}(n,g):x&&1<t&&n.reverse(),_&&v<t&&(n.length=v),this&&this!==Ss&&this instanceof e&&(u=k||hn(u)),u.apply(s,n)}}function gn(o,s){return function(e,t){return n=e,r=o,a=s(t),i={},Ve(n,function(e,t,n){r(i,a(e),t,n)}),i;var n,r,a,i}}function vn(r,a){return function(e,t){var n;if(e===to&&t===to)return a;if(e!==to&&(n=e),t!==to){if(n===to)return t;t=\"string\"==typeof e||\"string\"==typeof t?(e=Rt(e),Rt(t)):(e=Lt(e),Lt(t)),n=r(e,t)}return n}}function yn(r){return On(function(e){return e=Hs(e,ru(Rn())),kt(function(t){var n=this;return r(e,function(e){return zs(e,n,t)})})})}function _n(e,t){var n=(t=t===to?\" \":Rt(t)).length;if(n<2)return n?xt(t,e):t;var r=xt(t,W(e/gu(t)));return fu(t)?Jt(vu(r),0,e).join(\"\"):r.slice(0,e)}function bn(r){return function(e,t,n){return n&&\"number\"!=typeof n&&Vn(e,t,n)&&(t=n=to),e=Fa(e),t===to?(t=e,e=0):t=Fa(t),function(e,t,n,r){for(var a=-1,i=U(W((t-e)/(n||1)),0),o=T(i);i--;)o[r?i:++a]=e,e+=n;return o}(e,t,n=n===to?e<t?1:-1:Fa(n),r)}}function wn(n){return function(e,t){return\"string\"==typeof e&&\"string\"==typeof t||(e=Ua(e),t=Ua(t)),n(e,t)}}function An(e,t,n,r,a,i,o,s,u,c){var l=8&t;t|=l?32:64,4&(t&=~(l?64:32))||(t&=-4);var f=[e,t,a,l?i:to,l?o:to,l?to:i,l?to:o,s,u,c],h=n.apply(to,f);return Kn(e)&&ar(h,f),h.placeholder=r,sr(h,e,t)}function xn(e){var r=i[e];return function(e,t){if(e=Ua(e),(t=null==t?0:$(Ba(t),292))&&F(e)){var n=(Va(e)+\"e\").split(\"e\");return+((n=(Va(r(n[0]+\"e\"+(+n[1]+t)))+\"e\").split(\"e\"))[0]+\"e\"+(+n[1]-t))}return r(e)}}var kn=te&&1/mu(new te([,-0]))[1]==1/0?function(e){return new te(e)}:Yi;function En(o){return function(e){var t,n,r,a,i=Fn(e);return i==vo?hu(e):i==Ao?(t=e,n=-1,r=Array(t.size),t.forEach(function(e){r[++n]=[e,e]}),r):Hs(o(a=e),function(e){return[e,a[e]]})}}function Sn(e,t,n,r,a,i,o,s){var u=2&t;if(!u&&\"function\"!=typeof e)throw new C(no);var c=r?r.length:0;if(c||(t&=-97,r=a=to),o=o===to?o:U(Ba(o),0),s=s===to?s:Ba(s),c-=a?a.length:0,64&t){var l=r,f=a;r=a=to}var h,d,p,m,g,v,y,_,b,w,A,x,k,E=u?to:zn(e),S=[e,t,n,r,a,l,f,i,o,s];if(E&&function(e,t){var n=e[1],r=t[1],a=n|r,i=a<131,o=128==r&&8==n||128==r&&256==n&&e[7].length<=t[8]||384==r&&t[7].length<=t[8]&&8==n;if(i||o){1&r&&(e[2]=t[2],a|=1&n?0:4);var s=t[3];if(s){var u=e[3];e[3]=u?tn(u,s,t[4]):s,e[4]=u?pu(e[3],ao):t[4]}(s=t[5])&&(u=e[5],e[5]=u?nn(u,s,t[6]):s,e[6]=u?pu(e[5],ao):t[6]),(s=t[7])&&(e[7]=s),128&r&&(e[8]=null==e[8]?t[8]:$(e[8],t[8])),null==e[9]&&(e[9]=t[9]),e[0]=t[0],e[1]=a}}(S,E),e=S[0],t=S[1],n=S[2],r=S[3],a=S[4],!(s=S[9]=S[9]===to?u?0:e.length:U(S[9]-c,0))&&24&t&&(t&=-25),t&&1!=t)M=8==t||16==t?(y=t,_=s,b=hn(v=e),function e(){for(var t=arguments.length,n=T(t),r=t,a=Ln(e);r--;)n[r]=arguments[r];var i=t<3&&n[0]!==a&&n[t-1]!==a?[]:pu(n,a);return(t-=i.length)<_?An(v,y,mn,e.placeholder,to,n,i,to,to,_-t):zs(this&&this!==Ss&&this instanceof e?b:v,this,n)}):32!=t&&33!=t||a.length?mn.apply(to,S):(d=n,p=r,m=1&t,g=hn(h=e),function e(){for(var t=-1,n=arguments.length,r=-1,a=p.length,i=T(a+n),o=this&&this!==Ss&&this instanceof e?g:h;++r<a;)i[r]=p[r];for(;n--;)i[r++]=arguments[++t];return zs(o,m?d:this,i)});else var M=(A=n,x=1&t,k=hn(w=e),function e(){return(this&&this!==Ss&&this instanceof e?k:w).apply(x?A:this,arguments)});return sr((E?Tt:ar)(M,S),e,t)}function Mn(e,t,n,r){return e===to||ga(e,f[n])&&!E.call(r,n)?t:e}function Tn(e,t,n,r,a,i){return Da(e)&&Da(t)&&(i.set(t,e),gt(e,t,to,Tn,i),i.delete(t)),e}function Cn(e){return za(e)?to:e}function Dn(e,t,n,r,a,i){var o=1&n,s=e.length,u=t.length;if(s!=u&&!(o&&s<u))return!1;var c=i.get(e);if(c&&i.get(t))return c==t;var l=-1,f=!0,h=2&n?new Ae:to;for(i.set(e,t),i.set(t,e);++l<s;){var d=e[l],p=t[l];if(r)var m=o?r(p,d,l,t,e,i):r(d,p,l,e,t,i);if(m!==to){if(m)continue;f=!1;break}if(h){if(!Us(t,function(e,t){if(!iu(h,t)&&(d===e||a(d,e,n,r,i)))return h.push(t)})){f=!1;break}}else if(d!==p&&!a(d,p,n,r,i)){f=!1;break}}return i.delete(e),i.delete(t),f}function On(e){return or(tr(e,to,wr),e+\"\")}function jn(e){return Ze(e,si,In)}function Nn(e){return Ze(e,ui,Hn)}var zn=ae?function(e){return ae.get(e)}:Yi;function Pn(e){for(var t=e.name+\"\",n=ie[t],r=E.call(ie,t)?n.length:0;r--;){var a=n[r],i=a.func;if(null==i||i==e)return a.name}return t}function Ln(e){return(E.call(pe,\"placeholder\")?pe:e).placeholder}function Rn(){var e=pe.iteratee||zi;return e=e===zi?ct:e,arguments.length?e(arguments[0],arguments[1]):e}function Yn(e,t){var n,r,a=e.__data__;return(\"string\"==(r=typeof(n=t))||\"number\"==r||\"symbol\"==r||\"boolean\"==r?\"__proto__\"!==n:null===n)?a[\"string\"==typeof t?\"string\":\"hash\"]:a.map}function Wn(e){for(var t=si(e),n=t.length;n--;){var r=t[n],a=e[r];t[n]=[r,a,Qn(a)]}return t}function qn(e,t){var n,r,a=(r=t,null==(n=e)?to:n[r]);return ut(a)?a:to}var In=I?function(t){return null==t?[]:(t=k(t),Ws(I(t),function(e){return D.call(t,e)}))}:Gi,Hn=I?function(e){for(var t=[];e;)Fs(t,In(e)),e=S(e);return t}:Gi,Fn=Qe;function Bn(e,t,n){for(var r=-1,a=(t=$t(t,e)).length,i=!1;++r<a;){var o=dr(t[r]);if(!(i=null!=e&&n(e,o)))break;e=e[o]}return i||++r!=a?i:!!(a=null==e?0:e.length)&&Ca(a)&&$n(o,a)&&(ba(e)||_a(e))}function Gn(e){return\"function\"!=typeof e.constructor||Zn(e)?{}:me(S(e))}function Un(e){return ba(e)||_a(e)||!!(j&&e&&e[j])}function $n(e,t){var n=typeof e;return!!(t=null==t?io:t)&&(\"number\"==n||\"symbol\"!=n&&hs.test(e))&&-1<e&&e%1==0&&e<t}function Vn(e,t,n){if(!Da(n))return!1;var r=typeof t;return!!(\"number\"==r?Aa(n)&&$n(t,n.length):\"string\"==r&&t in n)&&ga(n[t],e)}function Jn(e,t){if(ba(e))return!1;var n=typeof e;return!(\"number\"!=n&&\"symbol\"!=n&&\"boolean\"!=n&&null!=e&&!Ya(e))||Vo.test(e)||!$o.test(e)||null!=t&&e in k(t)}function Kn(e){var t=Pn(e),n=pe[t];if(\"function\"!=typeof n||!(t in ye.prototype))return!1;if(e===n)return!0;var r=zn(n);return!!r&&e===r[0]}(Z&&Fn(new Z(new ArrayBuffer(1)))!=Mo||Q&&Fn(new Q)!=vo||ee&&Fn(ee.resolve())!=bo||te&&Fn(new te)!=Ao||ne&&Fn(new ne)!=Eo)&&(Fn=function(e){var t=Qe(e),n=t==_o?e.constructor:to,r=n?pr(n):\"\";if(r)switch(r){case oe:return Mo;case se:return vo;case ue:return bo;case ce:return Ao;case le:return Eo}return t});var Xn=u?Ma:Ui;function Zn(e){var t=e&&e.constructor;return e===(\"function\"==typeof t&&t.prototype||f)}function Qn(e){return e==e&&!Da(e)}function er(t,n){return function(e){return null!=e&&e[t]===n&&(n!==to||t in k(e))}}function tr(i,o,s){return o=U(o===to?i.length-1:o,0),function(){for(var e=arguments,t=-1,n=U(e.length-o,0),r=T(n);++t<n;)r[t]=e[o+t];t=-1;for(var a=T(o+1);++t<o;)a[t]=e[t];return a[o]=s(r),zs(i,this,a)}}function nr(e,t){return t.length<2?e:Xe(e,Ot(t,0,-1))}function rr(e,t){if((\"constructor\"!==t||\"function\"!=typeof e[t])&&\"__proto__\"!=t)return e[t]}var ar=ur(Tt),ir=Y||function(e,t){return Ss.setTimeout(e,t)},or=ur(Ct);function sr(e,t,n){var r,a,i,o=t+\"\";return or(e,function(e,t){var n=t.length;if(!n)return e;var r=n-1;return t[r]=(1<n?\"& \":\"\")+t[r],t=t.join(2<n?\", \":\" \"),e.replace(ts,\"{\\n/* [wrapped with \"+t+\"] */\\n\")}(o,(i=o.match(ns),r=i?i[1].split(rs):[],a=n,Ls(uo,function(e){var t=\"_.\"+e[0];a&e[1]&&!qs(r,t)&&r.push(t)}),r.sort())))}function ur(n){var r=0,a=0;return function(){var e=V(),t=16-(e-a);if(a=e,0<t){if(800<=++r)return arguments[0]}else r=0;return n.apply(to,arguments)}}function cr(e,t){var n=-1,r=e.length,a=r-1;for(t=t===to?r:t;++n<t;){var i=At(n,a),o=e[i];e[i]=e[n],e[n]=o}return e.length=t,e}var lr,fr,hr=(fr=(lr=la(function(e){var a=[];return 46===e.charCodeAt(0)&&a.push(\"\"),e.replace(Jo,function(e,t,n,r){a.push(n?r.replace(is,\"$1\"):t||e)}),a},function(e){return 500===fr.size&&fr.clear(),e})).cache,lr);function dr(e){if(\"string\"==typeof e||Ya(e))return e;var t=e+\"\";return\"0\"==t&&1/e==-1/0?\"-0\":t}function pr(e){if(null!=e){try{return c.call(e)}catch(e){}try{return e+\"\"}catch(e){}}return\"\"}function mr(e){if(e instanceof ye)return e.clone();var t=new ve(e.__wrapped__,e.__chain__);return t.__actions__=rn(e.__actions__),t.__index__=e.__index__,t.__values__=e.__values__,t}var gr=kt(function(e,t){return xa(e)?We(e,Ge(t,1,xa,!0)):[]}),vr=kt(function(e,t){var n=Sr(t);return xa(n)&&(n=to),xa(e)?We(e,Ge(t,1,xa,!0),Rn(n,2)):[]}),yr=kt(function(e,t){var n=Sr(t);return xa(n)&&(n=to),xa(e)?We(e,Ge(t,1,xa,!0),to,n):[]});function _r(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var a=null==n?0:Ba(n);return a<0&&(a=U(r+a,0)),Vs(e,Rn(t,3),a)}function br(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var a=r-1;return n!==to&&(a=Ba(n),a=n<0?U(r+a,0):$(a,r-1)),Vs(e,Rn(t,3),a,!0)}function wr(e){return null!=e&&e.length?Ge(e,1):[]}function Ar(e){return e&&e.length?e[0]:to}var xr=kt(function(e){var t=Hs(e,Gt);return t.length&&t[0]===e[0]?rt(t):[]}),kr=kt(function(e){var t=Sr(e),n=Hs(e,Gt);return t===Sr(n)?t=to:n.pop(),n.length&&n[0]===e[0]?rt(n,Rn(t,2)):[]}),Er=kt(function(e){var t=Sr(e),n=Hs(e,Gt);return(t=\"function\"==typeof t?t:to)&&n.pop(),n.length&&n[0]===e[0]?rt(n,to,t):[]});function Sr(e){var t=null==e?0:e.length;return t?e[t-1]:to}var Mr=kt(Tr);function Tr(e,t){return e&&e.length&&t&&t.length?bt(e,t):e}var Cr=On(function(e,t){var n=null==e?0:e.length,r=ze(e,t);return wt(e,Hs(t,function(e){return $n(e,n)?+e:e}).sort(en)),r});function Dr(e){return null==e?e:X.call(e)}var Or=kt(function(e){return Yt(Ge(e,1,xa,!0))}),jr=kt(function(e){var t=Sr(e);return xa(t)&&(t=to),Yt(Ge(e,1,xa,!0),Rn(t,2))}),Nr=kt(function(e){var t=Sr(e);return t=\"function\"==typeof t?t:to,Yt(Ge(e,1,xa,!0),to,t)});function zr(t){if(!t||!t.length)return[];var n=0;return t=Ws(t,function(e){if(xa(e))return n=U(e.length,n),!0}),nu(n,function(e){return Hs(t,Qs(e))})}function Pr(e,t){if(!e||!e.length)return[];var n=zr(e);return null==t?n:Hs(n,function(e){return zs(t,to,e)})}var Lr=kt(function(e,t){return xa(e)?We(e,t):[]}),Rr=kt(function(e){return Ft(Ws(e,xa))}),Yr=kt(function(e){var t=Sr(e);return xa(t)&&(t=to),Ft(Ws(e,xa),Rn(t,2))}),Wr=kt(function(e){var t=Sr(e);return t=\"function\"==typeof t?t:to,Ft(Ws(e,xa),to,t)}),qr=kt(zr);var Ir=kt(function(e){var t=e.length,n=1<t?e[t-1]:to;return Pr(e,n=\"function\"==typeof n?(e.pop(),n):to)});function Hr(e){var t=pe(e);return t.__chain__=!0,t}function Fr(e,t){return t(e)}var Br=On(function(t){var n=t.length,e=n?t[0]:0,r=this.__wrapped__,a=function(e){return ze(e,t)};return!(1<n||this.__actions__.length)&&r instanceof ye&&$n(e)?((r=r.slice(e,+e+(n?1:0))).__actions__.push({func:Fr,args:[a],thisArg:to}),new ve(r,this.__chain__).thru(function(e){return n&&!e.length&&e.push(to),e})):this.thru(a)});var Gr=on(function(e,t,n){E.call(e,n)?++e[n]:Ne(e,n,1)});var Ur=dn(_r),$r=dn(br);function Vr(e,t){return(ba(e)?Ls:qe)(e,Rn(t,3))}function Jr(e,t){return(ba(e)?Rs:Ie)(e,Rn(t,3))}var Kr=on(function(e,t,n){E.call(e,n)?e[n].push(t):Ne(e,n,[t])});var Xr=kt(function(e,t,n){var r=-1,a=\"function\"==typeof t,i=Aa(e)?T(e.length):[];return qe(e,function(e){i[++r]=a?zs(t,e,n):at(e,t,n)}),i}),Zr=on(function(e,t,n){Ne(e,n,t)});function Qr(e,t){return(ba(e)?Hs:dt)(e,Rn(t,3))}var ea=on(function(e,t,n){e[n?0:1].push(t)},function(){return[[],[]]});var ta=kt(function(e,t){if(null==e)return[];var n=t.length;return 1<n&&Vn(e,t[0],t[1])?t=[]:2<n&&Vn(t[0],t[1],t[2])&&(t=[t[0]]),yt(e,Ge(t,1),[])}),na=R||function(){return Ss.Date.now()};function ra(e,t,n){return t=n?to:t,t=e&&null==t?e.length:t,Sn(e,128,to,to,to,to,t)}function aa(e,t){var n;if(\"function\"!=typeof t)throw new C(no);return e=Ba(e),function(){return 0<--e&&(n=t.apply(this,arguments)),e<=1&&(t=to),n}}var ia=kt(function(e,t,n){var r=1;if(n.length){var a=pu(n,Ln(ia));r|=32}return Sn(e,r,t,n,a)}),oa=kt(function(e,t,n){var r=3;if(n.length){var a=pu(n,Ln(oa));r|=32}return Sn(t,r,e,n,a)});function sa(r,a,e){var i,o,s,u,c,l,f=0,h=!1,d=!1,t=!0;if(\"function\"!=typeof r)throw new C(no);function p(e){var t=i,n=o;return i=o=to,f=e,u=r.apply(n,t)}function m(e){var t=e-l;return l===to||a<=t||t<0||d&&s<=e-f}function g(){var e,t,n=na();if(m(n))return v(n);c=ir(g,(t=a-((e=n)-l),d?$(t,s-(e-f)):t))}function v(e){return c=to,t&&i?p(e):(i=o=to,u)}function n(){var e,t=na(),n=m(t);if(i=arguments,o=this,l=t,n){if(c===to)return f=e=l,c=ir(g,a),h?p(e):u;if(d)return Kt(c),c=ir(g,a),p(l)}return c===to&&(c=ir(g,a)),u}return a=Ua(a)||0,Da(e)&&(h=!!e.leading,s=(d=\"maxWait\"in e)?U(Ua(e.maxWait)||0,a):s,t=\"trailing\"in e?!!e.trailing:t),n.cancel=function(){c!==to&&Kt(c),f=0,i=l=o=c=to},n.flush=function(){return c===to?u:v(na())},n}var ua=kt(function(e,t){return Ye(e,1,t)}),ca=kt(function(e,t,n){return Ye(e,Ua(t)||0,n)});function la(a,i){if(\"function\"!=typeof a||null!=i&&\"function\"!=typeof i)throw new C(no);var o=function(){var e=arguments,t=i?i.apply(this,e):e[0],n=o.cache;if(n.has(t))return n.get(t);var r=a.apply(this,e);return o.cache=n.set(t,r)||n,r};return o.cache=new(la.Cache||we),o}function fa(t){if(\"function\"!=typeof t)throw new C(no);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}la.Cache=we;var ha=Vt(function(r,a){var i=(a=1==a.length&&ba(a[0])?Hs(a[0],ru(Rn())):Hs(Ge(a,1),ru(Rn()))).length;return kt(function(e){for(var t=-1,n=$(e.length,i);++t<n;)e[t]=a[t].call(this,e[t]);return zs(r,this,e)})}),da=kt(function(e,t){var n=pu(t,Ln(da));return Sn(e,32,to,t,n)}),pa=kt(function(e,t){var n=pu(t,Ln(pa));return Sn(e,64,to,t,n)}),ma=On(function(e,t){return Sn(e,256,to,to,to,t)});function ga(e,t){return e===t||e!=e&&t!=t}var va=wn(et),ya=wn(function(e,t){return t<=e}),_a=it(function(){return arguments}())?it:function(e){return Oa(e)&&E.call(e,\"callee\")&&!D.call(e,\"callee\")},ba=T.isArray,wa=Ts?ru(Ts):function(e){return Oa(e)&&Qe(e)==So};function Aa(e){return null!=e&&Ca(e.length)&&!Ma(e)}function xa(e){return Oa(e)&&Aa(e)}var ka=H||Ui,Ea=Cs?ru(Cs):function(e){return Oa(e)&&Qe(e)==ho};function Sa(e){if(!Oa(e))return!1;var t=Qe(e);return t==po||\"[object DOMException]\"==t||\"string\"==typeof e.message&&\"string\"==typeof e.name&&!za(e)}function Ma(e){if(!Da(e))return!1;var t=Qe(e);return t==mo||t==go||\"[object AsyncFunction]\"==t||\"[object Proxy]\"==t}function Ta(e){return\"number\"==typeof e&&e==Ba(e)}function Ca(e){return\"number\"==typeof e&&-1<e&&e%1==0&&e<=io}function Da(e){var t=typeof e;return null!=e&&(\"object\"==t||\"function\"==t)}function Oa(e){return null!=e&&\"object\"==typeof e}var ja=Ds?ru(Ds):function(e){return Oa(e)&&Fn(e)==vo};function Na(e){return\"number\"==typeof e||Oa(e)&&Qe(e)==yo}function za(e){if(!Oa(e)||Qe(e)!=_o)return!1;var t=S(e);if(null===t)return!0;var n=E.call(t,\"constructor\")&&t.constructor;return\"function\"==typeof n&&n instanceof n&&c.call(n)==m}var Pa=Os?ru(Os):function(e){return Oa(e)&&Qe(e)==wo};var La=js?ru(js):function(e){return Oa(e)&&Fn(e)==Ao};function Ra(e){return\"string\"==typeof e||!ba(e)&&Oa(e)&&Qe(e)==xo}function Ya(e){return\"symbol\"==typeof e||Oa(e)&&Qe(e)==ko}var Wa=Ns?ru(Ns):function(e){return Oa(e)&&Ca(e.length)&&!!As[Qe(e)]};var qa=wn(ht),Ia=wn(function(e,t){return e<=t});function Ha(e){if(!e)return[];if(Aa(e))return Ra(e)?vu(e):rn(e);if(N&&e[N])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[N]());var t=Fn(e);return(t==vo?hu:t==Ao?mu:gi)(e)}function Fa(e){return e?(e=Ua(e))!==1/0&&e!==-1/0?e==e?e:0:17976931348623157e292*(e<0?-1:1):0===e?e:0}function Ba(e){var t=Fa(e),n=t%1;return t==t?n?t-n:t:0}function Ga(e){return e?Pe(Ba(e),0,so):0}function Ua(e){if(\"number\"==typeof e)return e;if(Ya(e))return oo;if(Da(e)){var t=\"function\"==typeof e.valueOf?e.valueOf():e;e=Da(t)?t+\"\":t}if(\"string\"!=typeof e)return 0===e?e:+e;e=e.replace(Zo,\"\");var n=cs.test(e);return n||fs.test(e)?Es(e.slice(2),n?2:8):us.test(e)?oo:+e}function $a(e){return an(e,ui(e))}function Va(e){return null==e?\"\":Rt(e)}var Ja=sn(function(e,t){if(Zn(t)||Aa(t))an(t,si(t),e);else for(var n in t)E.call(t,n)&&Ce(e,n,t[n])}),Ka=sn(function(e,t){an(t,ui(t),e)}),Xa=sn(function(e,t,n,r){an(t,ui(t),e,r)}),Za=sn(function(e,t,n,r){an(t,si(t),e,r)}),Qa=On(ze);var ei=kt(function(e,t){e=k(e);var n=-1,r=t.length,a=2<r?t[2]:to;for(a&&Vn(t[0],t[1],a)&&(r=1);++n<r;)for(var i=t[n],o=ui(i),s=-1,u=o.length;++s<u;){var c=o[s],l=e[c];(l===to||ga(l,f[c])&&!E.call(e,c))&&(e[c]=i[c])}return e}),ti=kt(function(e){return e.push(to,Tn),zs(li,to,e)});function ni(e,t,n){var r=null==e?to:Xe(e,t);return r===to?n:r}function ri(e,t){return null!=e&&Bn(e,t,nt)}var ai=gn(function(e,t,n){null!=t&&\"function\"!=typeof t.toString&&(t=p.call(t)),e[t]=n},Di(Ni)),ii=gn(function(e,t,n){null!=t&&\"function\"!=typeof t.toString&&(t=p.call(t)),E.call(e,t)?e[t].push(n):e[t]=[n]},Rn),oi=kt(at);function si(e){return Aa(e)?ke(e):lt(e)}function ui(e){return Aa(e)?ke(e,!0):ft(e)}var ci=sn(function(e,t,n){gt(e,t,n)}),li=sn(function(e,t,n,r){gt(e,t,n,r)}),fi=On(function(t,e){var n={};if(null==t)return n;var r=!1;e=Hs(e,function(e){return e=$t(e,t),r||(r=1<e.length),e}),an(t,Nn(t),n),r&&(n=Le(n,7,Cn));for(var a=e.length;a--;)Wt(n,e[a]);return n});var hi=On(function(e,t){return null==e?{}:_t(n=e,t,function(e,t){return ri(n,t)});var n});function di(e,n){if(null==e)return{};var t=Hs(Nn(e),function(e){return[e]});return n=Rn(n),_t(e,t,function(e,t){return n(e,t[0])})}var pi=En(si),mi=En(ui);function gi(e){return null==e?[]:au(e,si(e))}var vi=fn(function(e,t,n){return t=t.toLowerCase(),e+(n?yi(t):t)});function yi(e){return Si(Va(e).toLowerCase())}function _i(e){return(e=Va(e))&&e.replace(ds,uu).replace(vs,\"\")}var bi=fn(function(e,t,n){return e+(n?\"-\":\"\")+t.toLowerCase()}),wi=fn(function(e,t,n){return e+(n?\" \":\"\")+t.toLowerCase()}),Ai=ln(\"toLowerCase\");var xi=fn(function(e,t,n){return e+(n?\"_\":\"\")+t.toLowerCase()});var ki=fn(function(e,t,n){return e+(n?\" \":\"\")+Si(t)});var Ei=fn(function(e,t,n){return e+(n?\" \":\"\")+t.toUpperCase()}),Si=ln(\"toUpperCase\");function Mi(e,t,n){return e=Va(e),(t=n?to:t)===to?(r=e,_s.test(r)?e.match(ys)||[]:e.match(as)||[]):e.match(t)||[];var r}var Ti=kt(function(e,t){try{return zs(e,to,t)}catch(e){return Sa(e)?e:new a(e)}}),Ci=On(function(t,e){return Ls(e,function(e){e=dr(e),Ne(t,e,ia(t[e],t))}),t});function Di(e){return function(){return e}}var Oi=pn(),ji=pn(!0);function Ni(e){return e}function zi(e){return ct(\"function\"==typeof e?e:Le(e,1))}var Pi=kt(function(t,n){return function(e){return at(e,t,n)}}),Li=kt(function(t,n){return function(e){return at(t,e,n)}});function Ri(r,t,e){var n=si(t),a=Ke(t,n);null!=e||Da(t)&&(a.length||!n.length)||(e=t,t=r,r=this,a=Ke(t,si(t)));var i=!(Da(e)&&\"chain\"in e&&!e.chain),o=Ma(r);return Ls(a,function(e){var n=t[e];r[e]=n,o&&(r.prototype[e]=function(){var e=this.__chain__;if(i||e){var t=r(this.__wrapped__);return(t.__actions__=rn(this.__actions__)).push({func:n,args:arguments,thisArg:r}),t.__chain__=e,t}return n.apply(r,Fs([this.value()],arguments))})}),r}function Yi(){}var Wi=yn(Hs),qi=yn(Ys),Ii=yn(Us);function Hi(e){return Jn(e)?Qs(dr(e)):(t=e,function(e){return Xe(e,t)});var t}var Fi=bn(),Bi=bn(!0);function Gi(){return[]}function Ui(){return!1}var $i=vn(function(e,t){return e+t},0),Vi=xn(\"ceil\"),Ji=vn(function(e,t){return e/t},1),Ki=xn(\"floor\");var Xi,Zi=vn(function(e,t){return e*t},1),Qi=xn(\"round\"),eo=vn(function(e,t){return e-t},0);return pe.after=function(e,t){if(\"function\"!=typeof t)throw new C(no);return e=Ba(e),function(){if(--e<1)return t.apply(this,arguments)}},pe.ary=ra,pe.assign=Ja,pe.assignIn=Ka,pe.assignInWith=Xa,pe.assignWith=Za,pe.at=Qa,pe.before=aa,pe.bind=ia,pe.bindAll=Ci,pe.bindKey=oa,pe.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return ba(e)?e:[e]},pe.chain=Hr,pe.chunk=function(e,t,n){t=(n?Vn(e,t,n):t===to)?1:U(Ba(t),0);var r=null==e?0:e.length;if(!r||t<1)return[];for(var a=0,i=0,o=T(W(r/t));a<r;)o[i++]=Ot(e,a,a+=t);return o},pe.compact=function(e){for(var t=-1,n=null==e?0:e.length,r=0,a=[];++t<n;){var i=e[t];i&&(a[r++]=i)}return a},pe.concat=function(){var e=arguments.length;if(!e)return[];for(var t=T(e-1),n=arguments[0],r=e;r--;)t[r-1]=arguments[r];return Fs(ba(n)?rn(n):[n],Ge(t,1))},pe.cond=function(r){var a=null==r?0:r.length,t=Rn();return r=a?Hs(r,function(e){if(\"function\"!=typeof e[1])throw new C(no);return[t(e[0]),e[1]]}):[],kt(function(e){for(var t=-1;++t<a;){var n=r[t];if(zs(n[0],this,e))return zs(n[1],this,e)}})},pe.conforms=function(e){return t=Le(e,1),n=si(t),function(e){return Re(e,t,n)};var t,n},pe.constant=Di,pe.countBy=Gr,pe.create=function(e,t){var n=me(e);return null==t?n:je(n,t)},pe.curry=function e(t,n,r){var a=Sn(t,8,to,to,to,to,to,n=r?to:n);return a.placeholder=e.placeholder,a},pe.curryRight=function e(t,n,r){var a=Sn(t,16,to,to,to,to,to,n=r?to:n);return a.placeholder=e.placeholder,a},pe.debounce=sa,pe.defaults=ei,pe.defaultsDeep=ti,pe.defer=ua,pe.delay=ca,pe.difference=gr,pe.differenceBy=vr,pe.differenceWith=yr,pe.drop=function(e,t,n){var r=null==e?0:e.length;return r?Ot(e,(t=n||t===to?1:Ba(t))<0?0:t,r):[]},pe.dropRight=function(e,t,n){var r=null==e?0:e.length;return r?Ot(e,0,(t=r-(t=n||t===to?1:Ba(t)))<0?0:t):[]},pe.dropRightWhile=function(e,t){return e&&e.length?It(e,Rn(t,3),!0,!0):[]},pe.dropWhile=function(e,t){return e&&e.length?It(e,Rn(t,3),!0):[]},pe.fill=function(e,t,n,r){var a=null==e?0:e.length;return a?(n&&\"number\"!=typeof n&&Vn(e,t,n)&&(n=0,r=a),function(e,t,n,r){var a=e.length;for((n=Ba(n))<0&&(n=a<-n?0:a+n),(r=r===to||a<r?a:Ba(r))<0&&(r+=a),r=r<n?0:Ga(r);n<r;)e[n++]=t;return e}(e,t,n,r)):[]},pe.filter=function(e,t){return(ba(e)?Ws:Be)(e,Rn(t,3))},pe.flatMap=function(e,t){return Ge(Qr(e,t),1)},pe.flatMapDeep=function(e,t){return Ge(Qr(e,t),1/0)},pe.flatMapDepth=function(e,t,n){return n=n===to?1:Ba(n),Ge(Qr(e,t),n)},pe.flatten=wr,pe.flattenDeep=function(e){return null!=e&&e.length?Ge(e,1/0):[]},pe.flattenDepth=function(e,t){return null!=e&&e.length?Ge(e,t=t===to?1:Ba(t)):[]},pe.flip=function(e){return Sn(e,512)},pe.flow=Oi,pe.flowRight=ji,pe.fromPairs=function(e){for(var t=-1,n=null==e?0:e.length,r={};++t<n;){var a=e[t];r[a[0]]=a[1]}return r},pe.functions=function(e){return null==e?[]:Ke(e,si(e))},pe.functionsIn=function(e){return null==e?[]:Ke(e,ui(e))},pe.groupBy=Kr,pe.initial=function(e){return null!=e&&e.length?Ot(e,0,-1):[]},pe.intersection=xr,pe.intersectionBy=kr,pe.intersectionWith=Er,pe.invert=ai,pe.invertBy=ii,pe.invokeMap=Xr,pe.iteratee=zi,pe.keyBy=Zr,pe.keys=si,pe.keysIn=ui,pe.map=Qr,pe.mapKeys=function(e,r){var a={};return r=Rn(r,3),Ve(e,function(e,t,n){Ne(a,r(e,t,n),e)}),a},pe.mapValues=function(e,r){var a={};return r=Rn(r,3),Ve(e,function(e,t,n){Ne(a,t,r(e,t,n))}),a},pe.matches=function(e){return pt(Le(e,1))},pe.matchesProperty=function(e,t){return mt(e,Le(t,1))},pe.memoize=la,pe.merge=ci,pe.mergeWith=li,pe.method=Pi,pe.methodOf=Li,pe.mixin=Ri,pe.negate=fa,pe.nthArg=function(t){return t=Ba(t),kt(function(e){return vt(e,t)})},pe.omit=fi,pe.omitBy=function(e,t){return di(e,fa(Rn(t)))},pe.once=function(e){return aa(2,e)},pe.orderBy=function(e,t,n,r){return null==e?[]:(ba(t)||(t=null==t?[]:[t]),ba(n=r?to:n)||(n=null==n?[]:[n]),yt(e,t,n))},pe.over=Wi,pe.overArgs=ha,pe.overEvery=qi,pe.overSome=Ii,pe.partial=da,pe.partialRight=pa,pe.partition=ea,pe.pick=hi,pe.pickBy=di,pe.property=Hi,pe.propertyOf=function(t){return function(e){return null==t?to:Xe(t,e)}},pe.pull=Mr,pe.pullAll=Tr,pe.pullAllBy=function(e,t,n){return e&&e.length&&t&&t.length?bt(e,t,Rn(n,2)):e},pe.pullAllWith=function(e,t,n){return e&&e.length&&t&&t.length?bt(e,t,to,n):e},pe.pullAt=Cr,pe.range=Fi,pe.rangeRight=Bi,pe.rearg=ma,pe.reject=function(e,t){return(ba(e)?Ws:Be)(e,fa(Rn(t,3)))},pe.remove=function(e,t){var n=[];if(!e||!e.length)return n;var r=-1,a=[],i=e.length;for(t=Rn(t,3);++r<i;){var o=e[r];t(o,r,e)&&(n.push(o),a.push(r))}return wt(e,a),n},pe.rest=function(e,t){if(\"function\"!=typeof e)throw new C(no);return kt(e,t=t===to?t:Ba(t))},pe.reverse=Dr,pe.sampleSize=function(e,t,n){return t=(n?Vn(e,t,n):t===to)?1:Ba(t),(ba(e)?Se:St)(e,t)},pe.set=function(e,t,n){return null==e?e:Mt(e,t,n)},pe.setWith=function(e,t,n,r){return r=\"function\"==typeof r?r:to,null==e?e:Mt(e,t,n,r)},pe.shuffle=function(e){return(ba(e)?Me:Dt)(e)},pe.slice=function(e,t,n){var r=null==e?0:e.length;return r?Ot(e,t,n=n&&\"number\"!=typeof n&&Vn(e,t,n)?(t=0,r):(t=null==t?0:Ba(t),n===to?r:Ba(n))):[]},pe.sortBy=ta,pe.sortedUniq=function(e){return e&&e.length?Pt(e):[]},pe.sortedUniqBy=function(e,t){return e&&e.length?Pt(e,Rn(t,2)):[]},pe.split=function(e,t,n){return n&&\"number\"!=typeof n&&Vn(e,t,n)&&(t=n=to),(n=n===to?so:n>>>0)?(e=Va(e))&&(\"string\"==typeof t||null!=t&&!Pa(t))&&!(t=Rt(t))&&fu(e)?Jt(vu(e),0,n):e.split(t,n):[]},pe.spread=function(r,a){if(\"function\"!=typeof r)throw new C(no);return a=null==a?0:U(Ba(a),0),kt(function(e){var t=e[a],n=Jt(e,0,a);return t&&Fs(n,t),zs(r,this,n)})},pe.tail=function(e){var t=null==e?0:e.length;return t?Ot(e,1,t):[]},pe.take=function(e,t,n){return e&&e.length?Ot(e,0,(t=n||t===to?1:Ba(t))<0?0:t):[]},pe.takeRight=function(e,t,n){var r=null==e?0:e.length;return r?Ot(e,(t=r-(t=n||t===to?1:Ba(t)))<0?0:t,r):[]},pe.takeRightWhile=function(e,t){return e&&e.length?It(e,Rn(t,3),!1,!0):[]},pe.takeWhile=function(e,t){return e&&e.length?It(e,Rn(t,3)):[]},pe.tap=function(e,t){return t(e),e},pe.throttle=function(e,t,n){var r=!0,a=!0;if(\"function\"!=typeof e)throw new C(no);return Da(n)&&(r=\"leading\"in n?!!n.leading:r,a=\"trailing\"in n?!!n.trailing:a),sa(e,t,{leading:r,maxWait:t,trailing:a})},pe.thru=Fr,pe.toArray=Ha,pe.toPairs=pi,pe.toPairsIn=mi,pe.toPath=function(e){return ba(e)?Hs(e,dr):Ya(e)?[e]:rn(hr(Va(e)))},pe.toPlainObject=$a,pe.transform=function(e,r,a){var t=ba(e),n=t||ka(e)||Wa(e);if(r=Rn(r,4),null==a){var i=e&&e.constructor;a=n?t?new i:[]:Da(e)&&Ma(i)?me(S(e)):{}}return(n?Ls:Ve)(e,function(e,t,n){return r(a,e,t,n)}),a},pe.unary=function(e){return ra(e,1)},pe.union=Or,pe.unionBy=jr,pe.unionWith=Nr,pe.uniq=function(e){return e&&e.length?Yt(e):[]},pe.uniqBy=function(e,t){return e&&e.length?Yt(e,Rn(t,2)):[]},pe.uniqWith=function(e,t){return t=\"function\"==typeof t?t:to,e&&e.length?Yt(e,to,t):[]},pe.unset=function(e,t){return null==e||Wt(e,t)},pe.unzip=zr,pe.unzipWith=Pr,pe.update=function(e,t,n){return null==e?e:qt(e,t,Ut(n))},pe.updateWith=function(e,t,n,r){return r=\"function\"==typeof r?r:to,null==e?e:qt(e,t,Ut(n),r)},pe.values=gi,pe.valuesIn=function(e){return null==e?[]:au(e,ui(e))},pe.without=Lr,pe.words=Mi,pe.wrap=function(e,t){return da(Ut(t),e)},pe.xor=Rr,pe.xorBy=Yr,pe.xorWith=Wr,pe.zip=qr,pe.zipObject=function(e,t){return Bt(e||[],t||[],Ce)},pe.zipObjectDeep=function(e,t){return Bt(e||[],t||[],Mt)},pe.zipWith=Ir,pe.entries=pi,pe.entriesIn=mi,pe.extend=Ka,pe.extendWith=Xa,Ri(pe,pe),pe.add=$i,pe.attempt=Ti,pe.camelCase=vi,pe.capitalize=yi,pe.ceil=Vi,pe.clamp=function(e,t,n){return n===to&&(n=t,t=to),n!==to&&(n=(n=Ua(n))==n?n:0),t!==to&&(t=(t=Ua(t))==t?t:0),Pe(Ua(e),t,n)},pe.clone=function(e){return Le(e,4)},pe.cloneDeep=function(e){return Le(e,5)},pe.cloneDeepWith=function(e,t){return Le(e,5,t=\"function\"==typeof t?t:to)},pe.cloneWith=function(e,t){return Le(e,4,t=\"function\"==typeof t?t:to)},pe.conformsTo=function(e,t){return null==t||Re(e,t,si(t))},pe.deburr=_i,pe.defaultTo=function(e,t){return null==e||e!=e?t:e},pe.divide=Ji,pe.endsWith=function(e,t,n){e=Va(e),t=Rt(t);var r=e.length,a=n=n===to?r:Pe(Ba(n),0,r);return 0<=(n-=t.length)&&e.slice(n,a)==t},pe.eq=ga,pe.escape=function(e){return(e=Va(e))&&Fo.test(e)?e.replace(Io,cu):e},pe.escapeRegExp=function(e){return(e=Va(e))&&Xo.test(e)?e.replace(Ko,\"\\\\$&\"):e},pe.every=function(e,t,n){var r=ba(e)?Ys:He;return n&&Vn(e,t,n)&&(t=to),r(e,Rn(t,3))},pe.find=Ur,pe.findIndex=_r,pe.findKey=function(e,t){return $s(e,Rn(t,3),Ve)},pe.findLast=$r,pe.findLastIndex=br,pe.findLastKey=function(e,t){return $s(e,Rn(t,3),Je)},pe.floor=Ki,pe.forEach=Vr,pe.forEachRight=Jr,pe.forIn=function(e,t){return null==e?e:Ue(e,Rn(t,3),ui)},pe.forInRight=function(e,t){return null==e?e:$e(e,Rn(t,3),ui)},pe.forOwn=function(e,t){return e&&Ve(e,Rn(t,3))},pe.forOwnRight=function(e,t){return e&&Je(e,Rn(t,3))},pe.get=ni,pe.gt=va,pe.gte=ya,pe.has=function(e,t){return null!=e&&Bn(e,t,tt)},pe.hasIn=ri,pe.head=Ar,pe.identity=Ni,pe.includes=function(e,t,n,r){e=Aa(e)?e:gi(e),n=n&&!r?Ba(n):0;var a=e.length;return n<0&&(n=U(a+n,0)),Ra(e)?n<=a&&-1<e.indexOf(t,n):!!a&&-1<Js(e,t,n)},pe.indexOf=function(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var a=null==n?0:Ba(n);return a<0&&(a=U(r+a,0)),Js(e,t,a)},pe.inRange=function(e,t,n){return t=Fa(t),n===to?(n=t,t=0):n=Fa(n),e=Ua(e),(r=e)>=$(a=t,i=n)&&r<U(a,i);var r,a,i},pe.invoke=oi,pe.isArguments=_a,pe.isArray=ba,pe.isArrayBuffer=wa,pe.isArrayLike=Aa,pe.isArrayLikeObject=xa,pe.isBoolean=function(e){return!0===e||!1===e||Oa(e)&&Qe(e)==fo},pe.isBuffer=ka,pe.isDate=Ea,pe.isElement=function(e){return Oa(e)&&1===e.nodeType&&!za(e)},pe.isEmpty=function(e){if(null==e)return!0;if(Aa(e)&&(ba(e)||\"string\"==typeof e||\"function\"==typeof e.splice||ka(e)||Wa(e)||_a(e)))return!e.length;var t=Fn(e);if(t==vo||t==Ao)return!e.size;if(Zn(e))return!lt(e).length;for(var n in e)if(E.call(e,n))return!1;return!0},pe.isEqual=function(e,t){return ot(e,t)},pe.isEqualWith=function(e,t,n){var r=(n=\"function\"==typeof n?n:to)?n(e,t):to;return r===to?ot(e,t,to,n):!!r},pe.isError=Sa,pe.isFinite=function(e){return\"number\"==typeof e&&F(e)},pe.isFunction=Ma,pe.isInteger=Ta,pe.isLength=Ca,pe.isMap=ja,pe.isMatch=function(e,t){return e===t||st(e,t,Wn(t))},pe.isMatchWith=function(e,t,n){return n=\"function\"==typeof n?n:to,st(e,t,Wn(t),n)},pe.isNaN=function(e){return Na(e)&&e!=+e},pe.isNative=function(e){if(Xn(e))throw new a(\"Unsupported core-js use. Try https://npms.io/search?q=ponyfill.\");return ut(e)},pe.isNil=function(e){return null==e},pe.isNull=function(e){return null===e},pe.isNumber=Na,pe.isObject=Da,pe.isObjectLike=Oa,pe.isPlainObject=za,pe.isRegExp=Pa,pe.isSafeInteger=function(e){return Ta(e)&&-io<=e&&e<=io},pe.isSet=La,pe.isString=Ra,pe.isSymbol=Ya,pe.isTypedArray=Wa,pe.isUndefined=function(e){return e===to},pe.isWeakMap=function(e){return Oa(e)&&Fn(e)==Eo},pe.isWeakSet=function(e){return Oa(e)&&\"[object WeakSet]\"==Qe(e)},pe.join=function(e,t){return null==e?\"\":B.call(e,t)},pe.kebabCase=bi,pe.last=Sr,pe.lastIndexOf=function(e,t,n){var r=null==e?0:e.length;if(!r)return-1;var a=r;return n!==to&&(a=(a=Ba(n))<0?U(r+a,0):$(a,r-1)),t==t?function(e,t,n){for(var r=n+1;r--;)if(e[r]===t)return r;return r}(e,t,a):Vs(e,Xs,a,!0)},pe.lowerCase=wi,pe.lowerFirst=Ai,pe.lt=qa,pe.lte=Ia,pe.max=function(e){return e&&e.length?Fe(e,Ni,et):to},pe.maxBy=function(e,t){return e&&e.length?Fe(e,Rn(t,2),et):to},pe.mean=function(e){return Zs(e,Ni)},pe.meanBy=function(e,t){return Zs(e,Rn(t,2))},pe.min=function(e){return e&&e.length?Fe(e,Ni,ht):to},pe.minBy=function(e,t){return e&&e.length?Fe(e,Rn(t,2),ht):to},pe.stubArray=Gi,pe.stubFalse=Ui,pe.stubObject=function(){return{}},pe.stubString=function(){return\"\"},pe.stubTrue=function(){return!0},pe.multiply=Zi,pe.nth=function(e,t){return e&&e.length?vt(e,Ba(t)):to},pe.noConflict=function(){return Ss._===this&&(Ss._=y),this},pe.noop=Yi,pe.now=na,pe.pad=function(e,t,n){e=Va(e);var r=(t=Ba(t))?gu(e):0;if(!t||t<=r)return e;var a=(t-r)/2;return _n(q(a),n)+e+_n(W(a),n)},pe.padEnd=function(e,t,n){e=Va(e);var r=(t=Ba(t))?gu(e):0;return t&&r<t?e+_n(t-r,n):e},pe.padStart=function(e,t,n){e=Va(e);var r=(t=Ba(t))?gu(e):0;return t&&r<t?_n(t-r,n)+e:e},pe.parseInt=function(e,t,n){return n||null==t?t=0:t&&(t=+t),J(Va(e).replace(Qo,\"\"),t||0)},pe.random=function(e,t,n){if(n&&\"boolean\"!=typeof n&&Vn(e,t,n)&&(t=n=to),n===to&&(\"boolean\"==typeof t?(n=t,t=to):\"boolean\"==typeof e&&(n=e,e=to)),e===to&&t===to?(e=0,t=1):(e=Fa(e),t===to?(t=e,e=0):t=Fa(t)),t<e){var r=e;e=t,t=r}if(n||e%1||t%1){var a=K();return $(e+a*(t-e+ks(\"1e-\"+((a+\"\").length-1))),t)}return At(e,t)},pe.reduce=function(e,t,n){var r=ba(e)?Bs:eu,a=arguments.length<3;return r(e,Rn(t,4),n,a,qe)},pe.reduceRight=function(e,t,n){var r=ba(e)?Gs:eu,a=arguments.length<3;return r(e,Rn(t,4),n,a,Ie)},pe.repeat=function(e,t,n){return t=(n?Vn(e,t,n):t===to)?1:Ba(t),xt(Va(e),t)},pe.replace=function(){var e=arguments,t=Va(e[0]);return e.length<3?t:t.replace(e[1],e[2])},pe.result=function(e,t,n){var r=-1,a=(t=$t(t,e)).length;for(a||(a=1,e=to);++r<a;){var i=null==e?to:e[dr(t[r])];i===to&&(r=a,i=n),e=Ma(i)?i.call(e):i}return e},pe.round=Qi,pe.runInContext=e,pe.sample=function(e){return(ba(e)?Ee:Et)(e)},pe.size=function(e){if(null==e)return 0;if(Aa(e))return Ra(e)?gu(e):e.length;var t=Fn(e);return t==vo||t==Ao?e.size:lt(e).length},pe.snakeCase=xi,pe.some=function(e,t,n){var r=ba(e)?Us:jt;return n&&Vn(e,t,n)&&(t=to),r(e,Rn(t,3))},pe.sortedIndex=function(e,t){return Nt(e,t)},pe.sortedIndexBy=function(e,t,n){return zt(e,t,Rn(n,2))},pe.sortedIndexOf=function(e,t){var n=null==e?0:e.length;if(n){var r=Nt(e,t);if(r<n&&ga(e[r],t))return r}return-1},pe.sortedLastIndex=function(e,t){return Nt(e,t,!0)},pe.sortedLastIndexBy=function(e,t,n){return zt(e,t,Rn(n,2),!0)},pe.sortedLastIndexOf=function(e,t){if(null!=e&&e.length){var n=Nt(e,t,!0)-1;if(ga(e[n],t))return n}return-1},pe.startCase=ki,pe.startsWith=function(e,t,n){return e=Va(e),n=null==n?0:Pe(Ba(n),0,e.length),t=Rt(t),e.slice(n,n+t.length)==t},pe.subtract=eo,pe.sum=function(e){return e&&e.length?tu(e,Ni):0},pe.sumBy=function(e,t){return e&&e.length?tu(e,Rn(t,2)):0},pe.template=function(o,e,t){var n=pe.templateSettings;t&&Vn(o,e,t)&&(e=to),o=Va(o),e=Xa({},e,n,Mn);var s,u,r=Xa({},e.imports,n.imports,Mn),a=si(r),i=au(r,a),c=0,l=e.interpolate||ps,f=\"__p += '\",h=v((e.escape||ps).source+\"|\"+l.source+\"|\"+(l===Uo?os:ps).source+\"|\"+(e.evaluate||ps).source+\"|$\",\"g\"),d=\"//# sourceURL=\"+(E.call(e,\"sourceURL\")?(e.sourceURL+\"\").replace(/[\\r\\n]/g,\" \"):\"lodash.templateSources[\"+ ++ws+\"]\")+\"\\n\";o.replace(h,function(e,t,n,r,a,i){return n||(n=r),f+=o.slice(c,i).replace(ms,lu),t&&(s=!0,f+=\"' +\\n__e(\"+t+\") +\\n'\"),a&&(u=!0,f+=\"';\\n\"+a+\";\\n__p += '\"),n&&(f+=\"' +\\n((__t = (\"+n+\")) == null ? '' : __t) +\\n'\"),c=i+e.length,e}),f+=\"';\\n\";var p=E.call(e,\"variable\")&&e.variable;p||(f=\"with (obj) {\\n\"+f+\"\\n}\\n\"),f=(u?f.replace(Ro,\"\"):f).replace(Yo,\"$1\").replace(Wo,\"$1;\"),f=\"function(\"+(p||\"obj\")+\") {\\n\"+(p?\"\":\"obj || (obj = {});\\n\")+\"var __t, __p = ''\"+(s?\", __e = _.escape\":\"\")+(u?\", __j = Array.prototype.join;\\nfunction print() { __p += __j.call(arguments, '') }\\n\":\";\\n\")+f+\"return __p\\n}\";var m=Ti(function(){return g(a,d+\"return \"+f).apply(to,i)});if(m.source=f,Sa(m))throw m;return m},pe.times=function(e,t){if((e=Ba(e))<1||io<e)return[];var n=so,r=$(e,so);t=Rn(t),e-=so;for(var a=nu(r,t);++n<e;)t(n);return a},pe.toFinite=Fa,pe.toInteger=Ba,pe.toLength=Ga,pe.toLower=function(e){return Va(e).toLowerCase()},pe.toNumber=Ua,pe.toSafeInteger=function(e){return e?Pe(Ba(e),-io,io):0===e?e:0},pe.toString=Va,pe.toUpper=function(e){return Va(e).toUpperCase()},pe.trim=function(e,t,n){if((e=Va(e))&&(n||t===to))return e.replace(Zo,\"\");if(!e||!(t=Rt(t)))return e;var r=vu(e),a=vu(t);return Jt(r,ou(r,a),su(r,a)+1).join(\"\")},pe.trimEnd=function(e,t,n){if((e=Va(e))&&(n||t===to))return e.replace(es,\"\");if(!e||!(t=Rt(t)))return e;var r=vu(e);return Jt(r,0,su(r,vu(t))+1).join(\"\")},pe.trimStart=function(e,t,n){if((e=Va(e))&&(n||t===to))return e.replace(Qo,\"\");if(!e||!(t=Rt(t)))return e;var r=vu(e);return Jt(r,ou(r,vu(t))).join(\"\")},pe.truncate=function(e,t){var n=30,r=\"...\";if(Da(t)){var a=\"separator\"in t?t.separator:a;n=\"length\"in t?Ba(t.length):n,r=\"omission\"in t?Rt(t.omission):r}var i=(e=Va(e)).length;if(fu(e)){var o=vu(e);i=o.length}if(i<=n)return e;var s=n-gu(r);if(s<1)return r;var u=o?Jt(o,0,s).join(\"\"):e.slice(0,s);if(a===to)return u+r;if(o&&(s+=u.length-s),Pa(a)){if(e.slice(s).search(a)){var c,l=u;for(a.global||(a=v(a.source,Va(ss.exec(a))+\"g\")),a.lastIndex=0;c=a.exec(l);)var f=c.index;u=u.slice(0,f===to?s:f)}}else if(e.indexOf(Rt(a),s)!=s){var h=u.lastIndexOf(a);-1<h&&(u=u.slice(0,h))}return u+r},pe.unescape=function(e){return(e=Va(e))&&Ho.test(e)?e.replace(qo,yu):e},pe.uniqueId=function(e){var t=++h;return Va(e)+t},pe.upperCase=Ei,pe.upperFirst=Si,pe.each=Vr,pe.eachRight=Jr,pe.first=Ar,Ri(pe,(Xi={},Ve(pe,function(e,t){E.call(pe.prototype,t)||(Xi[t]=e)}),Xi),{chain:!1}),pe.VERSION=\"4.17.15\",Ls([\"bind\",\"bindKey\",\"curry\",\"curryRight\",\"partial\",\"partialRight\"],function(e){pe[e].placeholder=pe}),Ls([\"drop\",\"take\"],function(n,r){ye.prototype[n]=function(e){e=e===to?1:U(Ba(e),0);var t=this.__filtered__&&!r?new ye(this):this.clone();return t.__filtered__?t.__takeCount__=$(e,t.__takeCount__):t.__views__.push({size:$(e,so),type:n+(t.__dir__<0?\"Right\":\"\")}),t},ye.prototype[n+\"Right\"]=function(e){return this.reverse()[n](e).reverse()}}),Ls([\"filter\",\"map\",\"takeWhile\"],function(e,t){var n=t+1,r=1==n||3==n;ye.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:Rn(e,3),type:n}),t.__filtered__=t.__filtered__||r,t}}),Ls([\"head\",\"last\"],function(e,t){var n=\"take\"+(t?\"Right\":\"\");ye.prototype[e]=function(){return this[n](1).value()[0]}}),Ls([\"initial\",\"tail\"],function(e,t){var n=\"drop\"+(t?\"\":\"Right\");ye.prototype[e]=function(){return this.__filtered__?new ye(this):this[n](1)}}),ye.prototype.compact=function(){return this.filter(Ni)},ye.prototype.find=function(e){return this.filter(e).head()},ye.prototype.findLast=function(e){return this.reverse().find(e)},ye.prototype.invokeMap=kt(function(t,n){return\"function\"==typeof t?new ye(this):this.map(function(e){return at(e,t,n)})}),ye.prototype.reject=function(e){return this.filter(fa(Rn(e)))},ye.prototype.slice=function(e,t){e=Ba(e);var n=this;return n.__filtered__&&(0<e||t<0)?new ye(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),t!==to&&(n=(t=Ba(t))<0?n.dropRight(-t):n.take(t-e)),n)},ye.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},ye.prototype.toArray=function(){return this.take(so)},Ve(ye.prototype,function(f,e){var h=/^(?:filter|find|map|reject)|While$/.test(e),d=/^(?:head|last)$/.test(e),p=pe[d?\"take\"+(\"last\"==e?\"Right\":\"\"):e],m=d||/^find/.test(e);p&&(pe.prototype[e]=function(){var e=this.__wrapped__,n=d?[1]:arguments,t=e instanceof ye,r=n[0],a=t||ba(e),i=function(e){var t=p.apply(pe,Fs([e],n));return d&&o?t[0]:t};a&&h&&\"function\"==typeof r&&1!=r.length&&(t=a=!1);var o=this.__chain__,s=!!this.__actions__.length,u=m&&!o,c=t&&!s;if(m||!a)return u&&c?f.apply(this,n):(l=this.thru(i),u?d?l.value()[0]:l.value():l);e=c?e:new ye(this);var l=f.apply(e,n);return l.__actions__.push({func:Fr,args:[i],thisArg:to}),new ve(l,o)})}),Ls([\"pop\",\"push\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(e){var n=o[e],r=/^(?:push|sort|unshift)$/.test(e)?\"tap\":\"thru\",a=/^(?:pop|shift)$/.test(e);pe.prototype[e]=function(){var t=arguments;if(!a||this.__chain__)return this[r](function(e){return n.apply(ba(e)?e:[],t)});var e=this.value();return n.apply(ba(e)?e:[],t)}}),Ve(ye.prototype,function(e,t){var n=pe[t];if(n){var r=n.name+\"\";E.call(ie,r)||(ie[r]=[]),ie[r].push({name:t,func:n})}}),ie[mn(to,2).name]=[{name:\"wrapper\",func:to}],ye.prototype.clone=function(){var e=new ye(this.__wrapped__);return e.__actions__=rn(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=rn(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=rn(this.__views__),e},ye.prototype.reverse=function(){if(this.__filtered__){var e=new ye(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},ye.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,n=ba(e),r=t<0,a=n?e.length:0,i=function(e,t,n){for(var r=-1,a=n.length;++r<a;){var i=n[r],o=i.size;switch(i.type){case\"drop\":e+=o;break;case\"dropRight\":t-=o;break;case\"take\":t=$(t,e+o);break;case\"takeRight\":e=U(e,t-o)}}return{start:e,end:t}}(0,a,this.__views__),o=i.start,s=i.end,u=s-o,c=r?s:o-1,l=this.__iteratees__,f=l.length,h=0,d=$(u,this.__takeCount__);if(!n||!r&&a==u&&d==u)return Ht(e,this.__actions__);var p=[];e:for(;u--&&h<d;){for(var m=-1,g=e[c+=t];++m<f;){var v=l[m],y=v.iteratee,_=v.type,b=y(g);if(2==_)g=b;else if(!b){if(1==_)continue e;break e}}p[h++]=g}return p},pe.prototype.at=Br,pe.prototype.chain=function(){return Hr(this)},pe.prototype.commit=function(){return new ve(this.value(),this.__chain__)},pe.prototype.next=function(){this.__values__===to&&(this.__values__=Ha(this.value()));var e=this.__index__>=this.__values__.length;return{done:e,value:e?to:this.__values__[this.__index__++]}},pe.prototype.plant=function(e){for(var t,n=this;n instanceof ge;){var r=mr(n);r.__index__=0,r.__values__=to,t?a.__wrapped__=r:t=r;var a=r;n=n.__wrapped__}return a.__wrapped__=e,t},pe.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof ye){var t=e;return this.__actions__.length&&(t=new ye(this)),(t=t.reverse()).__actions__.push({func:Fr,args:[Dr],thisArg:to}),new ve(t,this.__chain__)}return this.thru(Dr)},pe.prototype.toJSON=pe.prototype.valueOf=pe.prototype.value=function(){return Ht(this.__wrapped__,this.__actions__)},pe.prototype.first=pe.prototype.head,N&&(pe.prototype[N]=function(){return this}),pe}();z?((z.exports=_u)._=_u,N._=_u):Ss._=_u}).call(this)});function Gu(e){return e.reduce(function(e,t,n,r){return e+t})}function Uu(e){if(Bu.isArray(e))return e;if(\"string\"==typeof e)return e.split(\"\");throw Error(\"Parameter must be a string or array.\")}var $u={jarowinkler:function(e,t,n){var r,a;e=Uu(e),t=Uu(t),a=e.length>t.length?(r=e,t):(r=t,e);var i,o,s,u,c=n||.7,l=Math.floor(Math.max(r.length/2-1,0)),f=[],h=[],d=0;for(i=0;i<a.length;i++)for(u=a[i],o=Math.max(i-l,0),s=Math.min(i+l+1,r.length);o<s;o++)if(!h[o]&&u===r[o]){h[f[i]=o]=!0,d++;break}var p,m,g=[],v=[],y=0,_=0;for(m=p=0;p<a.length;p++)-1<f[p]&&(g[m]=a[p],m++);for(m=p=0;p<r.length;p++)h[p]&&(v[m]=r[p],m++);for(i=0;i<g.length;i++)g[i]!==v[i]&&y++;for(i=0;i<a.length&&e[i]===t[i];i++)_++;var b=d;n=y/2;if(b){var w=(b/e.length+b/t.length+(b-n)/b)/3;return w<c?w:w+Math.min(.1,1/r.length)*_*(1-w)}return 0},levenshtein:function(e,t,n){if(e=Uu(e),t=Uu(t),0===e.length)return t.length;if(0===t.length)return e.length;var r,a,i,o,s=n||{d:1,i:1,s:1},u=[],c=[],l=t.length+1;for(r=0;r<l;r++)u[r]=r;for(r=0;r<e.length;r++){for(c[0]=r+1,a=0;a<t.length;a++)i=e[r]===t[a]?0:s.s,c[a+1]=Math.min(c[a]+s.d,u[a+1]+s.i,u[a]+i);for(a=0;a<l;a++)u[a]=c[a]}return((o=Math.max(e.length,t.length))-c[t.length])/o},ngram:function(e,t,n){e=Uu(e),t=Uu(t);var r,a,i,o,s,u,c,l=e.length,f=t.length,h=n||2,d=[],p=[],m=[],g=[],v=[];if(0===l||0===f)return l===f?1:0;if(r=0,l<h||f<h){for(a=0,o=Math.min(l,f);a<o;a++)e[a]===t[a]&&r++;return r/Math.max(l,f)}for(a=0;a<l+h-1;a++)d[a]=a<h-1?0:e[a-h+1];for(a=0;a<=l;a++)p[a]=a;for(i=1;i<=f;i++){if(i<h){for(s=0;s<h-i;s++)v[s]=0;for(s=h-i;s<h;s++)v[s]=t[s-(h-i)]}else v=t.slice(i-h,i);for(m[0]=i,a=1;a<=l;a++){for(u=h,o=r=0;o<h;o++)d[a-1+o]!==v[o]?r++:0===d[a-1+o]&&u--;c=r/u,m[a]=Math.min(Math.min(m[a-1]+1,p[a]+1),p[a-1]+c)}g=p,p=m,m=g}return 1-p[l]/Math.max(l,f)},pearson:function(t,n){var r=[];Object.keys(t).forEach(function(e){n[e]&&r.push(e)});var e=r.length;if(0===e)return 0;var a=Gu(r.map(function(e){return t[e]})),i=Gu(r.map(function(e){return n[e]})),o=Gu(r.map(function(e){return Math.pow(t[e],2)})),s=Gu(r.map(function(e){return Math.pow(n[e],2)})),u=Gu(r.map(function(e){return t[e]*n[e]}))-a*i/e,c=Math.sqrt((o-Math.pow(a,2)/e)*(s-Math.pow(i,2)/e));return 0===c?0:u/c},jaccard:function(e,t){return e=Uu(e),t=Uu(t),Bu.intersection(e,t).length/Bu.union(e,t).length},tanimoto:function(e,t){e=Uu(e),t=Uu(t);var n=Bu.intersection(e,t).length;return n/(e.length+t.length-n)}};var Vu={author:$s,lead_image_url:Js,dek:function(e,t){var n=t.$,r=t.excerpt;if(1e3<e.length||e.length<5)return null;if(r&&Pa(r,10)===Pa(e,10))return null;var a=es(e,n);return Ns.test(a)?null:ua(a.trim())},date_published:Iu,content:Hu,title:Fu};function Ju(e,t){var o,a,i,s;return t.stripUnlikelyCandidates&&((o=e)(\"*\").not(\"a\").each(function(e,t){var n=o(t),r=n.attr(\"class\"),a=n.attr(\"id\");if(a||r){var i=\"\".concat(r||\"\",\" \").concat(a||\"\");ki.test(i)||Ai.test(i)&&n.remove()}}),e=o),e=function(a){var e=!(1<arguments.length&&void 0!==arguments[1])||arguments[1];return Wi.forEach(function(e){var t=ja(e,2),n=t[0],r=t[1];a(\"\".concat(n,\" \").concat(r)).each(function(e,t){ro(a(t).parent(n),a,80)})}),so(a,e),so(a,e),a}(e=Si(e),t.weightNodes),s=0,(a=e)(\"[score]\").each(function(e,t){if(!Yi.test(t.tagName)){var n=a(t),r=Zi(n);s<r&&(s=r,i=n)}}),i?i=uo(i,s,a):a(\"body\")||a(\"*\").first()}var Ku={defaultOpts:{stripUnlikelyCandidates:!0,weightNodes:!0,cleanConditionally:!0},extract:function(e,t){var n=e.$,r=e.html,a=e.title,i=e.url;t=pt({},this.defaultOpts,t),n=n||Cr.load(r);var o=this.getContentNode(n,a,i,t);if(ts(o))return this.cleanAndReturnNode(o,n);var s=!0,u=!1,c=void 0;try{for(var l,f=Ca(si(t).filter(function(e){return!0===t[e]}));!(s=(l=f.next()).done);s=!0){var h=l.value;if(t[h]=!1,n=Cr.load(r),ts(o=this.getContentNode(n,a,i,t)))break}}catch(e){u=!0,c=e}finally{try{s||null==f.return||f.return()}finally{if(u)throw c}}return this.cleanAndReturnNode(o,n)},getContentNode:function(e,t,n,r){return Hu(Ju(e,r),{$:e,cleanConditionally:r.cleanConditionally,title:t,url:n})},cleanAndReturnNode:function(e,t){return e?ua(t.html(e)):null}},Xu=[\"tweetmeme-title\",\"dc.title\",\"rbtitle\",\"headline\",\"title\"],Zu=[\"og:title\"],Qu=[\".hentry .entry-title\",\"h1#articleHeader\",\"h1.articleHeader\",\"h1.article\",\".instapaper_title\",\"#meebo-title\"],ec=[\"article h1\",\"#entry-title\",\".entry-title\",\"#entryTitle\",\"#entrytitle\",\".entryTitle\",\".entrytitle\",\"#articleTitle\",\".articleTitle\",\"post post-title\",\"h1.title\",\"h2.article\",\"h1\",\"html head title\",\"title\"],tc={extract:function(e){var t,n=e.$,r=e.url,a=e.metaCache;return(t=Xo(n,Xu,a))?Fu(t,{url:r,$:n}):(t=Qo(n,Qu))?Fu(t,{url:r,$:n}):(t=Xo(n,Zu,a))?Fu(t,{url:r,$:n}):(t=Qo(n,ec))?Fu(t,{url:r,$:n}):\"\"}},nc=[\"byl\",\"clmst\",\"dc.author\",\"dcsext.author\",\"dc.creator\",\"rbauthors\",\"authors\"],rc=[\".entry .entry-author\",\".author.vcard .fn\",\".author .vcard .fn\",\".byline.vcard .fn\",\".byline .vcard .fn\",\".byline .by .author\",\".byline .by\",\".byline .author\",\".post-author.vcard\",\".post-author .vcard\",\"a[rel=author]\",\"#by_author\",\".by_author\",\"#entryAuthor\",\".entryAuthor\",\".byline a[href*=author]\",\"#author .authorname\",\".author .authorname\",\"#author\",\".author\",\".articleauthor\",\".ArticleAuthor\",\".byline\"],ac=/^[\\n\\s]*By/i,ic=[[\"#byline\",ac],[\".byline\",ac]],oc={extract:function(e){var t,n=e.$,r=e.metaCache;if((t=Xo(n,nc,r))&&t.length<300)return $s(t);if((t=Qo(n,rc,2))&&t.length<300)return $s(t);var a=!0,i=!1,o=void 0;try{for(var s,u=Ca(ic);!(a=(s=u.next()).done);a=!0){var c=ja(s.value,2),l=c[0],f=c[1],h=n(l);if(1===h.length){var d=h.text();if(f.test(d))return $s(d)}}}catch(e){i=!0,o=e}finally{try{a||null==u.return||u.return()}finally{if(i)throw o}}return null}},sc=[\"article:published_time\",\"displaydate\",\"dc.date\",\"dc.date.issued\",\"rbpubdate\",\"publish_date\",\"pub_date\",\"pagedate\",\"pubdate\",\"revision_date\",\"doc_date\",\"date_created\",\"content_create_date\",\"lastmodified\",\"created\",\"date\"],uc=[\".hentry .dtstamp.published\",\".hentry .published\",\".hentry .dtstamp.updated\",\".hentry .updated\",\".single .published\",\".meta .published\",\".meta .postDate\",\".entry-date\",\".byline .date\",\".postmetadata .date\",\".article_datetime\",\".date-header\",\".story-date\",\".dateStamp\",\"#story .datetime\",\".dateline\",\".pubdate\"],cc=[new RegExp(\"/(20\\\\d{2}/\\\\d{2}/\\\\d{2})/\",\"i\"),new RegExp(\"(20\\\\d{2}-[01]\\\\d-[0-3]\\\\d)\",\"i\"),new RegExp(\"/(20\\\\d{2}/\".concat(\"(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\",\"/[0-3]\\\\d)/\"),\"i\")],lc={extract:function(e){var t,n,r,a=e.$,i=e.url,o=e.metaCache;return(t=Xo(a,sc,o,!1))?Iu(t):(t=Qo(a,uc))?Iu(t):(n=i,(t=(r=cc.find(function(e){return e.test(n)}))?r.exec(n)[1]:null)?Iu(t):null)}},fc=[\"og:image\",\"twitter:image\",\"image_src\"],hc=[\"link[rel=image_src]\"],dc=new RegExp([\"upload\",\"wp-content\",\"large\",\"photo\",\"wp-image\"].join(\"|\"),\"i\"),pc=new RegExp([\"spacer\",\"sprite\",\"blank\",\"throbber\",\"gradient\",\"tile\",\"bg\",\"background\",\"icon\",\"social\",\"header\",\"hdr\",\"advert\",\"spinner\",\"loader\",\"loading\",\"default\",\"rating\",\"share\",\"facebook\",\"twitter\",\"theme\",\"promo\",\"ads\",\"wp-includes\"].join(\"|\"),\"i\"),mc=/\\.gif(\\?.*)?$/i,gc=/\\.jpe?g(\\?.*)?$/i;function vc(e){return\"\".concat(e.attr(\"class\")||\"\",\" \").concat(e.attr(\"id\")||\"\")}var yc={extract:function(e){var t,c=e.$,n=e.content,r=e.metaCache,a=e.html;c.browser||0!==c(\"head\").length||c(\"*\").first().prepend(a);var i=Xo(c,fc,r,!1);if(i&&(t=Js(i)))return t;var o=c(n),l=c(\"img\",o).toArray(),f={};l.forEach(function(e,t){var n=c(e),r=n.attr(\"src\");if(r){var a,i,o,s,u=function(e){e=e.trim();var t=0;return dc.test(e)&&(t+=20),pc.test(e)&&(t-=20),mc.test(e)&&(t-=10),gc.test(e)&&(t+=10),t}(r);u+=n.attr(\"alt\")?5:0,u+=function(e){var t=0;1===e.parents(\"figure\").first().length&&(t+=25);var n,r=e.parent();return 1===r.length&&(n=r.parent()),[r,n].forEach(function(e){qi.test(vc(e))&&(t+=15)}),t}(n),u+=(a=0,i=n.next(),(o=i.get(0))&&\"figcaption\"===o.tagName.toLowerCase()&&(a+=25),qi.test(vc(i))&&(a+=15),a),u+=function(e){var t=0,n=Xi(e.attr(\"width\")),r=Xi(e.attr(\"height\")),a=e.attr(\"src\");if(n&&n<=50&&(t-=50),r&&r<=50&&(t-=50),n&&r&&!a.includes(\"sprite\")){var i=n*r;i<5e3?t-=100:t+=Math.round(i/1e3)}return t}(n),u+=(s=t,l.length/2-s),f[r]=u}});var s=si(f).reduce(function(e,t){return f[t]>e[1]?[t,f[t]]:e},[null,0]),u=ja(s,2),h=u[0];if(0<u[1]&&(t=Js(h)))return t;var d=!0,p=!1,m=void 0;try{for(var g,v=Ca(hc);!(d=(g=v.next()).done);d=!0){var y=g.value,_=c(y).first(),b=_.attr(\"src\");if(b&&(t=Js(b)))return t;var w=_.attr(\"href\");if(w&&(t=Js(w)))return t;var A=_.attr(\"value\");if(A&&(t=Js(A)))return t}}catch(e){p=!0,m=e}finally{try{d||null==v.return||v.return()}finally{if(p)throw m}}return null}},_c=e(function(t,e){(function(){var e,h,u,d,p,n,c,r,m,g,a,i,o,l,f;u=Math.floor,g=Math.min,h=function(e,t){return e<t?-1:t<e?1:0},m=function(e,t,n,r,a){var i;if(null==n&&(n=0),null==a&&(a=h),n<0)throw new Error(\"lo must be non-negative\");for(null==r&&(r=e.length);n<r;)a(t,e[i=u((n+r)/2)])<0?r=i:n=i+1;return[].splice.apply(e,[n,n-n].concat(t)),t},n=function(e,t,n){return null==n&&(n=h),e.push(t),l(e,0,e.length-1,n)},p=function(e,t){var n,r;return null==t&&(t=h),n=e.pop(),e.length?(r=e[0],e[0]=n,f(e,0,t)):r=n,r},r=function(e,t,n){var r;return null==n&&(n=h),r=e[0],e[0]=t,f(e,0,n),r},c=function(e,t,n){var r;return null==n&&(n=h),e.length&&n(e[0],t)<0&&(t=(r=[e[0],t])[0],e[0]=r[1],f(e,0,n)),t},d=function(n,e){var t,r,a,i,o,s;for(null==e&&(e=h),o=[],r=0,a=(i=function(){s=[];for(var e=0,t=u(n.length/2);0<=t?e<t:t<e;0<=t?e++:e--)s.push(e);return s}.apply(this).reverse()).length;r<a;r++)t=i[r],o.push(f(n,t,e));return o},o=function(e,t,n){var r;if(null==n&&(n=h),-1!==(r=e.indexOf(t)))return l(e,0,r,n),f(e,r,n)},a=function(e,t,n){var r,a,i,o,s;if(null==n&&(n=h),!(a=e.slice(0,t)).length)return a;for(d(a,n),i=0,o=(s=e.slice(t)).length;i<o;i++)r=s[i],c(a,r,n);return a.sort(n).reverse()},i=function(e,t,n){var r,a,i,o,s,u,c,l,f;if(null==n&&(n=h),10*t<=e.length){if(!(i=e.slice(0,t).sort(n)).length)return i;for(a=i[i.length-1],o=0,u=(c=e.slice(t)).length;o<u;o++)n(r=c[o],a)<0&&(m(i,r,0,null,n),i.pop(),a=i[i.length-1]);return i}for(d(e,n),f=[],s=0,l=g(t,e.length);0<=l?s<l:l<s;0<=l?++s:--s)f.push(p(e,n));return f},l=function(e,t,n,r){var a,i,o;for(null==r&&(r=h),a=e[n];t<n&&r(a,i=e[o=n-1>>1])<0;)e[n]=i,n=o;return e[n]=a},f=function(e,t,n){var r,a,i,o,s;for(null==n&&(n=h),a=e.length,i=e[s=t],r=2*t+1;r<a;)(o=r+1)<a&&!(n(e[r],e[o])<0)&&(r=o),e[t]=e[r],r=2*(t=r)+1;return e[t]=i,l(e,s,t,n)},e=function(){function t(e){this.cmp=null!=e?e:h,this.nodes=[]}return t.push=n,t.pop=p,t.replace=r,t.pushpop=c,t.heapify=d,t.updateItem=o,t.nlargest=a,t.nsmallest=i,t.prototype.push=function(e){return n(this.nodes,e,this.cmp)},t.prototype.pop=function(){return p(this.nodes,this.cmp)},t.prototype.peek=function(){return this.nodes[0]},t.prototype.contains=function(e){return-1!==this.nodes.indexOf(e)},t.prototype.replace=function(e){return r(this.nodes,e,this.cmp)},t.prototype.pushpop=function(e){return c(this.nodes,e,this.cmp)},t.prototype.heapify=function(){return d(this.nodes,this.cmp)},t.prototype.updateItem=function(e){return o(this.nodes,e,this.cmp)},t.prototype.clear=function(){return this.nodes=[]},t.prototype.empty=function(){return 0===this.nodes.length},t.prototype.size=function(){return this.nodes.length},t.prototype.clone=function(){var e;return(e=new t).nodes=this.nodes.slice(0),e},t.prototype.toArray=function(){return this.nodes.slice(0)},t.prototype.insert=t.prototype.push,t.prototype.top=t.prototype.peek,t.prototype.front=t.prototype.peek,t.prototype.has=t.prototype.contains,t.prototype.copy=t.prototype.clone,t}(),t.exports=e}).call(this)}),bc=e(function(e,l){(function(){var a,d,i,e,ee,t,p,n,g,v,r,o,s,I,S,f,u,H,q,E,c=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++)if(t in this&&this[t]===e)return t;return-1};p=Math.floor,g=Math.max,v=Math.min,d=_c,f=function(e,t){return t?2*e/t:1},S=function(e,t){var n,r,a,i,o,s;for(o=[e.length,t.length],n=i=0,s=v(r=o[0],a=o[1]);0<=s?i<s:s<i;n=0<=s?++i:--i){if(e[n]<t[n])return-1;if(e[n]>t[n])return 1}return r-a},E=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},I=function(e){var t,n;for(t=0,n=e.length;t<n;t++)if(e[t])return!0;return!1},ee=function(){function e(e,t,n,r){this.isjunk=e,null==t&&(t=\"\"),null==n&&(n=\"\"),this.autojunk=null==r||r,this.a=this.b=null,this.setSeqs(t,n)}return e.prototype.setSeqs=function(e,t){return this.setSeq1(e),this.setSeq2(t)},e.prototype.setSeq1=function(e){if(e!==this.a)return this.a=e,this.matchingBlocks=this.opcodes=null},e.prototype.setSeq2=function(e){if(e!==this.b)return this.b=e,this.matchingBlocks=this.opcodes=null,this.fullbcount=null,this._chainB()},e.prototype._chainB=function(){var e,t,n,r,a,i,o,s,u,c,l,f,h,d;for(e=this.b,this.b2j=t={},r=c=0,f=e.length;c<f;r=++c)n=e[r],(E(t,n)?t[n]:t[n]=[]).push(r);if(i={},a=this.isjunk)for(l=0,h=(d=Object.keys(t)).length;l<h;l++)a(n=d[l])&&(i[n]=!0,delete t[n]);if(u={},o=e.length,this.autojunk&&200<=o)for(n in s=p(o/100)+1,t)t[n].length>s&&(u[n]=!0,delete t[n]);return this.isbjunk=function(e){return E(i,e)},this.isbpopular=function(e){return E(u,e)}},e.prototype.findLongestMatch=function(e,t,n,r){var a,i,o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k;for(a=(_=[this.a,this.b,this.b2j,this.isbjunk])[0],i=_[1],o=_[2],f=_[3],s=(b=[e,n,0])[0],u=b[1],c=b[2],d={},l=g=e;e<=t?g<t:t<g;l=e<=t?++g:--g){for(m={},v=0,y=(w=E(o,a[l])?o[a[l]]:[]).length;v<y;v++)if(!((h=w[v])<n)){if(r<=h)break;c<(p=m[h]=(d[h-1]||0)+1)&&(s=(A=[l-p+1,h-p+1,p])[0],u=A[1],c=A[2])}d=m}for(;e<s&&n<u&&!f(i[u-1])&&a[s-1]===i[u-1];)s=(x=[s-1,u-1,c+1])[0],u=x[1],c=x[2];for(;s+c<t&&u+c<r&&!f(i[u+c])&&a[s+c]===i[u+c];)c++;for(;e<s&&n<u&&f(i[u-1])&&a[s-1]===i[u-1];)s=(k=[s-1,u-1,c+1])[0],u=k[1],c=k[2];for(;s+c<t&&u+c<r&&f(i[u+c])&&a[s+c]===i[u+c];)c++;return[s,u,c]},e.prototype.getMatchingBlocks=function(){var e,t,n,r,a,i,o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k,E;if(this.matchingBlocks)return this.matchingBlocks;for(v=[[0,d=(w=[this.a.length,this.b.length])[0],0,p=w[1]]],m=[];v.length;)t=(A=v.pop())[0],e=A[1],r=A[2],n=A[3],a=(x=y=this.findLongestMatch(t,e,r,n))[0],s=x[1],(l=x[2])&&(m.push(y),t<a&&r<s&&v.push([t,a,r,s]),a+l<e&&s+l<n&&v.push([a+l,e,s+l,n]));for(m.sort(S),i=u=f=0,g=[],_=0,b=m.length;_<b;_++)o=(k=m[_])[0],c=k[1],h=k[2],i+f===o&&u+f===c?f+=h:(f&&g.push([i,u,f]),i=(E=[o,c,h])[0],u=E[1],f=E[2]);return f&&g.push([i,u,f]),g.push([d,p,0]),this.matchingBlocks=g},e.prototype.getOpcodes=function(){var e,t,n,r,a,i,o,s,u,c,l,f;if(this.opcodes)return this.opcodes;for(r=a=0,this.opcodes=t=[],s=0,u=(c=this.getMatchingBlocks()).length;s<u;s++)e=(l=c[s])[0],n=l[1],i=l[2],o=\"\",r<e&&a<n?o=\"replace\":r<e?o=\"delete\":a<n&&(o=\"insert\"),o&&t.push([o,r,e,a,n]),r=(f=[e+i,n+i])[0],a=f[1],i&&t.push([\"equal\",e,r,n,a]);return t},e.prototype.getGroupedOpcodes=function(e){var t,n,r,a,i,o,s,u,c,l,f,h,d,p,m;for(null==e&&(e=3),(t=this.getOpcodes()).length||(t=[[\"equal\",0,1,0,1]]),\"equal\"===t[0][0]&&(c=(h=t[0])[0],a=h[1],i=h[2],o=h[3],s=h[4],t[0]=[c,g(a,i-e),i,g(o,s-e),s]),\"equal\"===t[t.length-1][0]&&(c=(d=t[t.length-1])[0],a=d[1],i=d[2],o=d[3],s=d[4],t[t.length-1]=[c,a,v(i,a+e),o,v(s,o+e)]),u=e+e,r=[],n=[],l=0,f=t.length;l<f;l++)c=(p=t[l])[0],a=p[1],i=p[2],o=p[3],s=p[4],\"equal\"===c&&u<i-a&&(n.push([c,a,v(i,a+e),o,v(s,o+e)]),r.push(n),n=[],a=(m=[g(a,i-e),g(o,s-e)])[0],o=m[1]),n.push([c,a,i,o,s]);return!n.length||1===n.length&&\"equal\"===n[0][0]||r.push(n),r},e.prototype.ratio=function(){var e,t,n,r;for(t=e=0,n=(r=this.getMatchingBlocks()).length;t<n;t++)e+=r[t][2];return f(e,this.a.length+this.b.length)},e.prototype.quickRatio=function(){var e,t,n,r,a,i,o,s,u,c,l;if(!this.fullbcount)for(this.fullbcount=n={},i=0,s=(c=this.b).length;i<s;i++)n[t=c[i]]=(n[t]||0)+1;for(n=this.fullbcount,e={},o=r=0,u=(l=this.a).length;o<u;o++)t=l[o],a=E(e,t)?e[t]:n[t]||0,e[t]=a-1,0<a&&r++;return f(r,this.a.length+this.b.length)},e.prototype.realQuickRatio=function(){var e,t,n;return n=[this.a.length,this.b.length],f(v(e=n[0],t=n[1]),e+t)},e}(),n=function(e,t,n,r){var a,i,o,s,u,c,l,f,h;if(null==n&&(n=3),null==r&&(r=.6),!(0<n))throw new Error(\"n must be > 0: (\"+n+\")\");if(!(0<=r&&r<=1))throw new Error(\"cutoff must be in [0.0, 1.0]: (\"+r+\")\");for(a=[],(i=new ee).setSeq2(e),s=0,c=t.length;s<c;s++)o=t[s],i.setSeq1(o),i.realQuickRatio()>=r&&i.quickRatio()>=r&&i.ratio()>=r&&a.push([i.ratio(),o]);for(h=[],u=0,l=(a=d.nlargest(a,n,S)).length;u<l;u++)(f=a[u])[0],o=f[1],h.push(o);return h},u=function(e,t){var n,r,a;for(n=(a=[0,e.length])[0],r=a[1];n<r&&e[n]===t;)n++;return n},a=function(){function e(e,t){this.linejunk=e,this.charjunk=t}return e.prototype.compare=function(e,t){var n,r,a,i,o,s,u,c,l,f,h,d,p,m;for(u=[],l=0,h=(p=new ee(this.linejunk,e,t).getOpcodes()).length;l<h;l++){switch(c=(m=p[l])[0],r=m[1],n=m[2],i=m[3],a=m[4],c){case\"replace\":o=this._fancyReplace(e,r,n,t,i,a);break;case\"delete\":o=this._dump(\"-\",e,r,n);break;case\"insert\":o=this._dump(\"+\",t,i,a);break;case\"equal\":o=this._dump(\" \",e,r,n);break;default:throw new Error(\"unknow tag (\"+c+\")\")}for(f=0,d=o.length;f<d;f++)s=o[f],u.push(s)}return u},e.prototype._dump=function(e,t,n,r){var a,i,o;for(o=[],a=i=n;n<=r?i<r:r<i;a=n<=r?++i:--i)o.push(e+\" \"+t[a]);return o},e.prototype._plainReplace=function(e,t,n,r,a,i){var o,s,u,c,l,f,h,d,p,m;for(l=i-a<n-t?(o=this._dump(\"+\",r,a,i),this._dump(\"-\",e,t,n)):(o=this._dump(\"-\",e,t,n),this._dump(\"+\",r,a,i)),c=[],f=0,d=(m=[o,l]).length;f<d;f++)for(h=0,p=(s=m[f]).length;h<p;h++)u=s[h],c.push(u);return c},e.prototype._fancyReplace=function(e,t,n,r,a,i){var o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k,E,S,M,T,C,D,O,j,N,z,P,L,R,Y,W,q,I,H,F,B,G,U,$,V,J,K,X,Z,Q;for(h=(I=[.74,.75])[0],_=I[1],y=new ee(this.charjunk),b=(H=[null,null])[0],w=H[1],M=[],x=C=a;a<=i?C<i:i<C;x=a<=i?++C:--C)for(m=r[x],y.setSeq2(m),A=D=t;t<=n?D<n:n<D;A=t<=n?++D:--D)(s=e[A])!==m?(y.setSeq1(s),y.realQuickRatio()>h&&y.quickRatio()>h&&y.ratio()>h&&(h=($=[y.ratio(),A,x])[0],d=$[1],p=$[2])):null===b&&(b=(U=[A,x])[0],w=U[1]);if(h<_){if(null===b){for(O=0,N=(V=this._plainReplace(e,t,n,r,a,i)).length;O<N;O++)S=V[O],M.push(S);return M}d=(J=[b,w,1])[0],p=J[1],h=J[2]}else b=null;for(j=0,z=(K=this._fancyHelper(e,t,d,r,a,p)).length;j<z;j++)S=K[j],M.push(S);if(o=(X=[e[d],r[p]])[0],f=X[1],null===b){for(l=v=\"\",y.setSeqs(o,f),Y=0,P=(Z=y.getOpcodes()).length;Y<P;Y++)switch(T=(Q=Z[Y])[0],u=Q[1],c=Q[2],g=Q[3],k=(F=[c-u,Q[4]-g])[0],E=F[1],T){case\"replace\":l+=Array(k+1).join(\"^\"),v+=Array(E+1).join(\"^\");break;case\"delete\":l+=Array(k+1).join(\"-\");break;case\"insert\":v+=Array(E+1).join(\"+\");break;case\"equal\":l+=Array(k+1).join(\" \"),v+=Array(E+1).join(\" \");break;default:throw new Error(\"unknow tag (\"+T+\")\")}for(W=0,L=(B=this._qformat(o,f,l,v)).length;W<L;W++)S=B[W],M.push(S)}else M.push(\"  \"+o);for(q=0,R=(G=this._fancyHelper(e,d+1,n,r,p+1,i)).length;q<R;q++)S=G[q],M.push(S);return M},e.prototype._fancyHelper=function(e,t,n,r,a,i){var o;return o=[],t<n?o=a<i?this._fancyReplace(e,t,n,r,a,i):this._dump(\"-\",e,t,n):a<i&&(o=this._dump(\"+\",r,a,i)),o},e.prototype._qformat=function(e,t,n,r){var a,i;return i=[],a=v(u(e,\"\\t\"),u(t,\"\\t\")),a=v(a,u(n.slice(0,a),\" \")),a=v(a,u(r.slice(0,a),\" \")),n=n.slice(a).replace(/\\s+$/,\"\"),r=r.slice(a).replace(/\\s+$/,\"\"),i.push(\"- \"+e),n.length&&i.push(\"? \"+Array(a+1).join(\"\\t\")+n+\"\\n\"),i.push(\"+ \"+t),r.length&&i.push(\"? \"+Array(a+1).join(\"\\t\")+r+\"\\n\"),i},e}(),e=function(e,t){return null==t&&(t=/^\\s*#?\\s*$/),t.test(e)},i=function(e,t){return null==t&&(t=\" \\t\"),0<=c.call(t,e)},q=function(e,t){var n,r;return n=e+1,1===(r=t-e)?\"\"+n:(r||n--,n+\",\"+r)},s=function(e,t,n){var r,a,i,o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k,E,S,M,T,C,D,O,j,N,z,P,L,R,Y,W;for(null==(s=(N=null!=n?n:{}).fromfile)&&(s=\"\"),null==(w=N.tofile)&&(w=\"\"),null==(u=N.fromfiledate)&&(u=\"\"),null==(A=N.tofiledate)&&(A=\"\"),null==N.n&&3,null==(v=N.lineterm)&&(v=\"\\n\"),y=!(g=[]),x=0,M=(z=new ee(null,e,t).getGroupedOpcodes()).length;x<M;x++)for(c=z[x],y||(y=!0,o=u?\"\\t\"+u:\"\",b=A?\"\\t\"+A:\"\",g.push(\"--- \"+s+o+v),g.push(\"+++ \"+w+b+v)),p=(P=[c[0],c[c.length-1]])[1],r=q((i=P[0])[1],p[2]),a=q(i[3],p[4]),g.push(\"@@ -\"+r+\" +\"+a+\" @@\"+v),k=0,T=c.length;k<T;k++)if(_=(L=c[k])[0],l=L[1],f=L[2],h=L[3],d=L[4],\"equal\"!==_){if(\"replace\"===_||\"delete\"===_)for(S=0,D=(Y=e.slice(l,f)).length;S<D;S++)m=Y[S],g.push(\"-\"+m);if(\"replace\"===_||\"insert\"===_)for(j=0,O=(W=t.slice(h,d)).length;j<O;j++)m=W[j],g.push(\"+\"+m)}else for(E=0,C=(R=e.slice(l,f)).length;E<C;E++)m=R[E],g.push(\" \"+m);return g},H=function(e,t){var n,r;return n=e+1,(r=t-e)||n--,r<=1?\"\"+n:n+\",\"+(n+r-1)},t=function(e,t,n){var r,a,i,o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k,E,S,M,T,C,D,O,j,N,z,P,L,R,Y,W,q;for(null==(s=(z=null!=n?n:{}).fromfile)&&(s=\"\"),null==(A=z.tofile)&&(A=\"\"),null==(u=z.fromfiledate)&&(u=\"\"),null==(x=z.tofiledate)&&(x=\"\"),null==z.n&&3,null==(v=z.lineterm)&&(v=\"\\n\"),_=!(y={insert:\"+ \",delete:\"- \",replace:\"! \",equal:\"  \"}),g=[],k=0,T=(P=new ee(null,e,t).getGroupedOpcodes()).length;k<T;k++)if(c=P[k],!_){if(_=!0,o=u?\"\\t\"+u:\"\",w=x?\"\\t\"+x:\"\",g.push(\"*** \"+s+o+v),g.push(\"--- \"+A+w+v),i=(L=[c[0],c[c.length-1]])[0],p=L[1],g.push(\"***************\"+v),r=H(i[1],p[2]),g.push(\"*** \"+r+\" ****\"+v),I(function(){var e,t,n,r;for(r=[],e=0,t=c.length;e<t;e++)n=c[e],b=n[0],n[1],n[2],n[3],n[4],r.push(\"replace\"===b||\"delete\"===b);return r}()))for(E=0,C=c.length;E<C;E++)if(R=c[E],b=R[0],l=R[1],f=R[2],R[3],R[4],\"insert\"!==b)for(S=0,D=(Y=e.slice(l,f)).length;S<D;S++)m=Y[S],g.push(y[b]+m);if(a=H(i[3],p[4]),g.push(\"--- \"+a+\" ----\"+v),I(function(){var e,t,n,r;for(r=[],e=0,t=c.length;e<t;e++)n=c[e],b=n[0],n[1],n[2],n[3],n[4],r.push(\"replace\"===b||\"insert\"===b);return r}()))for(M=0,O=c.length;M<O;M++)if(W=c[M],b=W[0],W[1],W[2],h=W[3],d=W[4],\"delete\"!==b)for(N=0,j=(q=t.slice(h,d)).length;N<j;N++)m=q[N],g.push(y[b]+m)}return g},r=function(e,t,n,r){return null==r&&(r=i),new a(n,r).compare(e,t)},o=function(e,t){var n,r,a,i,o,s,u;if(!(i={1:\"- \",2:\"+ \"}[t]))throw new Error(\"unknow delta choice (must be 1 or 2): \"+t);for(a=[\"  \",i],r=[],o=0,s=e.length;o<s;o++)u=(n=e[o]).slice(0,2),0<=c.call(a,u)&&r.push(n.slice(2));return r},l._arrayCmp=S,l.SequenceMatcher=ee,l.getCloseMatches=n,l._countLeading=u,l.Differ=a,l.IS_LINE_JUNK=e,l.IS_CHARACTER_JUNK=i,l._formatRangeUnified=q,l.unifiedDiff=s,l._formatRangeContext=H,l.contextDiff=t,l.ndiff=r,l.restore=o}).call(this)}),wc=(bc._arrayCmp,bc.SequenceMatcher,bc.getCloseMatches,bc._countLeading,bc.Differ,bc.IS_LINE_JUNK,bc.IS_CHARACTER_JUNK,bc._formatRangeUnified,bc.unifiedDiff,bc._formatRangeContext,bc.contextDiff,bc.ndiff,bc.restore,bc);var Ac=/\\d/,xc=new RegExp([\"print\",\"archive\",\"comment\",\"discuss\",\"e-mail\",\"email\",\"share\",\"reply\",\"all\",\"login\",\"sign\",\"single\",\"adx\",\"entry-unrelated\"].join(\"|\"),\"i\"),kc=new RegExp(\"(next|weiter|continue|>([^|]|$)|»([^|]|$))\",\"i\"),Ec=new RegExp(\"(first|last|end)\",\"i\"),Sc=new RegExp(\"(prev|earl|old|new|<|«)\",\"i\");function Mc(e){var t=e.links,k=e.articleUrl,E=e.baseUrl,S=e.parsedUrl,M=e.$,n=e.previousUrls,T=void 0===n?[]:n;S=S||Mr.parse(k);var C=new RegExp(\"^\".concat(E),\"i\"),D=0<M(yi).length,r=t.reduce(function(e,t){var n=ns(t);if(!n.href)return e;var r=Sa(n.href),a=M(t),i=a.text();if(!function(t,e,n,r,a,i){if(void 0!==i.find(function(e){return t===e}))return!1;if(!t||t===e||t===n)return!1;var o=r.hostname;if(Mr.parse(t).hostname!==o)return!1;var s=t.replace(n,\"\");return!(!Ac.test(s)||xc.test(a)||25<a.length)}(r,k,E,S,i,T))return e;e[r]?e[r].linkText=\"\".concat(e[r].linkText,\"|\").concat(i):e[r]={score:0,linkText:i,href:r};var o,s,u,c,l,f,h,d,p,m,g,v,y,_,b=e[r],w=(o=a,\"\".concat(i||o.text(),\" \").concat(o.attr(\"class\")||\"\",\" \").concat(o.attr(\"id\")||\"\")),A=function(e){var t=e.match(wa);if(!t)return null;var n=ba(t[6],10);return n<100?n:null}(r),x=(s=r,C.test(s)?0:-25);return x+=(u=w,kc.test(u)?50:0),x+=(c=w,Ec.test(c)&&kc.test(c)?-65:0),x+=(l=w,Sc.test(l)?-200:0),x+=(f=a.parent(),d=h=!1,Oi(ps(p=0,4)).forEach(function(){if(0!==f.length){var e,t=\"\".concat((e=f).attr(\"class\")||\"\",\" \").concat(e.attr(\"id\")||\"\");!h&&_i.test(t)&&(h=!0,p+=25),!d&&vi.test(t)&&xc.test(t)&&(gi.test(t)||(d=!0,p-=25)),f=f.parent()}}),p),x+=(m=r,xc.test(m)?-25:0),x+=(g=D,A&&!g?50:0),x+=function(e,t){var n=0;if(ka.test(e.trim())){var r=ba(e,10);n=r<2?-30:Math.max(0,10-r),t&&r<=t&&(n-=50)}return n}(i,A),x+=(y=k,_=r,0<(v=x)?v+-250*(1-new wc.SequenceMatcher(null,y,_).ratio()-.2):0),b.score=x,e},{});return 0===si(r).length?null:r}var Tc={extract:function(e){var t=e.$,n=e.url,r=e.parsedUrl,a=e.previousUrls,i=void 0===a?[]:a;r=r||Mr.parse(n);var o=Sa(n),s=Na(n,r),u=Mc({links:t(\"a[href]\").toArray(),articleUrl:o,baseUrl:s,parsedUrl:r,$:t,previousUrls:i});if(!u)return null;var c=si(u).reduce(function(e,t){var n=u[t];return n.score>e.score?n:e},{score:-100});return 50<=c.score?c.href:null}},Cc=[\"og:url\"];function Dc(e){return{url:e,domain:(t=e,Mr.parse(t).hostname)};var t}var Oc={extract:function(e){var t=e.$,n=e.url,r=e.metaCache,a=t(\"link[rel=canonical]\");if(0!==a.length){var i=a.attr(\"href\");if(i)return Dc(i)}var o=Xo(t,Cc,r);return Dc(o||n)}},jc={ellipse:\"…\",chars:[\" \",\"-\"],max:140,truncate:!0};var Nc=function(e,t,n){if(\"string\"!=typeof e||0===e.length)return\"\";if(0===t)return\"\";for(var r in n=n||{},jc)null!==n[r]&&void 0!==n[r]||(n[r]=jc[r]);return n.max=t||n.max,function(e,t,n,r,a){if(e.length<t)return e;for(var i=0,o=\"\",s=Math.floor(t/2),u=\"middle\"===a?s:t,c=0,l=e.length;c<l;c++)if(o=e.charAt(c),-1!==r.indexOf(o)&&\"middle\"!==a&&(i=c),!(c<u))return 0===i?a?e.substring(0,u-1)+n+(\"middle\"===a?e.substring(e.length-s,e.length):\"\"):\"\":e.substring(0,i)+n;return e}(e,n.max,n.ellipse,n.chars,n.truncate)},zc=[\"og:description\",\"twitter:description\"];function Pc(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:200;return e=e.replace(/[\\s\\n]+/g,\" \").trim(),Nc(e,n,{ellipse:\"&hellip;\"})}var Lc={extract:function(e){var t=e.$,n=e.content,r=e.metaCache,a=Xo(t,zc,r);if(a)return Pc(es(a,t));return Pc(t(n.slice(0,1e3)).text(),t,200)}},Rc={extract:function(e){var t=e.content;return ua(Cr.load(t)(\"div\").first().text()).split(/\\s/).length}},Yc={domain:\"*\",title:tc.extract,date_published:lc.extract,author:oc.extract,content:Ku.extract.bind(Ku),lead_image_url:yc.extract,dek:function(){return null},next_page_url:Tc.extract,url_and_domain:Oc.extract,excerpt:Lc.extract,word_count:Rc.extract,direction:function(e){var t=e.title;return Os.getDirection(t)},extract:function(e){var t=e.html,n=e.$;if(t&&!n){var r=Cr.load(t);e.$=r}var a=this.title(e),i=this.date_published(e),o=this.author(e),s=this.content(pt({},e,{title:a})),u=this.lead_image_url(pt({},e,{content:s})),c=this.dek(pt({},e,{content:s})),l=this.next_page_url(e),f=this.excerpt(pt({},e,{content:s})),h=this.word_count(pt({},e,{content:s})),d=this.direction({title:a}),p=this.url_and_domain(e);return{title:a,author:o,date_published:i||null,dek:c,lead_image_url:u,content:s,next_page_url:l,url:p.url,domain:p.domain,excerpt:f,word_count:h,direction:d}}},Wc={'meta[name=\"al:ios:app_name\"][value=\"Medium\"]':Es,'meta[name=\"generator\"][value=\"blogger\"]':As};function qc(e,t,n){var r,a,i=(t=t||Mr.parse(e)).hostname,o=i.split(\".\").slice(-2).join(\".\");return bs[i]||bs[o]||Ds[i]||Ds[o]||(r=n,a=si(Wc).find(function(e){return 0<r(e).length}),Wc[a])||Yc}function Ic(s){var u=s.$,t=s.type,c=s.extractionOpts,e=s.extractHtml,n=void 0!==e&&e;if(!c)return null;if(\"string\"==typeof c)return c;var a,i,o,r,l=c.selectors,f=c.defaultCleaner,h=void 0===f||f,d=c.allowMultiple,p=(a=u,i=n,o=d,l.find(function(e){if(Ma(e)){if(i)return e.reduce(function(e,t){return e&&0<a(t).length},!0);var t=ja(e,2),n=t[0],r=t[1];return(o||!o&&1===a(n).length)&&a(n).attr(r)&&\"\"!==a(n).attr(r).trim()}return(o||!o&&1===a(e).length)&&\"\"!==a(e).text().trim()}));if(!p)return null;function m(e){var t,n,r,a,i,o;return Go(e,u,s.url||\"\"),t=e,n=u,(r=c.clean)&&n(r.join(\",\"),t).remove(),a=e,i=u,(o=c.transforms)&&si(o).forEach(function(n){var e=i(n,a),r=o[n];\"string\"==typeof r?e.each(function(e,t){Mi(i(t),i,o[n])}):\"function\"==typeof r&&e.each(function(e,t){var n=r(i(t),i);\"string\"==typeof n&&Mi(i(t),i,n)})}),e}if(n)return function(){var e;if(Ma(p)){e=u(p.join(\",\"));var n=u(\"<div></div>\");e.each(function(e,t){n.append(t)}),e=n}else e=u(p);return e.wrap(u(\"<div></div>\")),e=m(e=e.parent()),Vu[t]&&Vu[t](e,pt({},s,{defaultCleaner:h})),d?e.children().toArray().map(function(e){return u.html(u(e))}):u.html(e)}();if(Ma(p)){var g=ja(p,3),v=g[0],y=g[1],_=g[2];r=m(u(v)).map(function(e,t){var n=u(t).attr(y).trim();return _?_(n):n})}else r=m(u(p)).map(function(e,t){return u(t).text().trim()});return r=Ma(r.toArray())&&d?r.toArray():r[0],h&&Vu[t]?Vu[t](r,pt({},s,c)):r}function Hc(t,n){var r={};return si(t).forEach(function(e){r[e]||(r[e]=Ic(pt({},n,{type:e,extractionOpts:t[e]})))}),r}function Fc(e){var t=e.type,n=e.extractor,r=e.fallback,a=void 0===r||r,i=Ic(pt({},e,{extractionOpts:n[t]}));return i||(a?Yc[t](e):null)}var Bc,Gc={extract:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:Yc,t=1<arguments.length?arguments[1]:void 0,n=t,r=n.contentOnly,a=n.extractedTitle;if(\"*\"===e.domain)return e.extract(t);if(t=pt({},t,{extractor:e}),r)return{content:Fc(pt({},t,{type:\"content\",extractHtml:!0,title:a}))};var i=Fc(pt({},t,{type:\"title\"})),o=Fc(pt({},t,{type:\"date_published\"})),s=Fc(pt({},t,{type:\"author\"})),u=Fc(pt({},t,{type:\"next_page_url\"})),c=Fc(pt({},t,{type:\"content\",extractHtml:!0,title:i})),l=Fc(pt({},t,{type:\"lead_image_url\",content:c})),f=Fc(pt({},t,{type:\"excerpt\",content:c})),h=Fc(pt({},t,{type:\"dek\",content:c,excerpt:f})),d=Fc(pt({},t,{type:\"word_count\",content:c})),p=Fc(pt({},t,{type:\"direction\",title:i})),m=Fc(pt({},t,{type:\"url_and_domain\"}))||{url:null,domain:null},g=m.url,v=m.domain,y={};return e.extend&&(y=Hc(e.extend,t)),pt({title:i,content:c,author:s,date_published:o,lead_image_url:l,dek:h,next_page_url:u,url:g,domain:v,excerpt:f,word_count:d,direction:p},y)}};function Uc(e){return $c.apply(this,arguments)}function $c(){return($c=Qn(S.mark(function e(t){var n,r,a,i,o,s,u,c,l,f,h,d,p;return S.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:n=t.next_page_url,r=t.html,a=t.$,i=t.metaCache,o=t.result,s=t.Extractor,u=t.title,c=t.url,l=1,f=[Sa(c)];case 3:if(n&&l<26)return l+=1,e.next=7,hs.create(n);e.next=16;break;case 7:a=e.sent,r=a.html(),h={url:n,html:r,$:a,metaCache:i,contentOnly:!0,extractedTitle:u,previousUrls:f},d=Gc.extract(s,h),f.push(n),o=pt({},o,{content:\"\".concat(o.content,\"<hr><h4>Page \").concat(l,\"</h4>\").concat(d.content)}),n=d.next_page_url,e.next=3;break;case 16:return p=Yc.word_count({content:\"<div>\".concat(o.content,\"</div>\")}),e.abrupt(\"return\",pt({},o,{total_pages:l,pages_rendered:l,word_count:p}));case 18:case\"end\":return e.stop()}},e,this)}))).apply(this,arguments)}return{parse:(Bc=Qn(S.mark(function e(t){var n,r,a,i,o,s,u,c,l,f,h,d,p,m,g,v,y,_,b,w,A,x,k,E=arguments;return S.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(n=1<E.length&&void 0!==E[1]?E[1]:{},r=n.html,a=gt(n,[\"html\"]),i=a.fetchAllPages,o=void 0===i||i,s=a.fallback,u=void 0===s||s,c=a.contentType,l=void 0===c?\"html\":c,f=a.headers,h=void 0===f?{}:f,d=a.extend,p=a.customExtractor,!t&&Cr.browser&&(t=window.location.href,r=r||Cr.html()),m=Mr.parse(t),m.hostname){e.next=6;break}return e.abrupt(\"return\",{error:!0,message:\"The url parameter passed does not look like a valid URL. Please check your URL and try again.\"});case 6:return e.next=8,hs.create(t,r,m,h);case 8:if((g=e.sent).failed)return e.abrupt(\"return\",g);e.next=11;break;case 11:if(p&&ws(p),v=qc(t,m,g),r||(r=g.html()),y=g(\"meta\").map(function(e,t){return g(t).attr(\"name\")}).toArray(),_={},d&&(_=Hc(d,{$:g,url:t,html:r})),b=Gc.extract(v,{url:t,html:r,$:g,metaCache:y,parsedUrl:m,fallback:u,contentType:l}),A=(w=b).title,x=w.next_page_url,o&&x)return e.next=22,Uc({Extractor:v,next_page_url:x,html:r,$:g,metaCache:y,result:b,title:A,url:t});e.next=25;break;case 22:b=e.sent,e.next=26;break;case 25:b=pt({},b,{total_pages:1,rendered_pages:1});case 26:return\"markdown\"===l?(k=new na,b.content=k.turndown(b.content)):\"text\"===l&&(b.content=g.text(g(b.content))),e.abrupt(\"return\",pt({},b,_));case 28:case\"end\":return e.stop()}},e,this)})),function(e){return Bc.apply(this,arguments)}),browser:!!Cr.browser,fetchResource:function(e){return hs.create(e)},addExtractor:function(e){return ws(e)}}}();\n"
  },
  {
    "path": "dist/fonts.vbs",
    "content": "Option Explicit\n\nDim objShell, objFSO, objFile, objFolder\nDim objFolderItem, colItems, objFont\nDim strFileName\n\n\nConst FONTS = &H14& ' Fonts Folder\n\n' Instantiate Objects\nSet objShell = CreateObject(\"Shell.Application\")\nSet objFolder = objShell.Namespace(FONTS)\nSet objFolderItem = objFolder.Self\nSet colItems = objFolder.Items\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\n\nFor Each objFont in colItems\n    WScript.StdOut.WriteLine(objFont.Path & vbtab & objFont.Name)\nNext\n\nSet objShell = nothing\nSet objFile = nothing\nSet objFolder = nothing\nSet objFolderItem = nothing\nSet colItems = nothing\nSet objFont = nothing\nSet objFSO = nothing\n\nwscript.quit\n"
  },
  {
    "path": "dist/index.css",
    "content": "@import \"styles/scroll.css\";\n@import \"styles/global.css\";\n@import \"styles/main.css\";\n@import \"styles/feeds.css\";\n@import \"styles/cards.css\";\n@import \"styles/dark.css\";\n"
  },
  {
    "path": "dist/styles/cards.css",
    "content": ".info {\n    display: flex;\n    position: relative;\n    margin: 10px 12px;\n    line-height: 16px;\n}\n.info img {\n    width: 16px;\n    height: 16px;\n    margin-right: 5px;\n}\n.info span.name {\n    font-size: 12px;\n    vertical-align: top;\n    display: inline-block;\n    flex-grow: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n}\n.info span.creator {\n    color: var(--neutralSecondaryAlt);\n}\n.info span.creator::before {\n    display: inline-block;\n    content: \"/\";\n    margin: 0 5px;\n}\n.info span.time {\n    font-size: 12px;\n}\n\n.read-indicator,\n.starred-indicator {\n    display: block;\n    width: 16px;\n    height: 16px;\n    text-align: center;\n}\n.read-indicator::after {\n    content: \"\";\n    vertical-align: top;\n    display: inline-block;\n    width: 6px;\n    height: 6px;\n    margin: 5px;\n    border-radius: 3px;\n    background-color: #ffaa44;\n    font-size: 10px;\n    box-sizing: border-box;\n}\n.starred-indicator::after {\n    content: \"★\";\n    vertical-align: top;\n    color: #ffaa44;\n    font-size: 11px;\n    line-height: 16px;\n}\n\n.card {\n    position: relative;\n    color: var(--neutralDarker);\n    user-select: none;\n    transform: scale(1);\n    cursor: pointer;\n    overflow: hidden;\n}\n.card:focus {\n    outline: none;\n}\n.ms-Fabric--isFocusVisible .card:focus::after {\n    content: \"\";\n    position: absolute;\n    top: 2px;\n    left: 2px;\n    width: calc(100% - 6px);\n    height: calc(100% - 6px);\n    border: 1px solid var(--white);\n    outline: 2px solid var(--primary);\n}\n.card.hidden::after {\n    content: \"\";\n    display: block;\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n    background: #0003;\n}\n.card span.h {\n    background: #fce10080;\n}\n.card.rtl .snippet,\n.card.rtl .title {\n    direction: rtl;\n}\n\n.default-card {\n    display: inline-block;\n    width: 256px;\n    height: 264px;\n    border-radius: 4px;\n    background-color: var(--white);\n    box-shadow: #0004 0 5px 20px;\n    margin: 18px 12px;\n    transition: box-shadow linear 0.08s, transform linear 0.08s;\n    animation-fill-mode: none;\n}\n.default-card:hover,\n.ms-Fabric--isFocusVisible .default-card:focus {\n    box-shadow: #0006 0 5px 40px;\n}\n.default-card:active {\n    transform: scale(0.97);\n    box-shadow: #0004 0 5px 20px;\n}\n\n.default-card .bg {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n}\n.default-card img.bg {\n    object-fit: cover;\n    filter: var(--blur);\n}\n.default-card div.bg {\n    background-color: #fffb;\n}\n.default-card img.head {\n    display: block;\n    object-fit: cover;\n    position: relative;\n    width: 100%;\n    height: 144px;\n    -webkit-user-drag: none;\n}\n.default-card img.head,\n.default-card p,\n.default-card h3 {\n    transition: transform ease-out 0.12s;\n}\n.default-card.transform:hover img.head,\n.default-card.transform:hover p,\n.default-card.transform:hover h3,\n.ms-Fabric--isFocusVisible .default-card.transform:focus img.head,\n.ms-Fabric--isFocusVisible .default-card.transform:focus p,\n.ms-Fabric--isFocusVisible .default-card.transform:focus h3 {\n    transform: translateY(-144px);\n}\n.default-card h3.title {\n    font-size: 16px;\n    line-height: 22px;\n    font-weight: 600;\n    margin: 10px 12px;\n    position: relative;\n    -webkit-line-clamp: 3;\n    overflow: hidden;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n}\n.default-card p.snippet {\n    font-size: 14px;\n    line-height: 20px;\n    margin: 10px 12px;\n    display: -webkit-box;\n    position: relative;\n    -webkit-line-clamp: 7;\n    -webkit-box-orient: vertical;\n    overflow: hidden;\n    transform: translateY(64px);\n}\n.default-card:hover p.snippet {\n    transform: translateY(-144px);\n}\n.default-card p.snippet.show {\n    transform: none;\n}\n\n.list-card {\n    display: flex;\n    transition: box-shadow linear 0.08s;\n    border-bottom: 1px solid var(--neutralQuaternaryAlt);\n    box-shadow: #0000 0 5px 15px;\n}\n.list-card:hover,\n.ms-Fabric--isFocusVisible .list-card:focus {\n    box-shadow: #0004 0 5px 15px;\n}\n.list-card:active {\n    box-shadow: #0000 0 5px 15px, inset #0004 0 0 15px;\n}\n.list-card div.head {\n    width: 80px;\n    height: 80px;\n    margin: 8px 0 8px 10px;\n}\n.list-card div.head img {\n    width: 80px;\n    height: 80px;\n    object-fit: cover;\n    -webkit-user-drag: none;\n}\n.list-card .data {\n    flex-grow: 1;\n    margin: 8px 10px;\n    overflow: hidden;\n}\n.list-card .info {\n    margin: 0 0 8px;\n    height: 16px;\n}\n.list-card h3.title {\n    font-size: 14px;\n    line-height: 18px;\n    font-weight: 600;\n    margin: 0;\n    position: relative;\n    -webkit-line-clamp: 3;\n    overflow: hidden;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n}\n.list-card p.snippet {\n    color: var(--neutralSecondary);\n    font-size: 12px;\n    line-height: 16px;\n    margin: 4px 0 0;\n    -webkit-line-clamp: 2;\n    overflow: hidden;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n}\n.list-card.selected::before {\n    content: \"\";\n    display: block;\n    position: absolute;\n    height: 100%;\n    border-left: 2px solid var(--primary);\n}\n.list-card.read,\n.list-card.read p.snippet {\n    color: var(--neutralSecondaryAlt);\n}\n\n.magazine-card {\n    width: 700px;\n    padding: 24px;\n    max-height: 160px;\n    display: flex;\n    transition: box-shadow linear 0.08s, background-color linear 0.08s,\n        transform linear 0.08s;\n    border-bottom: 1px solid var(--neutralQuaternaryAlt);\n    box-shadow: #0000 0 5px 20px;\n}\n.magazine-card.read {\n    color: var(--neutralSecondaryAlt);\n}\n.magazine-card:hover,\n.ms-Fabric--isFocusVisible .magazine-card:focus {\n    box-shadow: #0004 0 5px 20px;\n    background-color: var(--white);\n}\n.magazine-card:active {\n    box-shadow: #0000 0 5px 20px;\n    transform: scale(0.97);\n    background-color: unset;\n}\n.magazine-card div.head {\n    width: 200px;\n    height: 160px;\n    margin-right: 25px;\n}\n.magazine-card div.head img {\n    width: 200px;\n    height: 160px;\n    object-fit: cover;\n    -webkit-user-drag: none;\n}\n.magazine-card .data {\n    display: flex;\n    flex-grow: 1;\n    flex-direction: column;\n    justify-content: space-between;\n}\n.magazine-card .data > *:first-child {\n    flex-grow: 1;\n}\n.magazine-card .info {\n    height: 16px;\n    margin: 0;\n}\n.magazine-card h3.title,\n.magazine-card p.snippet {\n    overflow: hidden;\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    margin: 0 0 12px;\n}\n.magazine-card h3.title {\n    font-size: 18px;\n    line-height: 27px;\n    font-weight: 600;\n    -webkit-line-clamp: 2;\n}\n.magazine-card p.snippet {\n    font-size: 14px;\n    line-height: 21px;\n    -webkit-line-clamp: 3;\n}\n\n.compact-card {\n    height: 31px;\n    display: flex;\n    border-bottom: 1px solid var(--neutralQuaternaryAlt);\n    font-size: 14px;\n    line-height: 31px;\n    padding: 0 9px;\n    transition: box-shadow linear 0.08s, background-color linear 0.08s;\n}\n.compact-card:hover,\n.ms-Fabric--isFocusVisible .compact-card:focus {\n    box-shadow: #0004 0 0 10px;\n    background-color: var(--white);\n}\n.compact-card:active {\n    box-shadow: #0000 0 0 10px;\n}\n.compact-card > * {\n    margin: 0 3px;\n    flex-shrink: 0;\n}\n.compact-card .info {\n    display: flex;\n    line-height: 31px;\n    width: 140px;\n}\n.compact-card .info .name {\n    flex-grow: 1;\n}\n.compact-card .info img,\n.compact-card .info .read-indicator,\n.compact-card .info .starred-indicator {\n    margin: 7.5px 5px 7.5px 0;\n}\n.compact-card .data {\n    flex-grow: 1;\n    flex-shrink: 1;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n}\n.compact-card .data .title {\n    font-weight: 600;\n    margin-right: 6px;\n}\n.compact-card .data .snippet {\n    color: var(--neutralSecondaryAlt);\n}\n.compact-card .time {\n    font-size: 12px;\n}\n"
  },
  {
    "path": "dist/styles/dark.css",
    "content": "@media (prefers-color-scheme: dark) {\n    .ms-Button--commandBar.active .ms-Button-icon {\n        color: #c7e0f4;\n    }\n    .btn-group .btn:hover,\n    .ms-Nav-compositeLink:hover {\n        background-color: #fff1;\n    }\n    .btn-group .btn:active,\n    .ms-Nav-compositeLink:active {\n        background-color: #fff2;\n    }\n    .settings .loading {\n        background-color: #000a;\n    }\n    .default-card {\n        box-shadow: #0006 0px 5px 20px;\n    }\n    .default-card:hover,\n    .ms-Fabric--isFocusVisible .default-card:focus {\n        box-shadow: #0008 0px 5px 40px;\n    }\n    .default-card div.bg {\n        background-color: #000b;\n    }\n    .list-card:hover,\n    .ms-Fabric--isFocusVisible .list-card:focus {\n        box-shadow: #0006 0px 5px 15px;\n    }\n    .list-card:active {\n        box-shadow: #0000 0px 5px 15px, inset #0006 0px 0px 15px;\n    }\n    .magazine-card:hover,\n    .ms-Fabric--isFocusVisible .magazine-card:focus {\n        box-shadow: #0006 0px 5px 20px;\n    }\n    .magazine-card:active {\n        box-shadow: #0000 0px 5px 20px;\n    }\n    .compact-card:hover,\n    .ms-Fabric--isFocusVisible .compact-card:focus {\n        box-shadow: #0008 0 0 10px;\n    }\n    .compact-card:active {\n        box-shadow: #0000 0 0 10px;\n    }\n}\n"
  },
  {
    "path": "dist/styles/feeds.css",
    "content": "@keyframes slideUp20 {\n    0% {\n        transform: translateY(20px);\n    }\n    100% {\n        transform: translateY(0);\n    }\n}\n.article-wrapper {\n    margin: 32px auto 0;\n    width: 860px;\n    height: calc(100% - 50px);\n    background-color: var(--white);\n    box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132),\n        0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108);\n    border-radius: 5px;\n    overflow: hidden;\n    animation-name: slideUp20;\n}\n.article-container .btn-group .btn {\n    color: #fff;\n}\n.article-container .btn-group {\n    position: absolute;\n    top: calc(50% - 32px);\n}\n.article-container .btn-group.prev {\n    left: calc(50% - 486px);\n}\n.article-container .btn-group.next {\n    right: calc(50% - 486px);\n}\n.article {\n    height: 100%;\n    user-select: none;\n}\n.article webview,\n.article .error-prompt {\n    width: 100%;\n    height: calc(100% - 36px);\n    border: none;\n    color: var(--black);\n}\n.article webview.error {\n    display: none;\n}\n.article i.ms-Icon {\n    color: var(--neutralDarker);\n}\n.article .actions {\n    color: var(--black);\n    border-bottom: 1px solid var(--neutralQuaternaryAlt);\n}\n.article .actions .favicon,\n.article .actions .ms-Spinner {\n    margin: 8px 8px 11px 0;\n}\n.article .actions .ms-Spinner {\n    display: inline-block;\n    vertical-align: middle;\n}\n.article .actions .source-name {\n    line-height: 35px;\n    user-select: none;\n    max-width: 320px;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    display: inline-block;\n}\n.article .actions .creator {\n    color: var(--neutralSecondaryAlt);\n    user-select: text;\n}\n.article .actions .creator::before {\n    display: inline-block;\n    content: \"/\";\n    margin: 0 6px;\n}\n.side-article-wrapper,\n.side-logo-wrapper {\n    flex-grow: 1;\n    padding-top: var(--navHeight);\n    height: calc(100% - var(--navHeight));\n    background: var(--white);\n}\n.side-logo-wrapper {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n}\n.side-logo-wrapper > img {\n    width: 120px;\n    height: 120px;\n    user-select: none;\n    -webkit-user-drag: none;\n}\n.side-logo-wrapper > img.dark {\n    display: none;\n}\n@media (prefers-color-scheme: dark) {\n    .side-logo-wrapper > img.light {\n        display: none;\n    }\n    .side-logo-wrapper > img.dark {\n        display: inline;\n    }\n}\n.side-article-wrapper .article {\n    display: flex;\n    flex-direction: column-reverse;\n}\n.side-article-wrapper .article .actions {\n    border-bottom: none;\n}\n.side-article-wrapper .article > .ms-Stack {\n    border-top: 1px solid var(--neutralQuaternaryAlt);\n}\n.list-feed-container:first-child::before,\n.side-article-wrapper::before {\n    content: \"\";\n    display: block;\n    width: 100%;\n    border-bottom: 1px solid var(--neutralQuaternaryAlt);\n    position: absolute;\n    top: calc(var(--navHeight) - 1px);\n}\n\n.list-main {\n    display: flex;\n    flex-wrap: wrap;\n    height: 100%;\n    position: relative;\n    margin-top: calc(-1 * var(--navHeight));\n    overflow: hidden;\n    background: var(--white);\n}\n.list-feed-container {\n    width: 350px;\n    background-color: var(--neutralLighterAlt);\n    height: 100%;\n    position: relative;\n}\n.list-feed-container::after {\n    content: \"\";\n    display: block;\n    pointer-events: none;\n    position: absolute;\n    top: -10%;\n    right: 0;\n    width: 120%;\n    height: 120%;\n    box-shadow: inset 5px 0 25px #0004;\n}\n.list-feed {\n    margin-top: var(--navHeight);\n    height: calc(100% - var(--navHeight));\n    overflow: hidden scroll;\n    position: relative;\n}\n.list-feed > div.load-more-wrapper,\n.magazine-feed > div.load-more-wrapper,\n.compact-feed > div.load-more-wrapper {\n    text-align: center;\n    padding: 16px 0;\n}\n\n.magazine-feed,\n.compact-feed {\n    padding-top: 28px;\n    height: calc(100% - 60px);\n    overflow: hidden scroll;\n    margin-top: var(--navHeight);\n}\n.magazine-feed .ms-List-page {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n}\n\n.cards-feed-container {\n    display: inline-flex;\n    flex-wrap: wrap;\n    justify-content: space-around;\n    padding: 12px;\n    height: calc(100% - 32px);\n    overflow: hidden scroll;\n    margin-top: var(--navHeight);\n    width: 100%;\n    box-sizing: border-box;\n}\n.cards-feed-container .ms-List-page {\n    display: flex;\n    justify-content: space-around;\n    flex-wrap: wrap;\n}\n.cards-feed-container > div.load-more-wrapper,\n.flex-fix {\n    text-align: center;\n}\n.cards-feed-container > div.load-more-wrapper {\n    width: 100%;\n    margin: 16px 0;\n}\n.flex-fix {\n    min-width: 280px;\n}\n.cards-feed-container > .empty,\n.list-feed > .empty,\n.magazine-feed > .empty,\n.compact-feed > .empty {\n    width: 100%;\n    height: calc(100vh - 64px);\n    display: flex;\n    justify-content: space-around;\n    align-items: center;\n    color: var(--neutralSecondary);\n    font-size: 14px;\n    user-select: none;\n}\n"
  },
  {
    "path": "dist/styles/global.css",
    "content": ":root {\n    --neutralLighterAltOpacity: #faf9f8cc;\n    --neutralLighterAlt: #faf9f8;\n    --neutralLighter: #f3f2f1;\n    --neutralLight: #edebe9;\n    --neutralQuaternaryAlt: #e1dfdd;\n    --neutralQuaternary: #d2d0ce;\n    --neutralTertiaryAlt: #c8c6c4;\n    --neutralTertiary: #a19f9d;\n    --neutralSecondaryAlt: #8a8886;\n    --neutralSecondary: #605e5c;\n    --neutralPrimaryAlt: #3b3a39;\n    --neutralPrimary: #323130;\n    --neutralDark: #201f1e;\n    --neutralDarker: #161514;\n    --black: #000;\n    --white: #fff;\n    --whiteConstant: #fff;\n    --primary: #0078d4;\n    --navHeight: 32px;\n    --transition-timing: cubic-bezier(0.1, 0.9, 0.2, 1);\n    --blur: saturate(150%) blur(20px);\n}\n@media (prefers-color-scheme: dark) {\n    :root {\n        --neutralLighterAltOpacity: #282828cc;\n        --neutralLighterAlt: #282828;\n        --neutralLighter: #313131;\n        --neutralLight: #3f3f3f;\n        --neutralQuaternaryAlt: #484848;\n        --neutralQuaternary: #4f4f4f;\n        --neutralTertiaryAlt: #6d6d6d;\n        --neutralTertiary: #c8c8c8;\n        --neutralSecondaryAlt: #d2d0ce;\n        --neutralSecondary: #d0d0d0;\n        --neutralPrimaryAlt: #dadada;\n        --neutralPrimary: #ffffff;\n        --neutralDark: #f4f4f4;\n        --neutralDarker: #f4f4f4;\n        --black: #f8f8f8;\n        --white: #1f1f1f;\n        --whiteConstant: #f8f8f8;\n    }\n}\nbody.darwin {\n    --navHeight: 38px;\n}\n\nhtml,\nbody {\n    background-color: transparent;\n    font-family: \"Segoe UI\", \"Source Han Sans Regular\", sans-serif;\n    height: 100%;\n    overflow: hidden;\n    margin: 0;\n}\nbody:lang(zh-CN) {\n    font-family: \"Segoe UI\", \"Source Han Sans SC Regular\", \"Microsoft YaHei\",\n        sans-serif;\n}\nbody:lang(zh-TW) {\n    font-family: \"Segoe UI\", \"Source Han Sans TC Regular\", \"Microsoft JhengHei\",\n        sans-serif;\n}\nbody:lang(ja) {\n    font-family: \"Segoe UI\", \"Source Han Sans JP Regular\", \"Yu Gothic UI\",\n        sans-serif;\n}\nbody:lang(ko) {\n    font-family: \"Segoe UI\", \"Source Han Sans KR Regular\", \"Malgun Gothic\",\n        sans-serif;\n}\nbody.win32,\nbody.linux {\n    background-color: var(--neutralLighterAlt);\n}\n#root {\n    height: 100%;\n}\n\n.ms-Link {\n    user-select: none;\n}\n.ms-ContextualMenu-link,\n.ms-Button,\n.ms-ContextualMenu-item button {\n    cursor: default;\n    font-size: 13px;\n    user-select: none;\n}\n.ms-Nav-link,\n.ms-Nav-chevronButton {\n    font-size: 12px;\n    line-height: 32px;\n    height: 32px;\n    background-color: transparent;\n    color: var(--neutralPrimary);\n}\n.ms-Button--primary.danger {\n    background: #d13438;\n    border-color: #d13438;\n}\n.ms-Button--primary.danger:hover {\n    background: #ba2d32;\n    border-color: #ba2d32;\n}\n.ms-Button--primary.danger:active {\n    background: #a4262c;\n    border-color: #a4262c;\n}\n.ms-Button--primary.danger.is-disabled {\n    background: var(--neutralLighter);\n    border-color: var(--neutralLighter);\n}\n.ms-Button--commandBar.active {\n    background-color: var(--neutralLight);\n    color: var(--neutralDark);\n}\n.ms-Button--commandBar.active .ms-Button-icon {\n    color: #005a9e;\n}\ni.ms-Nav-chevron {\n    line-height: 32px;\n    height: 32px;\n}\n.ms-Nav-groupContent {\n    margin-bottom: 24px;\n}\n.ms-ActivityItem-activityTypeIcon,\n.ms-ActivityItem-timeStamp {\n    user-select: none;\n}\n.ms-Label,\n.ms-Spinner-label {\n    user-select: none;\n}\n.ms-ActivityItem,\n.ms-ActivityItem-commentText {\n    color: var(--neutralSecondary);\n}\n.ms-ActivityItem-timeStamp {\n    color: var(--neutralSecondaryAlt);\n}\n.ms-MessageBar {\n    user-select: none;\n    margin-bottom: 8px;\n}\n.ms-MessageBar:not(.ms-MessageBar--warning) {\n    background: var(--neutralLighter);\n    color: var(--neutralPrimary);\n}\n.ms-MessageBar:not(.ms-MessageBar--warning) i[data-icon-name=\"Info\"] {\n    color: var(--neutralPrimary);\n}\n\n.ms-Callout-main {\n    border-radius: 5px;\n}\n\n#root > nav {\n    height: var(--navHeight);\n    -webkit-app-region: drag;\n    user-select: none;\n    overflow: hidden;\n}\n#root > nav .btn,\n#root > nav span {\n    z-index: 1;\n    position: relative;\n}\nbody.blur #root > nav {\n    --black: var(--neutralSecondaryAlt);\n}\nnav .progress {\n    position: fixed;\n    top: 0;\n    left: 0;\n    z-index: 10;\n    width: 100%;\n    height: 2px;\n    overflow: hidden;\n}\n.ms-ProgressIndicator-itemProgress {\n    padding: 0;\n}\n.ms-ProgressIndicator-progressTrack {\n    background: none;\n}\n#root > nav span.title {\n    font-size: 12px;\n    line-height: var(--navHeight);\n    vertical-align: top;\n    letter-spacing: 2px;\n    margin: 0 4px;\n    display: inline-block;\n    max-width: 280px;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    color: var(--black);\n}\nbody.darwin #root > nav span.title {\n    max-width: 220px;\n}\n.btn-group {\n    display: inline-block;\n    user-select: none;\n    -webkit-app-region: none;\n}\n.btn-group .seperator {\n    display: inline-block;\n    width: var(--navHeight);\n    font-size: 12px;\n    color: #c8c6c4;\n    text-align: center;\n    vertical-align: middle;\n}\nbody.darwin .btn-group .seperator {\n    display: none;\n}\n.btn-group .seperator::before {\n    content: \"|\";\n}\n.btn-group .btn {\n    display: inline-block;\n    width: 48px;\n    height: 32px;\n    text-decoration: none;\n    text-align: center;\n    line-height: 32px;\n    color: var(--black);\n    font-size: 14px;\n    vertical-align: top;\n}\n#root > nav .btn-group .btn,\n.menu .btn-group .btn {\n    height: var(--navHeight);\n    line-height: var(--navHeight);\n}\nbody.darwin.not-fullscreen #root > nav .btn-group:first-of-type {\n    margin-left: 72px;\n}\n#root > nav .btn-group .btn.system {\n    position: relative;\n    z-index: 10;\n}\nnav.hide-btns .btn-group .btn {\n    display: none;\n}\nnav.hide-btns .btn-group .btn.system {\n    display: inline-block;\n}\nnav.item-on .btn-group .btn.system {\n    color: var(--whiteConstant);\n}\n.btn-group .btn:hover,\n.ms-Nav-compositeLink:hover {\n    background-color: #0001;\n}\n.btn-group .btn:active,\n.ms-Nav-compositeLink:active {\n    background-color: #0002;\n}\n.ms-Nav-compositeLink:hover .ms-Nav-link {\n    background: none;\n}\n.btn-group .btn.disabled,\n.btn-group .btn.fetching {\n    background-color: unset !important;\n    color: var(--neutralSecondaryAlt);\n}\n.btn-group .btn.fetching {\n    animation: rotating linear 1.5s infinite;\n}\n@keyframes rotating {\n    0% {\n        transform: rotate(0deg);\n    }\n    100% {\n        transform: rotate(360deg);\n    }\n}\n.btn-group .btn.close:hover {\n    background-color: #e81123;\n    color: var(--whiteConstant) !important;\n}\n.btn-group .btn.close:active {\n    background-color: #f1707a;\n    color: var(--whiteConstant) !important;\n}\n.btn-group .btn.inline-block-wide {\n    display: none;\n}\nbody.darwin .btn-group .btn.system {\n    display: none;\n}\n"
  },
  {
    "path": "dist/styles/main.css",
    "content": ".qr-container {\n    height: 150px;\n    padding: 7px;\n    margin: 8px;\n    background: #fff;\n}\n\n@keyframes fade {\n    0% {\n        opacity: 0;\n    }\n    100% {\n        opacity: 1;\n    }\n}\n.menu-container,\n.article-container {\n    position: fixed;\n    z-index: 5;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n}\n.article-container {\n    backdrop-filter: var(--blur);\n    animation-name: fade;\n    background-color: #0008;\n}\n.menu-container,\n.article-container,\n.article-wrapper {\n    animation-duration: 0.5s;\n    animation-timing-function: var(--transition-timing);\n    animation-fill-mode: both;\n}\n.menu-container {\n    pointer-events: none;\n}\n.menu-container.show {\n    pointer-events: unset;\n}\n.article-container {\n    z-index: 6;\n}\n.menu-container .menu {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 280px;\n    height: 100%;\n    background-color: var(--neutralLighterAltOpacity);\n    backdrop-filter: var(--blur);\n    box-shadow: 5px 0 25px #0004;\n    transition: clip-path var(--transition-timing) 0.367s,\n        opacity cubic-bezier(0, 0, 0.2, 1) 0.367s;\n    clip-path: inset(0 100% 0 0);\n    opacity: 0;\n}\n.menu-container.show .menu {\n    clip-path: inset(0 -50px 0 0);\n    opacity: 1;\n}\nbody.blur .menu .btn-group {\n    --black: var(--neutralSecondaryAlt);\n}\nbody.darwin .menu .btn-group {\n    display: flex;\n    flex-direction: row-reverse;\n}\n.menu-container .menu .nav-wrapper {\n    max-height: calc(100% - var(--navHeight));\n    overflow: hidden auto;\n}\n.menu-container .menu p.subs-header {\n    font-size: 12px;\n    color: var(--neutralSecondaryAlt);\n    margin: 2px 8px;\n    user-select: none;\n}\n.menu .link-stack {\n    overflow: hidden;\n}\n.menu .link-text {\n    margin-top: 0px;\n    margin-right: 4px;\n    margin-bottom: 0px;\n    margin-left: 4px;\n    text-align: left;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    flex-grow: 1;\n}\n.menu .unread-count {\n    color: var(--neutralSecondary);\n}\n\n.settings-container {\n    position: fixed;\n    z-index: 7;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    background-color: var(--neutralLight);\n    overflow: hidden;\n}\n.settings-container .settings {\n    margin: 64px auto 0;\n    width: 680px;\n    height: calc(100% - 64px);\n    background-color: var(--white);\n    box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132),\n        0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108);\n    overflow: hidden;\n}\ndiv[role=\"toolbar\"] {\n    height: 100%;\n}\ndiv[role=\"tabpanel\"] {\n    height: calc(100% - 68px);\n    padding: 12px 16px;\n    overflow-y: auto;\n    position: relative;\n}\n.settings .loading {\n    position: absolute;\n    left: 0;\n    top: 0;\n    width: 100%;\n    height: 100%;\n    background-color: #fffa;\n    z-index: 8;\n}\n.settings .loading .ms-Spinner {\n    margin-top: 180px;\n}\n.settings .loading .ms-Spinner:focus {\n    outline: none;\n}\n.tab-body .ms-StackItem {\n    margin-right: 6px;\n    margin-bottom: 12px;\n}\n.tab-body .ms-StackItem:last-child {\n    margin-right: 0;\n}\n.tab-body .ms-ChoiceFieldGroup {\n    margin-bottom: 20px;\n}\n.tab-body .ms-CommandBar {\n    padding: 0;\n}\nimg.favicon {\n    width: 16px;\n    height: 16px;\n    vertical-align: middle;\n    user-select: none;\n}\nimg.favicon.dropdown {\n    margin-right: 8px;\n    vertical-align: sub;\n}\n.ms-DetailsList-contentWrapper {\n    max-height: 400px;\n    overflow-x: hidden;\n    overflow-y: auto;\n    margin-bottom: 16px;\n}\n.settings-hint {\n    user-select: none;\n    line-height: 32px;\n    font-size: 12px;\n    color: var(--neutralSecondary);\n}\n.settings-hint.up {\n    position: relative;\n    top: -12px;\n    line-height: unset;\n}\n.settings-about {\n    margin: 72px 0;\n    color: var(--black);\n}\n.settings-about > * {\n    margin: 0 !important;\n    -webkit-user-drag: none;\n}\n.settings-rules-icons i {\n    color: var(--black);\n    user-select: none;\n}\n.settings-rules-icons i:last-of-type {\n    color: var(--neutralSecondary);\n}\n.login-form {\n    width: 300px;\n}\n.login-form .ms-Label {\n    width: 72px;\n}\n\n.main {\n    margin-top: calc(-1 * var(--navHeight));\n    height: 100%;\n    overflow: hidden;\n    background-color: var(--neutralLighterAlt);\n}\n.main::before {\n    content: \"\";\n    display: block;\n    position: relative;\n    top: var(--navHeight);\n    left: 0;\n    width: calc(100% - 16px);\n    height: var(--navHeight);\n    margin-bottom: calc(-1 * var(--navHeight));\n    background: linear-gradient(var(--neutralLighterAlt), #faf9f800);\n    z-index: 1;\n}\n.article-search {\n    z-index: 4;\n    position: absolute;\n    top: 0;\n    left: 36px;\n    width: 100%;\n    max-width: calc(100% - 484px);\n    margin: 4px 16px;\n    border: none;\n    -webkit-app-region: none;\n    height: calc(var(--navHeight) - 4px);\n    box-shadow: 0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132),\n        0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108);\n}\nbody.darwin.not-fullscreen .article-search {\n    left: 108px;\n    max-width: calc(100% - 384px);\n}\n.list-main .article-search {\n    max-width: 294px;\n    margin: 4px 10px;\n}\nbody.darwin .list-main .article-search {\n    max-width: 314px;\n    left: 0;\n    top: var(--navHeight);\n    margin: 0 10px;\n}\n.main,\n.list-main {\n    transition: margin-left var(--transition-timing) 0.367s;\n    margin-left: 0;\n}\n\n@media (min-width: 1440px) {\n    #root > nav.menu-on {\n        padding-left: 296px;\n    }\n    #root > nav.menu-on span.title,\n    body.darwin #root > nav.menu-on span.title {\n        max-width: 300px;\n    }\n    nav.menu-on .btn-group .btn {\n        display: inline-block;\n    }\n    nav.item-on .btn-group .btn.system {\n        color: var(--whiteConstant);\n    }\n    .menu-container {\n        width: 280px;\n        background: none;\n        backdrop-filter: none;\n    }\n    .menu-container .menu {\n        background-color: var(--neutralLight);\n        box-shadow: none;\n    }\n    .menu-container.show .menu {\n        clip-path: inset(0);\n    }\n    body.darwin .menu-container .menu {\n        background: none;\n    }\n    body.darwin .menu-container .menu.item-on {\n        background-color: var(--neutralLight);\n    }\n    .menu-container .menu::after {\n        content: \"\";\n        display: block;\n        pointer-events: none;\n        position: absolute;\n        top: -10%;\n        right: 0;\n        width: 120%;\n        height: 120%;\n        box-shadow: inset 5px 0 25px #0004;\n    }\n    .main.menu-on,\n    .list-main.menu-on {\n        margin-left: 280px;\n    }\n    .menu-on .article-search {\n        left: 280px;\n        max-width: calc(100% - 728px);\n    }\n    body.darwin .menu-on .article-search {\n        left: 280px;\n        max-width: calc(100% - 556px);\n    }\n    .list-main.menu-on .article-search {\n        left: 0;\n        width: 330px;\n    }\n    body.darwin .list-main.menu-on .article-search {\n        left: 0;\n        top: 4px;\n    }\n\n    nav.hide-btns .btn-group .btn,\n    nav.menu-on .btn-group .btn.hide-wide,\n    .menu .btn-group .btn.hide-wide {\n        display: none;\n    }\n    .btn-group .btn.inline-block-wide {\n        display: inline-block;\n    }\n}\n"
  },
  {
    "path": "dist/styles/scroll.css",
    "content": "::-webkit-scrollbar {\n    width: 16px;\n}\n::-webkit-scrollbar-thumb {\n    border: 2px solid transparent;\n    background-color: #0004;\n    background-clip: padding-box;\n}\n::-webkit-scrollbar-thumb:hover {\n    background-color: #0006;\n}\n::-webkit-scrollbar-thumb:active {\n    background-color: #0008;\n}\n@media (prefers-color-scheme: dark) {\n    ::-webkit-scrollbar-thumb {\n        background-color: #fff4;\n    }\n    ::-webkit-scrollbar-thumb:hover {\n        background-color: #fff6;\n    }\n    ::-webkit-scrollbar-thumb:active {\n        background-color: #fff8;\n    }\n}\n"
  },
  {
    "path": "docs/index.html",
    "content": "<html>\n    <head>\n        <title>Fluent Reader</title>\n        <link rel=\"icon\" href=\"imgs/icon.png\">\n        <link rel=\"stylesheet\" href=\"styles.css\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n        <meta name=\"apple-itunes-app\" content=\"app-id=1549611796\">\n    </head>\n    <body>\n        <div class=\"logo-container\">\n            <img src=\"imgs/logo.svg\" />\n            <header>Fluent Reader</header>\n        </div>\n        <div class=\"light-container\">\n            <div class=\"screenshot elevate\"><img src=\"imgs/light.png\" /></div>\n            <h1>Modern desktop RSS reader. Open-source.</h1>\n            <p>\n                Fluent Reader is a local, cross-platform news aggregator with a fresh look.\n                Bring all your favorite sources with you and read distraction-free.\n            </p>\n        </div>\n        <div class=\"features-container\">\n            <section class=\"elevate\">\n                <h2>Open & Organized.</h2>\n                <p>\n                    Stay in sync with Inoreader, Feedbin, or services compatible with\n                    Fever or Google Reader API. Alternatively, import your sources from\n                    an OPML file and read locally.\n                    Easily organize sources with groups. Move between computers with full\n                    data backups.\n                </p>\n                <img class=\"elevate\" src=\"imgs/opml.png\" />\n            </section>\n            <section class=\"elevate\">\n                <h2>Read fluently.</h2>\n                <p>\n                    Enjoy your contents like never before with the built-in article view \n                    for RSS full text tailored to maximize focus. Source only comes with \n                    snippets? Configure to load full content with Mercury Parser, load\n                    webpage in the app, or open externally by default.\n                </p>\n                <img class=\"elevate\" src=\"imgs/read.png\" />\n            </section>\n            <section class=\"elevate\">\n                <h2>Search. Filter.</h2>\n                <p>\n                    Find anything you want with the power of regular expressions. Search in \n                    both titles and full contents of articles. Mark articles as starred, \n                    hidden, or unread and filter as they arrive with custom rules based \n                    on regular expressions.\n                </p>\n                <img class=\"elevate center\" src=\"imgs/search.png\" />\n            </section>\n            <section class=\"elevate\">\n                <h2>Privacy first.</h2>\n                <h3>All your data stays with you.</h3>\n                <h3>All cookies cleared upon exit.</h3>\n                <h3>XSS blocked in an isolated context.</h3>\n                <h3>No personal information collected, ever.</h3>\n                <h3>Behavior tracking limited.</h3>\n                <h3>Strict Content Security Policy enforced.</h3>\n                <h3>Proxy support with PAC.</h3>\n                <br />\n                <h3><span>■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■</span></h3>\n                <h3><span>■ ■ ■ ■ ■ ■</span></h3>\n                <h3><span>■ ■ ■ ■ ■ ■ ■ ■ ■</span></h3>\n                <h3><span>■ ■ ■ ■ ■ ■ ■</span></h3>\n            </section>\n        </div>\n        <div class=\"dark-container\">\n            <div class=\"screenshot elevate\"><img src=\"imgs/dark.png\" /></div>\n            <h1>Oh, it also comes in black.</h1>\n            <p>Full system-level dark mode support for both UI and reading.</p>\n        </div>\n        <div class=\"get-container\">\n            <div class=\"stores\">\n                <a href=\"https://www.microsoft.com/store/apps/9P71FC94LRH8?cid=website\"><img class=\"ms-get\" src=\"imgs/store.png\" /></a>\n                <a href=\"https://apps.apple.com/app/id1520907427\"><img class=\"mac-get\" src=\"imgs/mac_store.svg\" /></a>\n            </div>\n            <div><a href=\"https://github.com/yang991178/fluent-reader/releases\">Download from GitHub Releases</a></div>\n            <div class=\"links\">\n                <a href=\"https://github.com/yang991178/fluent-reader/\">GitHub</a>\n                <a href=\"https://github.com/yang991178/fluent-reader/wiki/Support\">Help</a>\n                <a href=\"https://hyliu.me/fluent-reader-lite/\">Mobile App</a>\n            </div>\n        </div>\n    </body>\n</html>"
  },
  {
    "path": "docs/styles.css",
    "content": "html,\nbody {\n    background-color: #f3f2f1;\n    font-family: \"Segoe UI\", \"Microsoft YaHei\", sans-serif;\n    margin: 0;\n    line-height: 1.5;\n    width: 100%;\n}\nhtml {\n    overflow-x: hidden;\n}\n\na {\n    color: #0078d4;\n    text-decoration: none;\n}\na:hover,\na:active {\n    color: #004578;\n    text-decoration: underline;\n}\n\n.elevate {\n    box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132),\n        0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108);\n}\n\n.logo-container {\n    height: 100vh;\n    width: 100%;\n    min-height: 540px;\n    position: relative;\n}\n.logo-container img {\n    height: 180px;\n    width: 180px;\n    position: fixed;\n    left: calc(50% - 90px);\n    top: calc(50% - 230px);\n}\n.logo-container header {\n    text-align: center;\n    display: block;\n    width: 100%;\n    font-size: 1.75em;\n    font-weight: 500;\n    position: fixed;\n    left: 0;\n    top: calc(50% - 40px);\n}\n\n.screenshot {\n    display: block;\n    margin: 0 auto;\n    width: 90%;\n    max-width: 1464px;\n    overflow: hidden;\n}\n.screenshot > img {\n    width: 100%;\n}\n\n.light-container {\n    padding-bottom: 48px;\n    background-color: #fff;\n    position: relative;\n}\n.light-container .screenshot {\n    margin: 0 auto -280px;\n    position: relative;\n    top: -280px;\n}\n.light-container h1,\n.dark-container h1 {\n    width: 95%;\n    max-width: 800px;\n    margin: 48px auto 24px;\n    font-weight: 500;\n    text-align: center;\n}\n.light-container p,\n.dark-container p {\n    width: 85%;\n    max-width: 750px;\n    margin: 24px auto;\n    text-align: center;\n    font-size: 1.375em;\n    color: #323130;\n}\n\n.features-container {\n    padding: 48px 0;\n    margin: 0 auto;\n    width: 95%;\n    max-width: 950px;\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: space-around;\n    position: relative;\n    background-color: #f3f2f1;\n}\n.features-container > section {\n    display: block;\n    width: 45%;\n    height: 560px;\n    padding: 18px 36px;\n    background-color: #fff;\n    margin: 24px 0;\n    overflow: hidden;\n    position: relative;\n    box-sizing: border-box;\n}\n.features-container > section > h3 {\n    font-weight: 500;\n    color: #605e5c;\n    margin: 0 0 0.5em;\n}\n.features-container > section > h3 > span {\n    color: #d2d0ce;\n    background-color: #d2d0ce;\n    user-select: none;\n}\n.features-container > section > img {\n    position: absolute;\n    right: 0;\n    bottom: 0;\n    max-width: 90%;\n}\n.features-container > section > img.center {\n    left: auto;\n    right: auto;\n}\n\n.dark-container {\n    position: relative;\n    background-color: #1f1f1f;\n    color: #fff;\n    padding: 72px 0;\n    overflow: hidden;\n}\n.dark-container p {\n    color: #d2d0ce;\n}\n\n.get-container {\n    height: 100vh;\n    width: 100%;\n    min-height: 540px;\n    display: flex;\n    align-items: center;\n    justify-content: flex-end;\n    flex-direction: column;\n    position: relative;\n}\n.stores {\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    align-items: center;\n}\n.stores > a {\n    display: inline-block;\n    margin: 0 16px 16px;\n}\n.ms-get {\n    width: 142px;\n    height: 52px;\n}\n.mac-get {\n    height: 52px;\n}\n.links {\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    margin: calc(50vh - 210px) 0 48px;\n}\n.links > a {\n    display: inline-block;\n    margin: 0 8px;\n}\n\n@media (max-width: 780px) {\n    html,\n    body {\n        font-size: 14px;\n    }\n    .logo-container img {\n        height: 140px;\n        width: 140px;\n        left: calc(50% - 70px);\n        top: calc(50% - 190px);\n    }\n    .screenshot {\n        margin-left: 5vw;\n    }\n    .light-container .screenshot {\n        width: 95vw;\n        margin: 0 0 -25vw 5vw;\n        position: relative;\n        top: -25vw;\n    }\n    .screenshot > img {\n        width: 150%;\n    }\n    .features-container > section {\n        width: 95%;\n        height: auto;\n        padding-bottom: 80%;\n    }\n    .features-container > section:last-of-type {\n        padding-bottom: 36px;\n    }\n    .stores {\n        flex-direction: column;\n    }\n    .links {\n        margin-top: calc(50vh - 270px);\n    }\n}\n"
  },
  {
    "path": "electron-builder-mas.yml",
    "content": "appId: DevHYLiu.FluentReader\nbuildVersion: 29\nproductName: Fluent Reader\ncopyright: Copyright © 2020 Haoyuan Liu\nfiles:\n    - \"./dist/**/*\"\n    - \"!./dist/fonts.vbs\"\n    - \"!**/*.js.map\"\nasarUnpack:\n    - \"./dist/fontlist\"\ndirectories:\n    output: \"./bin/${platform}/${arch}/\"\nmac:\n    darkModeSupport: true\n    target:\n        - dmg\n    category: public.app-category.news\n    electronLanguages:\n        - zh_CN\n        - zh_TW\n        - en\n        - fr\n        - es\n        - de\n        - tr\n        - ja\n        - sv\n        - uk\n        - it\n        - nl\n        - ko\n        - ru\n        - pt_BR\n        - pt_PT\n        - cs\n    minimumSystemVersion: 10.15.0\nmas:\n    entitlements: build/entitlements.mas.plist\n    entitlementsInherit: build/entitlements.mas.inherit.plist\n    provisioningProfile: build/embedded.provisionprofile\n    hardenedRuntime: false\n    gatekeeperAssess: false\n    asarUnpack: []\n"
  },
  {
    "path": "electron-builder.yml",
    "content": "appId: me.hyliu.fluentreader\nproductName: Fluent Reader\ncopyright: Copyright © 2020 Haoyuan Liu\nfiles:\n    - \"./dist/**/*\"\n    - \"!./dist/fontlist\"\n    - \"!**/*.js.map\"\ndirectories:\n    output: \"./bin/${platform}/${arch}/\"\nmac:\n    darkModeSupport: true\n    target:\n        - dmg\n    category: public.app-category.news\n    electronLanguages:\n        - zh_CN\n        - zh_TW\n        - en\n        - fr\n        - es\n        - de\n        - tr\n        - ja\n        - sv\n        - uk\n        - it\n        - nl\n        - ko\n        - ru\n        - pt_BR\n        - pt_PT\n        - cs\nwin:\n    target:\n        - nsis\n        - zip\nappx:\n    applicationId: FluentReader\n    identityName: 25286HaoyuanLiu.FluentReader\n    publisher: CN=FD70E7FA-E5AC-41C4-B9C4-6E8708A6616A\n    backgroundColor: transparent\n    languages:\n        - zh-CN\n        - zh-TW\n        - en-US\n        - fr-FR\n        - es\n        - de\n        - tr\n        - ja\n        - sv\n        - uk\n        - it\n        - nl\n        - ko\n        - ru\n        - pt-BR\n        - pt-PT\n        - cs\n    showNameOnTiles: true\n    setBuildNumber: true\nnsis:\n    oneClick: false\n    perMachine: true\n    allowToChangeInstallationDirectory: true\n    deleteAppDataOnUninstall: true\nlinux:\n    target:\n        - AppImage\n    icon: build/icons\n    category: Utility\n    desktop:\n        StartupWMClass: fluent-reader\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"fluent-reader\",\n  \"version\": \"1.1.4\",\n  \"description\": \"Modern desktop RSS reader\",\n  \"main\": \"./dist/electron.js\",\n  \"scripts\": {\n    \"build\": \"webpack --config ./webpack.config.js\",\n    \"electron\": \"electron ./dist/electron.js\",\n    \"start\": \"npm run build && npm run electron\",\n    \"format\": \"prettier --write .\",\n    \"package-win\": \"electron-builder -w appx:x64 && electron-builder -w appx:ia32 && electron-builder -w appx:arm64\",\n    \"package-win-ci\": \"electron-builder -w --x64 -p never && electron-builder -w --ia32 -p never\",\n    \"package-mac\": \"electron-builder --mac --x64\",\n    \"package-mas\": \"bash build/resignAndPackage.sh\",\n    \"package-linux\": \"electron-builder --linux --x64 -p never\"\n  },\n  \"keywords\": [],\n  \"author\": \"Haoyuan Liu\",\n  \"license\": \"BSD-3-Clause\",\n  \"repository\": \"github:yang991178/fluent-reader\",\n  \"devDependencies\": {\n    \"@fluentui/react\": \"^7.126.2\",\n    \"@types/lovefield\": \"^2.1.3\",\n    \"@types/nedb\": \"^1.8.9\",\n    \"@types/react\": \"^16.9.35\",\n    \"@types/react-dom\": \"^16.9.8\",\n    \"@types/react-redux\": \"^7.1.9\",\n    \"electron\": \"^34.3.0\",\n    \"electron-builder\": \"^23.0.3\",\n    \"electron-react-devtools\": \"^0.5.3\",\n    \"electron-store\": \"^5.2.0\",\n    \"electron-window-state\": \"^5.0.3\",\n    \"font-list\": \"^1.4.2\",\n    \"html-webpack-plugin\": \"^5.5.3\",\n    \"js-md5\": \"^0.7.3\",\n    \"lovefield\": \"^2.1.12\",\n    \"nedb\": \"^1.8.0\",\n    \"prettier\": \"2.3.2\",\n    \"qrcode.react\": \"^1.0.0\",\n    \"react\": \"^16.13.1\",\n    \"react-dom\": \"^16.13.1\",\n    \"react-intl-universal\": \"^2.2.5\",\n    \"react-redux\": \"^7.2.0\",\n    \"redux\": \"^4.0.5\",\n    \"redux-devtools\": \"^3.5.0\",\n    \"redux-thunk\": \"^2.3.0\",\n    \"reselect\": \"^4.0.0\",\n    \"rss-parser\": \"^3.13.0\",\n    \"ts-loader\": \"^7.0.4\",\n    \"typescript\": \"^5.8.2\",\n    \"webpack\": \"^5.89.0\",\n    \"webpack-cli\": \"^5.1.4\"\n  },\n  \"dependencies\": {\n    \"node-polyfill-webpack-plugin\": \"^2.0.1\"\n  }\n}\n"
  },
  {
    "path": "src/bridges/settings.ts",
    "content": "import {\n    SourceGroup,\n    ViewType,\n    ThemeSettings,\n    SearchEngines,\n    ServiceConfigs,\n    ViewConfigs,\n} from \"../schema-types\"\nimport { ipcRenderer } from \"electron\"\n\nconst settingsBridge = {\n    saveGroups: (groups: SourceGroup[]) => {\n        ipcRenderer.invoke(\"set-groups\", groups)\n    },\n    loadGroups: (): SourceGroup[] => {\n        return ipcRenderer.sendSync(\"get-groups\")\n    },\n\n    getDefaultMenu: (): boolean => {\n        return ipcRenderer.sendSync(\"get-menu\")\n    },\n    setDefaultMenu: (state: boolean) => {\n        ipcRenderer.invoke(\"set-menu\", state)\n    },\n\n    getProxyStatus: (): boolean => {\n        return ipcRenderer.sendSync(\"get-proxy-status\")\n    },\n    toggleProxyStatus: () => {\n        ipcRenderer.send(\"toggle-proxy-status\")\n    },\n    getProxy: (): string => {\n        return ipcRenderer.sendSync(\"get-proxy\")\n    },\n    setProxy: (address: string = null) => {\n        ipcRenderer.invoke(\"set-proxy\", address)\n    },\n\n    getDefaultView: (): ViewType => {\n        return ipcRenderer.sendSync(\"get-view\")\n    },\n    setDefaultView: (viewType: ViewType) => {\n        ipcRenderer.invoke(\"set-view\", viewType)\n    },\n\n    getThemeSettings: (): ThemeSettings => {\n        return ipcRenderer.sendSync(\"get-theme\")\n    },\n    setThemeSettings: (theme: ThemeSettings) => {\n        ipcRenderer.invoke(\"set-theme\", theme)\n    },\n    shouldUseDarkColors: (): boolean => {\n        return ipcRenderer.sendSync(\"get-theme-dark-color\")\n    },\n    addThemeUpdateListener: (callback: (shouldDark: boolean) => any) => {\n        ipcRenderer.on(\"theme-updated\", (_, shouldDark) => {\n            callback(shouldDark)\n        })\n    },\n\n    setLocaleSettings: (option: string) => {\n        ipcRenderer.invoke(\"set-locale\", option)\n    },\n    getLocaleSettings: (): string => {\n        return ipcRenderer.sendSync(\"get-locale-settings\")\n    },\n    getCurrentLocale: (): string => {\n        return ipcRenderer.sendSync(\"get-locale\")\n    },\n\n    getFontSize: (): number => {\n        return ipcRenderer.sendSync(\"get-font-size\")\n    },\n    setFontSize: (size: number) => {\n        ipcRenderer.invoke(\"set-font-size\", size)\n    },\n\n    getFont: (): string => {\n        return ipcRenderer.sendSync(\"get-font\")\n    },\n    setFont: (font: string) => {\n        ipcRenderer.invoke(\"set-font\", font)\n    },\n\n    getFetchInterval: (): number => {\n        return ipcRenderer.sendSync(\"get-fetch-interval\")\n    },\n    setFetchInterval: (interval: number) => {\n        ipcRenderer.invoke(\"set-fetch-interval\", interval)\n    },\n\n    getSearchEngine: (): SearchEngines => {\n        return ipcRenderer.sendSync(\"get-search-engine\")\n    },\n    setSearchEngine: (engine: SearchEngines) => {\n        ipcRenderer.invoke(\"set-search-engine\", engine)\n    },\n\n    getServiceConfigs: (): ServiceConfigs => {\n        return ipcRenderer.sendSync(\"get-service-configs\")\n    },\n    setServiceConfigs: (configs: ServiceConfigs) => {\n        ipcRenderer.invoke(\"set-service-configs\", configs)\n    },\n\n    getFilterType: (): number => {\n        return ipcRenderer.sendSync(\"get-filter-type\")\n    },\n    setFilterType: (filterType: number) => {\n        ipcRenderer.invoke(\"set-filter-type\", filterType)\n    },\n\n    getViewConfigs: (view: ViewType): ViewConfigs => {\n        return ipcRenderer.sendSync(\"get-view-configs\", view)\n    },\n    setViewConfigs: (view: ViewType, configs: ViewConfigs) => {\n        ipcRenderer.invoke(\"set-view-configs\", view, configs)\n    },\n\n    getNeDBStatus: (): boolean => {\n        return ipcRenderer.sendSync(\"get-nedb-status\")\n    },\n    setNeDBStatus: (flag: boolean) => {\n        ipcRenderer.invoke(\"set-nedb-status\", flag)\n    },\n\n    getAll: () => {\n        return ipcRenderer.sendSync(\"get-all-settings\") as Object\n    },\n\n    setAll: configs => {\n        ipcRenderer.invoke(\"import-all-settings\", configs)\n    },\n}\n\ndeclare global {\n    interface Window {\n        settings: typeof settingsBridge\n    }\n}\n\nexport default settingsBridge\n"
  },
  {
    "path": "src/bridges/utils.ts",
    "content": "import { ipcRenderer } from \"electron\"\nimport {\n    ImageCallbackTypes,\n    TouchBarTexts,\n    WindowStateListenerType,\n} from \"../schema-types\"\nimport { IObjectWithKey } from \"@fluentui/react\"\n\nconst utilsBridge = {\n    platform: process.platform,\n\n    getVersion: (): string => {\n        return ipcRenderer.sendSync(\"get-version\")\n    },\n\n    openExternal: (url: string, background = false) => {\n        ipcRenderer.invoke(\"open-external\", url, background)\n    },\n\n    showErrorBox: (title: string, content: string, copy?: string) => {\n        ipcRenderer.invoke(\"show-error-box\", title, content, copy)\n    },\n\n    showMessageBox: async (\n        title: string,\n        message: string,\n        confirm: string,\n        cancel: string,\n        defaultCancel = false,\n        type = \"none\"\n    ) => {\n        return (await ipcRenderer.invoke(\n            \"show-message-box\",\n            title,\n            message,\n            confirm,\n            cancel,\n            defaultCancel,\n            type\n        )) as boolean\n    },\n\n    showSaveDialog: async (filters: Electron.FileFilter[], path: string) => {\n        let result = (await ipcRenderer.invoke(\n            \"show-save-dialog\",\n            filters,\n            path\n        )) as boolean\n        if (result) {\n            return (result: string, errmsg: string) => {\n                ipcRenderer.invoke(\"write-save-result\", result, errmsg)\n            }\n        } else {\n            return null\n        }\n    },\n\n    showOpenDialog: async (filters: Electron.FileFilter[]) => {\n        return (await ipcRenderer.invoke(\"show-open-dialog\", filters)) as string\n    },\n\n    getCacheSize: async (): Promise<number> => {\n        return await ipcRenderer.invoke(\"get-cache\")\n    },\n\n    clearCache: async () => {\n        await ipcRenderer.invoke(\"clear-cache\")\n    },\n\n    addMainContextListener: (\n        callback: (pos: [number, number], text: string) => any\n    ) => {\n        ipcRenderer.removeAllListeners(\"window-context-menu\")\n        ipcRenderer.on(\"window-context-menu\", (_, pos, text) => {\n            callback(pos, text)\n        })\n    },\n    addWebviewContextListener: (\n        callback: (pos: [number, number], text: string, url: string) => any\n    ) => {\n        ipcRenderer.removeAllListeners(\"webview-context-menu\")\n        ipcRenderer.on(\"webview-context-menu\", (_, pos, text, url) => {\n            callback(pos, text, url)\n        })\n    },\n    imageCallback: (type: ImageCallbackTypes) => {\n        ipcRenderer.invoke(\"image-callback\", type)\n    },\n\n    addWebviewKeydownListener: (callback: (event: Electron.Input) => any) => {\n        ipcRenderer.removeAllListeners(\"webview-keydown\")\n        ipcRenderer.on(\"webview-keydown\", (_, input) => {\n            callback(input)\n        })\n    },\n\n    addWebviewErrorListener: (callback: (reason: string) => any) => {\n        ipcRenderer.removeAllListeners(\"webview-error\")\n        ipcRenderer.on(\"webview-error\", (_, reason) => {\n            callback(reason)\n        })\n    },\n\n    writeClipboard: (text: string) => {\n        ipcRenderer.invoke(\"write-clipboard\", text)\n    },\n\n    closeWindow: () => {\n        ipcRenderer.invoke(\"close-window\")\n    },\n    minimizeWindow: () => {\n        ipcRenderer.invoke(\"minimize-window\")\n    },\n    maximizeWindow: () => {\n        ipcRenderer.invoke(\"maximize-window\")\n    },\n    isMaximized: () => {\n        return ipcRenderer.sendSync(\"is-maximized\") as boolean\n    },\n    isFullscreen: () => {\n        return ipcRenderer.sendSync(\"is-fullscreen\") as boolean\n    },\n    isFocused: () => {\n        return ipcRenderer.sendSync(\"is-focused\") as boolean\n    },\n    focus: () => {\n        ipcRenderer.invoke(\"request-focus\")\n    },\n    requestAttention: () => {\n        ipcRenderer.invoke(\"request-attention\")\n    },\n    addWindowStateListener: (\n        callback: (type: WindowStateListenerType, state: boolean) => any\n    ) => {\n        ipcRenderer.removeAllListeners(\"maximized\")\n        ipcRenderer.on(\"maximized\", () => {\n            callback(WindowStateListenerType.Maximized, true)\n        })\n        ipcRenderer.removeAllListeners(\"unmaximized\")\n        ipcRenderer.on(\"unmaximized\", () => {\n            callback(WindowStateListenerType.Maximized, false)\n        })\n        ipcRenderer.removeAllListeners(\"enter-fullscreen\")\n        ipcRenderer.on(\"enter-fullscreen\", () => {\n            callback(WindowStateListenerType.Fullscreen, true)\n        })\n        ipcRenderer.removeAllListeners(\"leave-fullscreen\")\n        ipcRenderer.on(\"leave-fullscreen\", () => {\n            callback(WindowStateListenerType.Fullscreen, false)\n        })\n        ipcRenderer.removeAllListeners(\"window-focus\")\n        ipcRenderer.on(\"window-focus\", () => {\n            callback(WindowStateListenerType.Focused, true)\n        })\n        ipcRenderer.removeAllListeners(\"window-blur\")\n        ipcRenderer.on(\"window-blur\", () => {\n            callback(WindowStateListenerType.Focused, false)\n        })\n    },\n\n    addTouchBarEventsListener: (callback: (IObjectWithKey) => any) => {\n        ipcRenderer.removeAllListeners(\"touchbar-event\")\n        ipcRenderer.on(\"touchbar-event\", (_, key: string) => {\n            callback({ key: key })\n        })\n    },\n    initTouchBar: (texts: TouchBarTexts) => {\n        ipcRenderer.invoke(\"touchbar-init\", texts)\n    },\n    destroyTouchBar: () => {\n        ipcRenderer.invoke(\"touchbar-destroy\")\n    },\n\n    initFontList: (): Promise<Array<string>> => {\n        return ipcRenderer.invoke(\"init-font-list\")\n    },\n}\n\ndeclare global {\n    interface Window {\n        utils: typeof utilsBridge\n        fontList: Array<string>\n    }\n}\n\nexport default utilsBridge\n"
  },
  {
    "path": "src/components/article.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { renderToString } from \"react-dom/server\"\nimport { RSSItem } from \"../scripts/models/item\"\nimport {\n    Stack,\n    CommandBarButton,\n    IContextualMenuProps,\n    FocusZone,\n    ContextualMenuItemType,\n    Spinner,\n    Icon,\n    Link,\n} from \"@fluentui/react\"\nimport {\n    RSSSource,\n    SourceOpenTarget,\n    SourceTextDirection,\n} from \"../scripts/models/source\"\nimport { shareSubmenu } from \"./context-menu\"\nimport { platformCtrl, decodeFetchResponse } from \"../scripts/utils\"\n\nconst FONT_SIZE_OPTIONS = [12, 13, 14, 15, 16, 17, 18, 19, 20]\n\ntype ArticleProps = {\n    item: RSSItem\n    source: RSSSource\n    locale: string\n    shortcuts: (item: RSSItem, e: KeyboardEvent) => void\n    dismiss: () => void\n    offsetItem: (offset: number) => void\n    toggleHasRead: (item: RSSItem) => void\n    toggleStarred: (item: RSSItem) => void\n    toggleHidden: (item: RSSItem) => void\n    textMenu: (position: [number, number], text: string, url: string) => void\n    imageMenu: (position: [number, number]) => void\n    dismissContextMenu: () => void\n    updateSourceTextDirection: (\n        source: RSSSource,\n        direction: SourceTextDirection\n    ) => void\n}\n\ntype ArticleState = {\n    fontFamily: string\n    fontSize: number\n    loadWebpage: boolean\n    loadFull: boolean\n    fullContent: string\n    loaded: boolean\n    error: boolean\n    errorDescription: string\n}\n\nclass Article extends React.Component<ArticleProps, ArticleState> {\n    webview: Electron.WebviewTag\n\n    constructor(props: ArticleProps) {\n        super(props)\n        this.state = {\n            fontFamily: window.settings.getFont(),\n            fontSize: window.settings.getFontSize(),\n            loadWebpage: props.source.openTarget === SourceOpenTarget.Webpage,\n            loadFull: props.source.openTarget === SourceOpenTarget.FullContent,\n            fullContent: \"\",\n            loaded: false,\n            error: false,\n            errorDescription: \"\",\n        }\n        window.utils.addWebviewContextListener(this.contextMenuHandler)\n        window.utils.addWebviewKeydownListener(this.keyDownHandler)\n        window.utils.addWebviewErrorListener(this.webviewError)\n        if (props.source.openTarget === SourceOpenTarget.FullContent)\n            this.loadFull()\n    }\n\n    setFontSize = (size: number) => {\n        window.settings.setFontSize(size)\n        this.setState({ fontSize: size })\n    }\n    setFont = (font: string) => {\n        window.settings.setFont(font)\n        this.setState({ fontFamily: font })\n    }\n\n    fontSizeMenuProps = (): IContextualMenuProps => ({\n        items: FONT_SIZE_OPTIONS.map(size => ({\n            key: String(size),\n            text: String(size),\n            canCheck: true,\n            checked: size === this.state.fontSize,\n            onClick: () => this.setFontSize(size),\n        })),\n    })\n\n    fontFamilyMenuProps = (): IContextualMenuProps => ({\n        items: window.fontList.map((font, idx) => ({\n            key: String(idx),\n            text: font === \"\" ? intl.get(\"default\") : font,\n            canCheck: true,\n            checked: this.state.fontFamily === font,\n            onClick: () => this.setFont(font),\n        })),\n    })\n\n    updateTextDirection = (direction: SourceTextDirection) => {\n        this.props.updateSourceTextDirection(this.props.source, direction)\n    }\n\n    directionMenuProps = (): IContextualMenuProps => ({\n        items: [\n            {\n                key: \"LTR\",\n                text: intl.get(\"article.LTR\"),\n                iconProps: { iconName: \"Forward\" },\n                canCheck: true,\n                checked: this.props.source.textDir === SourceTextDirection.LTR,\n                onClick: () =>\n                    this.updateTextDirection(SourceTextDirection.LTR),\n            },\n            {\n                key: \"RTL\",\n                text: intl.get(\"article.RTL\"),\n                iconProps: { iconName: \"Back\" },\n                canCheck: true,\n                checked: this.props.source.textDir === SourceTextDirection.RTL,\n                onClick: () =>\n                    this.updateTextDirection(SourceTextDirection.RTL),\n            },\n            {\n                key: \"Vertical\",\n                text: intl.get(\"article.Vertical\"),\n                iconProps: { iconName: \"Down\" },\n                canCheck: true,\n                checked:\n                    this.props.source.textDir === SourceTextDirection.Vertical,\n                onClick: () =>\n                    this.updateTextDirection(SourceTextDirection.Vertical),\n            },\n        ],\n    })\n\n    moreMenuProps = (): IContextualMenuProps => ({\n        items: [\n            {\n                key: \"openInBrowser\",\n                text: intl.get(\"openExternal\"),\n                iconProps: { iconName: \"NavigateExternalInline\" },\n                onClick: e => {\n                    window.utils.openExternal(\n                        this.props.item.link,\n                        platformCtrl(e)\n                    )\n                },\n            },\n            {\n                key: \"copyURL\",\n                text: intl.get(\"context.copyURL\"),\n                iconProps: { iconName: \"Link\" },\n                onClick: () => {\n                    window.utils.writeClipboard(this.props.item.link)\n                },\n            },\n            {\n                key: \"toggleHidden\",\n                text: this.props.item.hidden\n                    ? intl.get(\"article.unhide\")\n                    : intl.get(\"article.hide\"),\n                iconProps: {\n                    iconName: this.props.item.hidden ? \"View\" : \"Hide3\",\n                },\n                onClick: () => {\n                    this.props.toggleHidden(this.props.item)\n                },\n            },\n            {\n                key: \"fontMenu\",\n                text: intl.get(\"article.font\"),\n                iconProps: { iconName: \"Font\" },\n                disabled: this.state.loadWebpage,\n                subMenuProps: this.fontFamilyMenuProps(),\n            },\n            {\n                key: \"fontSizeMenu\",\n                text: intl.get(\"article.fontSize\"),\n                iconProps: { iconName: \"FontSize\" },\n                disabled: this.state.loadWebpage,\n                subMenuProps: this.fontSizeMenuProps(),\n            },\n            {\n                key: \"directionMenu\",\n                text: intl.get(\"article.textDir\"),\n                iconProps: { iconName: \"ChangeEntitlements\" },\n                disabled: this.state.loadWebpage,\n                subMenuProps: this.directionMenuProps(),\n            },\n            {\n                key: \"divider_1\",\n                itemType: ContextualMenuItemType.Divider,\n            },\n            ...shareSubmenu(this.props.item),\n        ],\n    })\n\n    contextMenuHandler = (pos: [number, number], text: string, url: string) => {\n        if (pos) {\n            if (text || url) this.props.textMenu(pos, text, url)\n            else this.props.imageMenu(pos)\n        } else {\n            this.props.dismissContextMenu()\n        }\n    }\n\n    keyDownHandler = (input: Electron.Input) => {\n        if (input.type === \"keyDown\") {\n            switch (input.key) {\n                case \"Escape\":\n                    this.props.dismiss()\n                    break\n                case \"ArrowLeft\":\n                case \"ArrowRight\":\n                    this.props.offsetItem(input.key === \"ArrowLeft\" ? -1 : 1)\n                    break\n                case \"l\":\n                case \"L\":\n                    this.toggleWebpage()\n                    break\n                case \"w\":\n                case \"W\":\n                    this.toggleFull()\n                    break\n                case \"H\":\n                case \"h\":\n                    if (!input.meta) this.props.toggleHidden(this.props.item)\n                    break\n                default:\n                    const keyboardEvent = new KeyboardEvent(\"keydown\", {\n                        code: input.code,\n                        key: input.key,\n                        shiftKey: input.shift,\n                        altKey: input.alt,\n                        ctrlKey: input.control,\n                        metaKey: input.meta,\n                        repeat: input.isAutoRepeat,\n                        bubbles: true,\n                    })\n                    this.props.shortcuts(this.props.item, keyboardEvent)\n                    document.dispatchEvent(keyboardEvent)\n                    break\n            }\n        }\n    }\n\n    webviewLoaded = () => {\n        this.setState({ loaded: true })\n    }\n    webviewError = (reason: string) => {\n        this.setState({ error: true, errorDescription: reason })\n    }\n    webviewReload = () => {\n        if (this.webview) {\n            this.setState({ loaded: false, error: false })\n            this.webview.reload()\n        } else if (this.state.loadFull) {\n            this.loadFull()\n        }\n    }\n\n    componentDidMount = () => {\n        let webview = document.getElementById(\"article\") as Electron.WebviewTag\n        if (webview != this.webview) {\n            this.webview = webview\n            if (webview) {\n                webview.focus()\n                this.setState({ loaded: false, error: false })\n                webview.addEventListener(\"did-stop-loading\", this.webviewLoaded)\n                let card = document.querySelector(\n                    `#refocus div[data-iid=\"${this.props.item._id}\"]`\n                ) as HTMLElement\n                // @ts-ignore\n                if (card) card.scrollIntoViewIfNeeded()\n            }\n        }\n    }\n    componentDidUpdate = (prevProps: ArticleProps) => {\n        if (prevProps.item._id != this.props.item._id) {\n            this.setState({\n                loadWebpage:\n                    this.props.source.openTarget === SourceOpenTarget.Webpage,\n                loadFull:\n                    this.props.source.openTarget ===\n                    SourceOpenTarget.FullContent,\n            })\n            if (this.props.source.openTarget === SourceOpenTarget.FullContent)\n                this.loadFull()\n        }\n        this.componentDidMount()\n    }\n\n    componentWillUnmount = () => {\n        let refocus = document.querySelector(\n            `#refocus div[data-iid=\"${this.props.item._id}\"]`\n        ) as HTMLElement\n        if (refocus) refocus.focus()\n    }\n\n    toggleWebpage = () => {\n        if (this.state.loadWebpage) {\n            this.setState({ loadWebpage: false })\n        } else if (\n            this.props.item.link.startsWith(\"https://\") ||\n            this.props.item.link.startsWith(\"http://\")\n        ) {\n            this.setState({ loadWebpage: true, loadFull: false })\n        }\n    }\n\n    toggleFull = () => {\n        if (this.state.loadFull) {\n            this.setState({ loadFull: false })\n        } else if (\n            this.props.item.link.startsWith(\"https://\") ||\n            this.props.item.link.startsWith(\"http://\")\n        ) {\n            this.setState({ loadFull: true, loadWebpage: false })\n            this.loadFull()\n        }\n    }\n    loadFull = async () => {\n        this.setState({ fullContent: \"\", loaded: false, error: false })\n        const link = this.props.item.link\n        try {\n            const result = await fetch(link)\n            if (!result || !result.ok) throw new Error()\n            const html = await decodeFetchResponse(result, true)\n            if (link === this.props.item.link) {\n                this.setState({ fullContent: html })\n            }\n        } catch {\n            if (link === this.props.item.link) {\n                this.setState({\n                    loaded: true,\n                    error: true,\n                    errorDescription: \"MERCURY_PARSER_FAILURE\",\n                })\n            }\n        }\n    }\n\n    articleView = () => {\n        const a = encodeURIComponent(\n            this.state.loadFull\n                ? this.state.fullContent\n                : this.props.item.content\n        )\n        const h = encodeURIComponent(\n            renderToString(\n                <>\n                    <p className=\"title\">{this.props.item.title}</p>\n                    <p className=\"date\">\n                        {this.props.item.date.toLocaleString(\n                            this.props.locale,\n                            { hour12: !this.props.locale.startsWith(\"zh\") }\n                        )}\n                    </p>\n                    <article></article>\n                </>\n            )\n        )\n        return `article/article.html?a=${a}&h=${h}&f=${encodeURIComponent(\n            this.state.fontFamily\n        )}&s=${this.state.fontSize}&d=${this.props.source.textDir}&u=${\n            this.props.item.link\n        }&m=${this.state.loadFull ? 1 : 0}`\n    }\n\n    render = () => (\n        <FocusZone className=\"article\">\n            <Stack horizontal style={{ height: 36 }}>\n                <span style={{ width: 96 }}></span>\n                <Stack\n                    className=\"actions\"\n                    grow\n                    horizontal\n                    tokens={{ childrenGap: 12 }}>\n                    <Stack.Item grow>\n                        <span className=\"source-name\">\n                            {this.state.loaded ? (\n                                this.props.source.iconurl && (\n                                    <img\n                                        className=\"favicon\"\n                                        src={this.props.source.iconurl}\n                                    />\n                                )\n                            ) : (\n                                <Spinner size={1} />\n                            )}\n                            {this.props.source.name}\n                            {this.props.item.creator && (\n                                <span className=\"creator\">\n                                    {this.props.item.creator}\n                                </span>\n                            )}\n                        </span>\n                    </Stack.Item>\n                    <CommandBarButton\n                        title={\n                            this.props.item.hasRead\n                                ? intl.get(\"article.markUnread\")\n                                : intl.get(\"article.markRead\")\n                        }\n                        iconProps={\n                            this.props.item.hasRead\n                                ? { iconName: \"StatusCircleRing\" }\n                                : {\n                                      iconName: \"RadioBtnOn\",\n                                      style: {\n                                          fontSize: 14,\n                                          textAlign: \"center\",\n                                      },\n                                  }\n                        }\n                        onClick={() =>\n                            this.props.toggleHasRead(this.props.item)\n                        }\n                    />\n                    <CommandBarButton\n                        title={\n                            this.props.item.starred\n                                ? intl.get(\"article.unstar\")\n                                : intl.get(\"article.star\")\n                        }\n                        iconProps={{\n                            iconName: this.props.item.starred\n                                ? \"FavoriteStarFill\"\n                                : \"FavoriteStar\",\n                        }}\n                        onClick={() =>\n                            this.props.toggleStarred(this.props.item)\n                        }\n                    />\n                    <CommandBarButton\n                        title={intl.get(\"article.loadFull\")}\n                        className={this.state.loadFull ? \"active\" : \"\"}\n                        iconProps={{ iconName: \"RawSource\" }}\n                        onClick={this.toggleFull}\n                    />\n                    <CommandBarButton\n                        title={intl.get(\"article.loadWebpage\")}\n                        className={this.state.loadWebpage ? \"active\" : \"\"}\n                        iconProps={{ iconName: \"Globe\" }}\n                        onClick={this.toggleWebpage}\n                    />\n                    <CommandBarButton\n                        title={intl.get(\"more\")}\n                        iconProps={{ iconName: \"More\" }}\n                        menuIconProps={{ style: { display: \"none\" } }}\n                        menuProps={this.moreMenuProps()}\n                    />\n                </Stack>\n                <Stack horizontal horizontalAlign=\"end\" style={{ width: 112 }}>\n                    <CommandBarButton\n                        title={intl.get(\"close\")}\n                        iconProps={{ iconName: \"BackToWindow\" }}\n                        onClick={this.props.dismiss}\n                    />\n                </Stack>\n            </Stack>\n            {(!this.state.loadFull || this.state.fullContent) && (\n                <webview\n                    id=\"article\"\n                    className={this.state.error ? \"error\" : \"\"}\n                    key={\n                        this.props.item._id +\n                        (this.state.loadWebpage ? \"_\" : \"\") +\n                        (this.state.loadFull ? \"__\" : \"\")\n                    }\n                    src={\n                        this.state.loadWebpage\n                            ? this.props.item.link\n                            : this.articleView()\n                    }\n                    allowpopups={\"true\" as unknown as boolean}\n                    webpreferences=\"contextIsolation,disableDialogs,autoplayPolicy=document-user-activation-required\"\n                    partition={this.state.loadWebpage ? \"sandbox\" : undefined}\n                />\n            )}\n            {this.state.error && (\n                <Stack\n                    className=\"error-prompt\"\n                    verticalAlign=\"center\"\n                    horizontalAlign=\"center\"\n                    tokens={{ childrenGap: 12 }}>\n                    <Icon iconName=\"HeartBroken\" style={{ fontSize: 32 }} />\n                    <Stack\n                        horizontal\n                        horizontalAlign=\"center\"\n                        tokens={{ childrenGap: 7 }}>\n                        <small>{intl.get(\"article.error\")}</small>\n                        <small>\n                            <Link onClick={this.webviewReload}>\n                                {intl.get(\"article.reload\")}\n                            </Link>\n                        </small>\n                    </Stack>\n                    <span style={{ fontSize: 11 }}>\n                        {this.state.errorDescription}\n                    </span>\n                </Stack>\n            )}\n        </FocusZone>\n    )\n}\n\nexport default Article\n"
  },
  {
    "path": "src/components/cards/card.tsx",
    "content": "import * as React from \"react\"\nimport { RSSSource, SourceOpenTarget } from \"../../scripts/models/source\"\nimport { RSSItem } from \"../../scripts/models/item\"\nimport { platformCtrl } from \"../../scripts/utils\"\nimport { FeedFilter } from \"../../scripts/models/feed\"\nimport { ViewConfigs } from \"../../schema-types\"\n\nexport namespace Card {\n    export type Props = {\n        feedId: string\n        item: RSSItem\n        source: RSSSource\n        filter: FeedFilter\n        selected?: boolean\n        viewConfigs?: ViewConfigs\n        shortcuts: (item: RSSItem, e: KeyboardEvent) => void\n        markRead: (item: RSSItem) => void\n        contextMenu: (feedId: string, item: RSSItem, e) => void\n        showItem: (fid: string, item: RSSItem) => void\n    }\n\n    const openInBrowser = (props: Props, e: React.MouseEvent) => {\n        props.markRead(props.item)\n        window.utils.openExternal(props.item.link, platformCtrl(e))\n    }\n\n    export const bindEventsToProps = (props: Props) => ({\n        onClick: (e: React.MouseEvent) => onClick(props, e),\n        onMouseUp: (e: React.MouseEvent) => onMouseUp(props, e),\n        onKeyDown: (e: React.KeyboardEvent) => onKeyDown(props, e),\n    })\n\n    const onClick = (props: Props, e: React.MouseEvent) => {\n        e.preventDefault()\n        e.stopPropagation()\n        switch (props.source.openTarget) {\n            case SourceOpenTarget.External: {\n                openInBrowser(props, e)\n                break\n            }\n            default: {\n                props.markRead(props.item)\n                props.showItem(props.feedId, props.item)\n                break\n            }\n        }\n    }\n\n    const onMouseUp = (props: Props, e: React.MouseEvent) => {\n        e.preventDefault()\n        e.stopPropagation()\n        switch (e.button) {\n            case 1:\n                openInBrowser(props, e)\n                break\n            case 2:\n                props.contextMenu(props.feedId, props.item, e)\n        }\n    }\n\n    const onKeyDown = (props: Props, e: React.KeyboardEvent) => {\n        props.shortcuts(props.item, e.nativeEvent)\n    }\n}\n"
  },
  {
    "path": "src/components/cards/compact-card.tsx",
    "content": "import * as React from \"react\"\nimport { Card } from \"./card\"\nimport CardInfo from \"./info\"\nimport Time from \"../utils/time\"\nimport Highlights from \"./highlights\"\nimport { SourceTextDirection } from \"../../scripts/models/source\"\n\nconst className = (props: Card.Props) => {\n    let cn = [\"card\", \"compact-card\"]\n    if (props.item.hidden) cn.push(\"hidden\")\n    if (props.source.textDir === SourceTextDirection.RTL) cn.push(\"rtl\")\n    return cn.join(\" \")\n}\n\nconst CompactCard: React.FunctionComponent<Card.Props> = props => (\n    <div\n        className={className(props)}\n        {...Card.bindEventsToProps(props)}\n        data-iid={props.item._id}\n        data-is-focusable>\n        <CardInfo source={props.source} item={props.item} hideTime />\n        <div className=\"data\">\n            <span className=\"title\">\n                <Highlights\n                    text={props.item.title}\n                    filter={props.filter}\n                    title\n                />\n            </span>\n            <span className=\"snippet\">\n                <Highlights text={props.item.snippet} filter={props.filter} />\n            </span>\n        </div>\n        <Time date={props.item.date} />\n    </div>\n)\n\nexport default CompactCard\n"
  },
  {
    "path": "src/components/cards/default-card.tsx",
    "content": "import * as React from \"react\"\nimport { Card } from \"./card\"\nimport CardInfo from \"./info\"\nimport Highlights from \"./highlights\"\nimport { SourceTextDirection } from \"../../scripts/models/source\"\n\nconst className = (props: Card.Props) => {\n    let cn = [\"card\", \"default-card\"]\n    if (props.item.snippet && props.item.thumb) cn.push(\"transform\")\n    if (props.item.hidden) cn.push(\"hidden\")\n    if (props.source.textDir === SourceTextDirection.RTL) cn.push(\"rtl\")\n    return cn.join(\" \")\n}\n\nconst DefaultCard: React.FunctionComponent<Card.Props> = props => (\n    <div\n        className={className(props)}\n        {...Card.bindEventsToProps(props)}\n        data-iid={props.item._id}\n        data-is-focusable>\n        {props.item.thumb ? (\n            <img className=\"bg\" src={props.item.thumb} />\n        ) : null}\n        <div className=\"bg\"></div>\n        {props.item.thumb ? (\n            <img className=\"head\" src={props.item.thumb} />\n        ) : null}\n        <CardInfo source={props.source} item={props.item} />\n        <h3 className=\"title\">\n            <Highlights text={props.item.title} filter={props.filter} title />\n        </h3>\n        <p className={\"snippet\" + (props.item.thumb ? \"\" : \" show\")}>\n            <Highlights text={props.item.snippet} filter={props.filter} />\n        </p>\n    </div>\n)\n\nexport default DefaultCard\n"
  },
  {
    "path": "src/components/cards/highlights.tsx",
    "content": "import * as React from \"react\"\nimport { validateRegex } from \"../../scripts/utils\"\nimport { FeedFilter, FilterType } from \"../../scripts/models/feed\"\nimport { SourceTextDirection } from \"../../scripts/models/source\"\n\ntype HighlightsProps = {\n    text: string\n    filter: FeedFilter\n    title?: boolean\n}\n\nconst Highlights: React.FunctionComponent<HighlightsProps> = props => {\n    const spans: [string, boolean][] = new Array()\n    const flags = props.filter.type & FilterType.CaseInsensitive ? \"ig\" : \"g\"\n    let regex: RegExp\n    if (\n        props.filter.search === \"\" ||\n        !(regex = validateRegex(props.filter.search, flags))\n    ) {\n        if (props.title) spans.push([props.text, false])\n        else spans.push([props.text.substr(0, 325), false])\n    } else if (props.title) {\n        let match: RegExpExecArray\n        do {\n            const startIndex = regex.lastIndex\n            match = regex.exec(props.text)\n            if (match) {\n                if (startIndex != match.index) {\n                    spans.push([\n                        props.text.substring(startIndex, match.index),\n                        false,\n                    ])\n                }\n                spans.push([match[0], true])\n            } else {\n                spans.push([props.text.substr(startIndex), false])\n            }\n        } while (match && regex.lastIndex < props.text.length)\n    } else {\n        const match = regex.exec(props.text)\n        if (match) {\n            if (match.index != 0) {\n                const startIndex = Math.max(\n                    match.index - 25,\n                    props.text.lastIndexOf(\" \", Math.max(match.index - 10, 0))\n                )\n                spans.push([\n                    props.text.substring(Math.max(0, startIndex), match.index),\n                    false,\n                ])\n            }\n            spans.push([match[0], true])\n            if (regex.lastIndex < props.text.length) {\n                spans.push([props.text.substr(regex.lastIndex, 300), false])\n            }\n        } else {\n            spans.push([props.text.substr(0, 325), false])\n        }\n    }\n\n    return (\n        <>\n            {spans.map(([text, flag]) =>\n                flag ? <span className=\"h\">{text}</span> : text\n            )}\n        </>\n    )\n}\n\nexport default Highlights\n"
  },
  {
    "path": "src/components/cards/info.tsx",
    "content": "import * as React from \"react\"\nimport Time from \"../utils/time\"\nimport { RSSSource } from \"../../scripts/models/source\"\nimport { RSSItem } from \"../../scripts/models/item\"\n\ntype CardInfoProps = {\n    source: RSSSource\n    item: RSSItem\n    hideTime?: boolean\n    showCreator?: boolean\n}\n\nconst CardInfo: React.FunctionComponent<CardInfoProps> = props => (\n    <p className=\"info\">\n        {props.source.iconurl ? <img src={props.source.iconurl} /> : null}\n        <span className=\"name\">\n            {props.source.name}\n            {props.showCreator && props.item.creator && (\n                <span className=\"creator\">{props.item.creator}</span>\n            )}\n        </span>\n        {props.item.starred ? (\n            <span className=\"starred-indicator\"></span>\n        ) : null}\n        {props.item.hasRead ? null : <span className=\"read-indicator\"></span>}\n        {props.hideTime ? null : <Time date={props.item.date} />}\n    </p>\n)\n\nexport default CardInfo\n"
  },
  {
    "path": "src/components/cards/list-card.tsx",
    "content": "import * as React from \"react\"\nimport { Card } from \"./card\"\nimport CardInfo from \"./info\"\nimport Highlights from \"./highlights\"\nimport { ViewConfigs } from \"../../schema-types\"\nimport { SourceTextDirection } from \"../../scripts/models/source\"\n\nconst className = (props: Card.Props) => {\n    let cn = [\"card\", \"list-card\"]\n    if (props.item.hidden) cn.push(\"hidden\")\n    if (props.selected) cn.push(\"selected\")\n    if (props.viewConfigs & ViewConfigs.FadeRead && props.item.hasRead)\n        cn.push(\"read\")\n    if (props.source.textDir === SourceTextDirection.RTL) cn.push(\"rtl\")\n    return cn.join(\" \")\n}\n\nconst ListCard: React.FunctionComponent<Card.Props> = props => (\n    <div\n        className={className(props)}\n        {...Card.bindEventsToProps(props)}\n        data-iid={props.item._id}\n        data-is-focusable>\n        {props.item.thumb && props.viewConfigs & ViewConfigs.ShowCover ? (\n            <div className=\"head\">\n                <img src={props.item.thumb} />\n            </div>\n        ) : null}\n        <div className=\"data\">\n            <CardInfo source={props.source} item={props.item} />\n            <h3 className=\"title\">\n                <Highlights\n                    text={props.item.title}\n                    filter={props.filter}\n                    title\n                />\n            </h3>\n            {Boolean(props.viewConfigs & ViewConfigs.ShowSnippet) && (\n                <p className=\"snippet\">\n                    <Highlights\n                        text={props.item.snippet}\n                        filter={props.filter}\n                    />\n                </p>\n            )}\n        </div>\n    </div>\n)\n\nexport default ListCard\n"
  },
  {
    "path": "src/components/cards/magazine-card.tsx",
    "content": "import * as React from \"react\"\nimport { Card } from \"./card\"\nimport CardInfo from \"./info\"\nimport Highlights from \"./highlights\"\nimport { SourceTextDirection } from \"../../scripts/models/source\"\n\nconst className = (props: Card.Props) => {\n    let cn = [\"card\", \"magazine-card\"]\n    if (props.item.hasRead) cn.push(\"read\")\n    if (props.item.hidden) cn.push(\"hidden\")\n    if (props.source.textDir === SourceTextDirection.RTL) cn.push(\"rtl\")\n    return cn.join(\" \")\n}\n\nconst MagazineCard: React.FunctionComponent<Card.Props> = props => (\n    <div\n        className={className(props)}\n        {...Card.bindEventsToProps(props)}\n        data-iid={props.item._id}\n        data-is-focusable>\n        {props.item.thumb ? (\n            <div className=\"head\">\n                <img src={props.item.thumb} />\n            </div>\n        ) : null}\n        <div className=\"data\">\n            <div>\n                <h3 className=\"title\">\n                    <Highlights\n                        text={props.item.title}\n                        filter={props.filter}\n                        title\n                    />\n                </h3>\n                <p className=\"snippet\">\n                    <Highlights\n                        text={props.item.snippet}\n                        filter={props.filter}\n                    />\n                </p>\n            </div>\n            <CardInfo source={props.source} item={props.item} showCreator />\n        </div>\n    </div>\n)\n\nexport default MagazineCard\n"
  },
  {
    "path": "src/components/context-menu.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport QRCode from \"qrcode.react\"\nimport {\n    cutText,\n    webSearch,\n    getSearchEngineName,\n    platformCtrl,\n} from \"../scripts/utils\"\nimport {\n    ContextualMenu,\n    IContextualMenuItem,\n    ContextualMenuItemType,\n    DirectionalHint,\n} from \"office-ui-fabric-react/lib/ContextualMenu\"\nimport { closeContextMenu, ContextMenuType } from \"../scripts/models/app\"\nimport {\n    markAllRead,\n    markRead,\n    markUnread,\n    RSSItem,\n    toggleHidden,\n    toggleStarred,\n} from \"../scripts/models/item\"\nimport { ViewType, ImageCallbackTypes, ViewConfigs } from \"../schema-types\"\nimport { FilterType } from \"../scripts/models/feed\"\nimport { useAppDispatch, useAppSelector } from \"../scripts/reducer\"\nimport {\n    setViewConfigs,\n    showItem,\n    switchFilter,\n    switchView,\n    toggleFilter,\n} from \"../scripts/models/page\"\n\nexport const shareSubmenu = (item: RSSItem): IContextualMenuItem[] => [\n    { key: \"qr\", url: item.link, onRender: renderShareQR },\n]\n\nexport const renderShareQR = (item: IContextualMenuItem) => (\n    <div className=\"qr-container\">\n        <QRCode value={item.url} size={150} renderAs=\"svg\" />\n    </div>\n)\n\nfunction getSearchItem(text: string): IContextualMenuItem {\n    const engine = window.settings.getSearchEngine()\n    return {\n        key: \"searchText\",\n        text: intl.get(\"context.search\", {\n            text: cutText(text, 15),\n            engine: getSearchEngineName(engine),\n        }),\n        iconProps: { iconName: \"Search\" },\n        onClick: () => webSearch(text, engine),\n    }\n}\n\nexport function ContextMenu() {\n    const { type } = useAppSelector(state => state.app.contextMenu)\n\n    switch (type) {\n        case ContextMenuType.Hidden:\n            return null\n        case ContextMenuType.Item:\n            return <ItemContextMenu />\n        case ContextMenuType.Text:\n            return <TextContextMenu />\n        case ContextMenuType.Image:\n            return <ImageContextMenu />\n        case ContextMenuType.View:\n            return <ViewContextMenu />\n        case ContextMenuType.Group:\n            return <GroupContextMenu />\n        case ContextMenuType.MarkRead:\n            return <MarkReadContextMenu />\n    }\n}\n\nfunction ItemContextMenu() {\n    const dispatch = useAppDispatch()\n    const viewConfigs = useAppSelector(state => state.page.viewConfigs)\n    const target = useAppSelector(state => state.app.contextMenu.target)\n    const item = target[0] as RSSItem\n    const feedId = target[1] as string\n\n    const menuItems: IContextualMenuItem[] = [\n        {\n            key: \"showItem\",\n            text: intl.get(\"context.read\"),\n            iconProps: { iconName: \"TextDocument\" },\n            onClick: () => {\n                dispatch(markRead(item))\n                dispatch(showItem(feedId, item))\n            },\n        },\n        {\n            key: \"openInBrowser\",\n            text: intl.get(\"openExternal\"),\n            iconProps: { iconName: \"NavigateExternalInline\" },\n            onClick: e => {\n                dispatch(markRead(item))\n                window.utils.openExternal(item.link, platformCtrl(e))\n            },\n        },\n        {\n            key: \"markAsRead\",\n            text: item.hasRead\n                ? intl.get(\"article.markUnread\")\n                : intl.get(\"article.markRead\"),\n            iconProps: item.hasRead\n                ? {\n                      iconName: \"RadioBtnOn\",\n                      style: { fontSize: 14, textAlign: \"center\" },\n                  }\n                : { iconName: \"StatusCircleRing\" },\n            onClick: () => {\n                if (item.hasRead) {\n                    dispatch(markUnread(item))\n                } else {\n                    dispatch(markRead(item))\n                }\n            },\n            split: true,\n            subMenuProps: {\n                items: [\n                    {\n                        key: \"markBelow\",\n                        text: intl.get(\"article.markBelow\"),\n                        iconProps: {\n                            iconName: \"Down\",\n                            style: { fontSize: 14 },\n                        },\n                        onClick: () => {\n                            dispatch(markAllRead(null, item.date))\n                        },\n                    },\n                    {\n                        key: \"markAbove\",\n                        text: intl.get(\"article.markAbove\"),\n                        iconProps: {\n                            iconName: \"Up\",\n                            style: { fontSize: 14 },\n                        },\n                        onClick: () => {\n                            dispatch(markAllRead(null, item.date, false))\n                        },\n                    },\n                ],\n            },\n        },\n        {\n            key: \"toggleStarred\",\n            text: item.starred\n                ? intl.get(\"article.unstar\")\n                : intl.get(\"article.star\"),\n            iconProps: {\n                iconName: item.starred ? \"FavoriteStar\" : \"FavoriteStarFill\",\n            },\n            onClick: () => {\n                dispatch(toggleStarred(item))\n            },\n        },\n        {\n            key: \"toggleHidden\",\n            text: item.hidden\n                ? intl.get(\"article.unhide\")\n                : intl.get(\"article.hide\"),\n            iconProps: {\n                iconName: item.hidden ? \"View\" : \"Hide3\",\n            },\n            onClick: () => {\n                dispatch(toggleHidden(item))\n            },\n        },\n        {\n            key: \"divider_1\",\n            itemType: ContextualMenuItemType.Divider,\n        },\n        {\n            key: \"share\",\n            text: intl.get(\"context.share\"),\n            iconProps: { iconName: \"Share\" },\n            subMenuProps: {\n                items: shareSubmenu(item),\n            },\n        },\n        {\n            key: \"copyTitle\",\n            text: intl.get(\"context.copyTitle\"),\n            onClick: () => {\n                window.utils.writeClipboard(item.title)\n            },\n        },\n        {\n            key: \"copyURL\",\n            text: intl.get(\"context.copyURL\"),\n            onClick: () => {\n                window.utils.writeClipboard(item.link)\n            },\n        },\n        ...(viewConfigs !== undefined\n            ? [\n                  {\n                      key: \"divider_2\",\n                      itemType: ContextualMenuItemType.Divider,\n                  },\n                  {\n                      key: \"view\",\n                      text: intl.get(\"context.view\"),\n                      subMenuProps: {\n                          items: [\n                              {\n                                  key: \"showCover\",\n                                  text: intl.get(\"context.showCover\"),\n                                  canCheck: true,\n                                  checked: Boolean(\n                                      viewConfigs & ViewConfigs.ShowCover\n                                  ),\n                                  onClick: () =>\n                                      dispatch(\n                                          setViewConfigs(\n                                              viewConfigs ^\n                                                  ViewConfigs.ShowCover\n                                          )\n                                      ),\n                              },\n                              {\n                                  key: \"showSnippet\",\n                                  text: intl.get(\"context.showSnippet\"),\n                                  canCheck: true,\n                                  checked: Boolean(\n                                      viewConfigs & ViewConfigs.ShowSnippet\n                                  ),\n                                  onClick: () =>\n                                      dispatch(\n                                          setViewConfigs(\n                                              viewConfigs ^\n                                                  ViewConfigs.ShowSnippet\n                                          )\n                                      ),\n                              },\n                              {\n                                  key: \"fadeRead\",\n                                  text: intl.get(\"context.fadeRead\"),\n                                  canCheck: true,\n                                  checked: Boolean(\n                                      viewConfigs & ViewConfigs.FadeRead\n                                  ),\n                                  onClick: () =>\n                                      dispatch(\n                                          setViewConfigs(\n                                              viewConfigs ^ ViewConfigs.FadeRead\n                                          )\n                                      ),\n                              },\n                          ],\n                      },\n                  },\n              ]\n            : []),\n    ]\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction TextContextMenu() {\n    const target = useAppSelector(state => state.app.contextMenu.target) as [\n        string,\n        string\n    ]\n    const text = target[0]\n    const url = target[1]\n    const menuItems: IContextualMenuItem[] = text\n        ? [\n              {\n                  key: \"copyText\",\n                  text: intl.get(\"context.copy\"),\n                  iconProps: { iconName: \"Copy\" },\n                  onClick: () => {\n                      window.utils.writeClipboard(text)\n                  },\n              },\n              getSearchItem(text),\n          ]\n        : []\n    if (url) {\n        menuItems.push({\n            key: \"urlSection\",\n            itemType: ContextualMenuItemType.Section,\n            sectionProps: {\n                topDivider: menuItems.length > 0,\n                items: [\n                    {\n                        key: \"openInBrowser\",\n                        text: intl.get(\"openExternal\"),\n                        iconProps: {\n                            iconName: \"NavigateExternalInline\",\n                        },\n                        onClick: e => {\n                            window.utils.openExternal(url, platformCtrl(e))\n                        },\n                    },\n                    {\n                        key: \"copyURL\",\n                        text: intl.get(\"context.copyURL\"),\n                        iconProps: { iconName: \"Link\" },\n                        onClick: () => {\n                            window.utils.writeClipboard(url)\n                        },\n                    },\n                ],\n            },\n        })\n    }\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction ImageContextMenu() {\n    const menuItems: IContextualMenuItem[] = [\n        {\n            key: \"openInBrowser\",\n            text: intl.get(\"openExternal\"),\n            iconProps: { iconName: \"NavigateExternalInline\" },\n            onClick: e => {\n                if (platformCtrl(e)) {\n                    window.utils.imageCallback(\n                        ImageCallbackTypes.OpenExternalBg\n                    )\n                } else {\n                    window.utils.imageCallback(ImageCallbackTypes.OpenExternal)\n                }\n            },\n        },\n        {\n            key: \"saveImageAs\",\n            text: intl.get(\"context.saveImageAs\"),\n            iconProps: { iconName: \"SaveTemplate\" },\n            onClick: () => {\n                window.utils.imageCallback(ImageCallbackTypes.SaveAs)\n            },\n        },\n        {\n            key: \"copyImage\",\n            text: intl.get(\"context.copyImage\"),\n            iconProps: { iconName: \"FileImage\" },\n            onClick: () => {\n                window.utils.imageCallback(ImageCallbackTypes.Copy)\n            },\n        },\n        {\n            key: \"copyImageURL\",\n            text: intl.get(\"context.copyImageURL\"),\n            iconProps: { iconName: \"Link\" },\n            onClick: () => {\n                window.utils.imageCallback(ImageCallbackTypes.CopyLink)\n            },\n        },\n    ]\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction ViewContextMenu() {\n    const dispatch = useAppDispatch()\n    const viewType = useAppSelector(state => state.page.viewType)\n    const filter = useAppSelector(state => state.page.filter.type)\n\n    const menuItems: IContextualMenuItem[] = [\n        {\n            key: \"section_1\",\n            itemType: ContextualMenuItemType.Section,\n            sectionProps: {\n                title: intl.get(\"context.view\"),\n                bottomDivider: true,\n                items: [\n                    {\n                        key: \"cardView\",\n                        text: intl.get(\"context.cardView\"),\n                        iconProps: { iconName: \"GridViewMedium\" },\n                        canCheck: true,\n                        checked: viewType === ViewType.Cards,\n                        onClick: () => dispatch(switchView(ViewType.Cards)),\n                    },\n                    {\n                        key: \"listView\",\n                        text: intl.get(\"context.listView\"),\n                        iconProps: { iconName: \"BacklogList\" },\n                        canCheck: true,\n                        checked: viewType === ViewType.List,\n                        onClick: () => dispatch(switchView(ViewType.List)),\n                    },\n                    {\n                        key: \"magazineView\",\n                        text: intl.get(\"context.magazineView\"),\n                        iconProps: { iconName: \"Articles\" },\n                        canCheck: true,\n                        checked: viewType === ViewType.Magazine,\n                        onClick: () => dispatch(switchView(ViewType.Magazine)),\n                    },\n                    {\n                        key: \"compactView\",\n                        text: intl.get(\"context.compactView\"),\n                        iconProps: { iconName: \"BulletedList\" },\n                        canCheck: true,\n                        checked: viewType === ViewType.Compact,\n                        onClick: () => dispatch(switchView(ViewType.Compact)),\n                    },\n                ],\n            },\n        },\n        {\n            key: \"section_2\",\n            itemType: ContextualMenuItemType.Section,\n            sectionProps: {\n                title: intl.get(\"context.filter\"),\n                bottomDivider: true,\n                items: [\n                    {\n                        key: \"allArticles\",\n                        text: intl.get(\"allArticles\"),\n                        iconProps: { iconName: \"ClearFilter\" },\n                        canCheck: true,\n                        checked:\n                            (filter & ~FilterType.Toggles) ==\n                            FilterType.Default,\n                        onClick: () =>\n                            dispatch(switchFilter(FilterType.Default)),\n                    },\n                    {\n                        key: \"unreadOnly\",\n                        text: intl.get(\"context.unreadOnly\"),\n                        iconProps: {\n                            iconName: \"RadioBtnOn\",\n                            style: {\n                                fontSize: 14,\n                                textAlign: \"center\",\n                            },\n                        },\n                        canCheck: true,\n                        checked:\n                            (filter & ~FilterType.Toggles) ==\n                            FilterType.UnreadOnly,\n                        onClick: () =>\n                            dispatch(switchFilter(FilterType.UnreadOnly)),\n                    },\n                    {\n                        key: \"starredOnly\",\n                        text: intl.get(\"context.starredOnly\"),\n                        iconProps: { iconName: \"FavoriteStarFill\" },\n                        canCheck: true,\n                        checked:\n                            (filter & ~FilterType.Toggles) ==\n                            FilterType.StarredOnly,\n                        onClick: () =>\n                            dispatch(switchFilter(FilterType.StarredOnly)),\n                    },\n                ],\n            },\n        },\n        {\n            key: \"section_3\",\n            itemType: ContextualMenuItemType.Section,\n            sectionProps: {\n                title: intl.get(\"search\"),\n                bottomDivider: true,\n                items: [\n                    {\n                        key: \"caseSensitive\",\n                        text: intl.get(\"context.caseSensitive\"),\n                        iconProps: {\n                            style: {\n                                fontSize: 12,\n                                fontStyle: \"normal\",\n                            },\n                            children: \"Aa\",\n                        },\n                        canCheck: true,\n                        checked: !(filter & FilterType.CaseInsensitive),\n                        onClick: () =>\n                            dispatch(toggleFilter(FilterType.CaseInsensitive)),\n                    },\n                    {\n                        key: \"fullSearch\",\n                        text: intl.get(\"context.fullSearch\"),\n                        iconProps: { iconName: \"Breadcrumb\" },\n                        canCheck: true,\n                        checked: Boolean(filter & FilterType.FullSearch),\n                        onClick: () =>\n                            dispatch(toggleFilter(FilterType.FullSearch)),\n                    },\n                ],\n            },\n        },\n        {\n            key: \"showHidden\",\n            text: intl.get(\"context.showHidden\"),\n            canCheck: true,\n            checked: Boolean(filter & FilterType.ShowHidden),\n            onClick: () => dispatch(toggleFilter(FilterType.ShowHidden)),\n        },\n    ]\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction GroupContextMenu() {\n    const dispatch = useAppDispatch()\n    const sids = useAppSelector(\n        state => state.app.contextMenu.target\n    ) as number[]\n\n    const menuItems: IContextualMenuItem[] = [\n        {\n            key: \"markAllRead\",\n            text: intl.get(\"nav.markAllRead\"),\n            iconProps: { iconName: \"CheckMark\" },\n            onClick: () => {\n                dispatch(markAllRead(sids))\n            },\n        },\n        {\n            key: \"refresh\",\n            text: intl.get(\"nav.refresh\"),\n            iconProps: { iconName: \"Sync\" },\n            onClick: () => {\n                dispatch(markAllRead(sids))\n            },\n        },\n        {\n            key: \"manage\",\n            text: intl.get(\"context.manageSources\"),\n            iconProps: { iconName: \"Settings\" },\n            onClick: () => {\n                dispatch(markAllRead(sids))\n            },\n        },\n    ]\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction MarkReadContextMenu() {\n    const dispatch = useAppDispatch()\n\n    const menuItems: IContextualMenuItem[] = [\n        {\n            key: \"section_1\",\n            itemType: ContextualMenuItemType.Section,\n            sectionProps: {\n                title: intl.get(\"nav.markAllRead\"),\n                items: [\n                    {\n                        key: \"all\",\n                        text: intl.get(\"allArticles\"),\n                        iconProps: { iconName: \"ReceiptCheck\" },\n                        onClick: () => {\n                            dispatch(markAllRead())\n                        },\n                    },\n                    {\n                        key: \"1d\",\n                        text: intl.get(\"app.daysAgo\", { days: 1 }),\n                        onClick: () => {\n                            let date = new Date()\n                            date.setTime(date.getTime() - 86400000)\n                            dispatch(markAllRead(null, date))\n                        },\n                    },\n                    {\n                        key: \"3d\",\n                        text: intl.get(\"app.daysAgo\", { days: 3 }),\n                        onClick: () => {\n                            let date = new Date()\n                            date.setTime(date.getTime() - 3 * 86400000)\n                            dispatch(markAllRead(null, date))\n                        },\n                    },\n                    {\n                        key: \"7d\",\n                        text: intl.get(\"app.daysAgo\", { days: 7 }),\n                        onClick: () => {\n                            let date = new Date()\n                            date.setTime(date.getTime() - 7 * 86400000)\n                            dispatch(markAllRead(null, date))\n                        },\n                    },\n                ],\n            },\n        },\n    ]\n    return <ContextMenuBase menuItems={menuItems} />\n}\n\nfunction ContextMenuBase({\n    menuItems,\n}: Readonly<{ menuItems: IContextualMenuItem[] }>) {\n    const { event, position } = useAppSelector(state => state.app.contextMenu)\n    const dispatch = useAppDispatch()\n\n    return (\n        <ContextualMenu\n            directionalHint={DirectionalHint.bottomLeftEdge}\n            items={menuItems}\n            target={\n                event ||\n                (position && {\n                    left: position[0],\n                    top: position[1],\n                })\n            }\n            onDismiss={() => dispatch(closeContextMenu())}\n        />\n    )\n}\n"
  },
  {
    "path": "src/components/feeds/cards-feed.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { FeedProps } from \"./feed\"\nimport DefaultCard from \"../cards/default-card\"\nimport { PrimaryButton, FocusZone } from \"office-ui-fabric-react\"\nimport { RSSItem } from \"../../scripts/models/item\"\nimport { List, AnimationClassNames } from \"@fluentui/react\"\n\nclass CardsFeed extends React.Component<FeedProps> {\n    observer: ResizeObserver\n    state = { width: window.innerWidth, height: window.innerHeight }\n\n    updateWindowSize = (entries: ResizeObserverEntry[]) => {\n        if (entries) {\n            this.setState({\n                width: entries[0].contentRect.width - 40,\n                height: window.innerHeight,\n            })\n        }\n    }\n\n    componentDidMount() {\n        this.setState({\n            width: document.querySelector(\".main\").clientWidth - 40,\n        })\n        this.observer = new ResizeObserver(this.updateWindowSize)\n        this.observer.observe(document.querySelector(\".main\"))\n    }\n    componentWillUnmount() {\n        this.observer.disconnect()\n    }\n\n    getItemCountForPage = () => {\n        let elemPerRow = Math.floor(this.state.width / 280)\n        let rows = Math.ceil(this.state.height / 304)\n        return elemPerRow * rows\n    }\n    getPageHeight = () => {\n        return this.state.height + (304 - (this.state.height % 304))\n    }\n\n    flexFixItems = () => {\n        let elemPerRow = Math.floor(this.state.width / 280)\n        let elemLastRow = this.props.items.length % elemPerRow\n        let items = [...this.props.items]\n        for (let i = 0; i < elemPerRow - elemLastRow; i += 1) items.push(null)\n        return items\n    }\n    onRenderItem = (item: RSSItem, index: number) =>\n        item ? (\n            <DefaultCard\n                feedId={this.props.feed._id}\n                key={item._id}\n                item={item}\n                source={this.props.sourceMap[item.source]}\n                filter={this.props.filter}\n                shortcuts={this.props.shortcuts}\n                markRead={this.props.markRead}\n                contextMenu={this.props.contextMenu}\n                showItem={this.props.showItem}\n            />\n        ) : (\n            <div className=\"flex-fix\" key={\"f-\" + index}></div>\n        )\n\n    canFocusChild = (el: HTMLElement) => {\n        if (el.id === \"load-more\") {\n            const container = document.getElementById(\"refocus\")\n            const result =\n                container.scrollTop >\n                container.scrollHeight - 2 * container.offsetHeight\n            if (!result) container.scrollTop += 100\n            return result\n        } else {\n            return true\n        }\n    }\n\n    render() {\n        return (\n            this.props.feed.loaded && (\n                <FocusZone\n                    as=\"div\"\n                    id=\"refocus\"\n                    className=\"cards-feed-container\"\n                    shouldReceiveFocus={this.canFocusChild}\n                    data-is-scrollable>\n                    <List\n                        className={AnimationClassNames.slideUpIn10}\n                        items={this.flexFixItems()}\n                        onRenderCell={this.onRenderItem}\n                        getItemCountForPage={this.getItemCountForPage}\n                        getPageHeight={this.getPageHeight}\n                        ignoreScrollingState\n                        usePageCache\n                    />\n                    {this.props.feed.loaded && !this.props.feed.allLoaded ? (\n                        <div className=\"load-more-wrapper\">\n                            <PrimaryButton\n                                id=\"load-more\"\n                                text={intl.get(\"loadMore\")}\n                                disabled={this.props.feed.loading}\n                                onClick={() =>\n                                    this.props.loadMore(this.props.feed)\n                                }\n                            />\n                        </div>\n                    ) : null}\n                    {this.props.items.length === 0 && (\n                        <div className=\"empty\">{intl.get(\"article.empty\")}</div>\n                    )}\n                </FocusZone>\n            )\n        )\n    }\n}\n\nexport default CardsFeed\n"
  },
  {
    "path": "src/components/feeds/feed.tsx",
    "content": "import * as React from \"react\"\nimport { RSSItem } from \"../../scripts/models/item\"\nimport { FeedReduxProps } from \"../../containers/feed-container\"\nimport { RSSFeed, FeedFilter } from \"../../scripts/models/feed\"\nimport { ViewType, ViewConfigs } from \"../../schema-types\"\nimport CardsFeed from \"./cards-feed\"\nimport ListFeed from \"./list-feed\"\n\nexport type FeedProps = FeedReduxProps & {\n    feed: RSSFeed\n    viewType: ViewType\n    viewConfigs?: ViewConfigs\n    items: RSSItem[]\n    currentItem: number\n    sourceMap: Object\n    filter: FeedFilter\n    shortcuts: (item: RSSItem, e: KeyboardEvent) => void\n    markRead: (item: RSSItem) => void\n    contextMenu: (feedId: string, item: RSSItem, e) => void\n    loadMore: (feed: RSSFeed) => void\n    showItem: (fid: string, item: RSSItem) => void\n}\n\nexport class Feed extends React.Component<FeedProps> {\n    render() {\n        switch (this.props.viewType) {\n            case ViewType.Cards:\n                return <CardsFeed {...this.props} />\n            case ViewType.Magazine:\n            case ViewType.Compact:\n            case ViewType.List:\n                return <ListFeed {...this.props} />\n        }\n    }\n}\n"
  },
  {
    "path": "src/components/feeds/list-feed.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { FeedProps } from \"./feed\"\nimport {\n    PrimaryButton,\n    FocusZone,\n    FocusZoneDirection,\n    List,\n} from \"office-ui-fabric-react\"\nimport { RSSItem } from \"../../scripts/models/item\"\nimport { AnimationClassNames } from \"@fluentui/react\"\nimport { ViewType } from \"../../schema-types\"\nimport ListCard from \"../cards/list-card\"\nimport MagazineCard from \"../cards/magazine-card\"\nimport CompactCard from \"../cards/compact-card\"\nimport { Card } from \"../cards/card\"\n\nclass ListFeed extends React.Component<FeedProps> {\n    onRenderItem = (item: RSSItem) => {\n        const props = {\n            feedId: this.props.feed._id,\n            key: item._id,\n            item: item,\n            source: this.props.sourceMap[item.source],\n            filter: this.props.filter,\n            viewConfigs: this.props.viewConfigs,\n            shortcuts: this.props.shortcuts,\n            markRead: this.props.markRead,\n            contextMenu: this.props.contextMenu,\n            showItem: this.props.showItem,\n        } as Card.Props\n        if (\n            this.props.viewType === ViewType.List &&\n            this.props.currentItem === item._id\n        ) {\n            props.selected = true\n        }\n\n        switch (this.props.viewType) {\n            case ViewType.Magazine:\n                return <MagazineCard {...props} />\n            case ViewType.Compact:\n                return <CompactCard {...props} />\n            default:\n                return <ListCard {...props} />\n        }\n    }\n\n    getClassName = () => {\n        switch (this.props.viewType) {\n            case ViewType.Magazine:\n                return \"magazine-feed\"\n            case ViewType.Compact:\n                return \"compact-feed\"\n            default:\n                return \"list-feed\"\n        }\n    }\n\n    canFocusChild = (el: HTMLElement) => {\n        if (el.id === \"load-more\") {\n            const container = document.getElementById(\"refocus\")\n            const result =\n                container.scrollTop >\n                container.scrollHeight - 2 * container.offsetHeight\n            if (!result) container.scrollTop += 100\n            return result\n        } else {\n            return true\n        }\n    }\n\n    render() {\n        return (\n            this.props.feed.loaded && (\n                <FocusZone\n                    as=\"div\"\n                    id=\"refocus\"\n                    direction={FocusZoneDirection.vertical}\n                    className={this.getClassName()}\n                    shouldReceiveFocus={this.canFocusChild}\n                    data-is-scrollable>\n                    <List\n                        className={AnimationClassNames.slideUpIn10}\n                        items={this.props.items}\n                        onRenderCell={this.onRenderItem}\n                        ignoreScrollingState\n                        usePageCache\n                    />\n                    {this.props.feed.loaded && !this.props.feed.allLoaded ? (\n                        <div className=\"load-more-wrapper\">\n                            <PrimaryButton\n                                id=\"load-more\"\n                                text={intl.get(\"loadMore\")}\n                                disabled={this.props.feed.loading}\n                                onClick={() =>\n                                    this.props.loadMore(this.props.feed)\n                                }\n                            />\n                        </div>\n                    ) : null}\n                    {this.props.items.length === 0 && (\n                        <div className=\"empty\">{intl.get(\"article.empty\")}</div>\n                    )}\n                </FocusZone>\n            )\n        )\n    }\n}\n\nexport default ListFeed\n"
  },
  {
    "path": "src/components/log-menu.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport {\n    Callout,\n    ActivityItem,\n    Icon,\n    DirectionalHint,\n    Link,\n} from \"@fluentui/react\"\nimport { AppLog, AppLogType, toggleLogMenu } from \"../scripts/models/app\"\nimport Time from \"./utils/time\"\nimport { useAppDispatch, useAppSelector } from \"../scripts/reducer\"\nimport { showItemFromId } from \"../scripts/models/page\"\n\nfunction getLogIcon(log: AppLog) {\n    switch (log.type) {\n        case AppLogType.Info:\n            return \"Info\"\n        case AppLogType.Article:\n            return \"KnowledgeArticle\"\n        default:\n            return \"Warning\"\n    }\n}\n\nfunction LogMenu() {\n    const dispatch = useAppDispatch()\n    const { display, logs } = useAppSelector(state => state.app.logMenu)\n\n    return (\n        display && (\n            <Callout\n                target=\"#log-toggle\"\n                role=\"log-menu\"\n                directionalHint={DirectionalHint.bottomCenter}\n                calloutWidth={320}\n                calloutMaxHeight={240}\n                onDismiss={() => dispatch(toggleLogMenu())}>\n                {logs.length == 0 ? (\n                    <p style={{ textAlign: \"center\" }}>\n                        {intl.get(\"log.empty\")}\n                    </p>\n                ) : (\n                    logs\n                        .map((l, i) => (\n                            <ActivityItem\n                                activityDescription={\n                                    l.iid ? (\n                                        <b>\n                                            <Link\n                                                onClick={() => {\n                                                    dispatch(toggleLogMenu())\n                                                    dispatch(\n                                                        showItemFromId(l.iid)\n                                                    )\n                                                }}>\n                                                {l.title}\n                                            </Link>\n                                        </b>\n                                    ) : (\n                                        <b>{l.title}</b>\n                                    )\n                                }\n                                comments={l.details}\n                                activityIcon={<Icon iconName={getLogIcon(l)} />}\n                                timeStamp={<Time date={l.time} />}\n                                key={i}\n                                style={{ margin: 12 }}\n                            />\n                        ))\n                        .reverse()\n                )}\n            </Callout>\n        )\n    )\n}\n\nexport default LogMenu\n"
  },
  {
    "path": "src/components/menu.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { Icon } from \"@fluentui/react/lib/Icon\"\nimport { Nav, INavLink, INavLinkGroup } from \"office-ui-fabric-react/lib/Nav\"\nimport { SourceGroup } from \"../schema-types\"\nimport { SourceState, RSSSource } from \"../scripts/models/source\"\nimport { ALL } from \"../scripts/models/feed\"\nimport { AnimationClassNames, Stack, FocusZone } from \"@fluentui/react\"\n\nexport type MenuProps = {\n    status: boolean\n    display: boolean\n    selected: string\n    sources: SourceState\n    groups: SourceGroup[]\n    searchOn: boolean\n    itemOn: boolean\n    toggleMenu: () => void\n    allArticles: (init?: boolean) => void\n    selectSourceGroup: (group: SourceGroup, menuKey: string) => void\n    selectSource: (source: RSSSource) => void\n    groupContextMenu: (sids: number[], event: React.MouseEvent) => void\n    updateGroupExpansion: (\n        event: React.MouseEvent<HTMLElement>,\n        key: string,\n        selected: string\n    ) => void\n    toggleSearch: () => void\n}\n\nexport class Menu extends React.Component<MenuProps> {\n    countOverflow = (count: number) => (count >= 1000 ? \" 999+\" : ` ${count}`)\n\n    getLinkGroups = (): INavLinkGroup[] => [\n        {\n            links: [\n                {\n                    name: intl.get(\"search\"),\n                    ariaLabel:\n                        intl.get(\"search\") + (this.props.searchOn ? \" ✓\" : \" \"),\n                    key: \"search\",\n                    icon: \"Search\",\n                    onClick: this.props.toggleSearch,\n                    url: null,\n                },\n                {\n                    name: intl.get(\"allArticles\"),\n                    ariaLabel:\n                        intl.get(\"allArticles\") +\n                        this.countOverflow(\n                            Object.values(this.props.sources)\n                                .filter(s => !s.hidden)\n                                .map(s => s.unreadCount)\n                                .reduce((a, b) => a + b, 0)\n                        ),\n                    key: ALL,\n                    icon: \"TextDocument\",\n                    onClick: () =>\n                        this.props.allArticles(this.props.selected !== ALL),\n                    url: null,\n                },\n            ],\n        },\n        {\n            name: intl.get(\"menu.subscriptions\"),\n            links: this.props.groups\n                .filter(g => g.sids.length > 0)\n                .map(g => {\n                    if (g.isMultiple) {\n                        let sources = g.sids.map(sid => this.props.sources[sid])\n                        return {\n                            name: g.name,\n                            ariaLabel:\n                                g.name +\n                                this.countOverflow(\n                                    sources\n                                        .map(s => s.unreadCount)\n                                        .reduce((a, b) => a + b, 0)\n                                ),\n                            key: \"g-\" + g.index,\n                            url: null,\n                            isExpanded: g.expanded,\n                            onClick: () =>\n                                this.props.selectSourceGroup(g, \"g-\" + g.index),\n                            links: sources.map(this.getSource),\n                        }\n                    } else {\n                        return this.getSource(this.props.sources[g.sids[0]])\n                    }\n                }),\n        },\n    ]\n\n    getSource = (s: RSSSource): INavLink => ({\n        name: s.name,\n        ariaLabel: s.name + this.countOverflow(s.unreadCount),\n        key: \"s-\" + s.sid,\n        onClick: () => this.props.selectSource(s),\n        iconProps: s.iconurl ? this.getIconStyle(s.iconurl) : null,\n        url: null,\n    })\n\n    getIconStyle = (url: string) => ({\n        style: { width: 16 },\n        imageProps: {\n            style: { width: \"100%\" },\n            src: url,\n        },\n    })\n\n    onContext = (item: INavLink, event: React.MouseEvent) => {\n        let sids: number[]\n        let [type, index] = item.key.split(\"-\")\n        if (type === \"s\") {\n            sids = [parseInt(index)]\n        } else if (type === \"g\") {\n            sids = this.props.groups[parseInt(index)].sids\n        } else {\n            return\n        }\n        this.props.groupContextMenu(sids, event)\n    }\n\n    _onRenderLink = (link: INavLink): JSX.Element => {\n        let count = link.ariaLabel.split(\" \").pop()\n        return (\n            <Stack\n                className=\"link-stack\"\n                horizontal\n                grow\n                onContextMenu={event => this.onContext(link, event)}>\n                <div className=\"link-text\">{link.name}</div>\n                {count && count !== \"0\" && (\n                    <div className=\"unread-count\">{count}</div>\n                )}\n            </Stack>\n        )\n    }\n\n    _onRenderGroupHeader = (group: INavLinkGroup): JSX.Element => {\n        return (\n            <p className={\"subs-header \" + AnimationClassNames.slideDownIn10}>\n                {group.name}\n            </p>\n        )\n    }\n\n    render() {\n        return (\n            this.props.status && (\n                <div\n                    className={\n                        \"menu-container\" + (this.props.display ? \" show\" : \"\")\n                    }\n                    onClick={this.props.toggleMenu}>\n                    <div\n                        className={\n                            \"menu\" + (this.props.itemOn ? \" item-on\" : \"\")\n                        }\n                        onClick={e => e.stopPropagation()}>\n                        <div className=\"btn-group\">\n                            <a\n                                className=\"btn hide-wide\"\n                                title={intl.get(\"menu.close\")}\n                                onClick={this.props.toggleMenu}>\n                                <Icon iconName=\"Back\" />\n                            </a>\n                            <a\n                                className=\"btn inline-block-wide\"\n                                title={intl.get(\"menu.close\")}\n                                onClick={this.props.toggleMenu}>\n                                <Icon\n                                    iconName={\n                                        window.utils.platform === \"darwin\"\n                                            ? \"SidePanel\"\n                                            : \"GlobalNavButton\"\n                                    }\n                                />\n                            </a>\n                        </div>\n                        <FocusZone\n                            as=\"div\"\n                            disabled={!this.props.display}\n                            className=\"nav-wrapper\">\n                            <Nav\n                                onRenderGroupHeader={this._onRenderGroupHeader}\n                                onRenderLink={this._onRenderLink}\n                                groups={this.getLinkGroups()}\n                                selectedKey={this.props.selected}\n                                onLinkExpandClick={(event, item) =>\n                                    this.props.updateGroupExpansion(\n                                        event,\n                                        item.key,\n                                        this.props.selected\n                                    )\n                                }\n                            />\n                        </FocusZone>\n                    </div>\n                </div>\n            )\n        )\n    }\n}\n"
  },
  {
    "path": "src/components/nav.tsx",
    "content": "import * as React from \"react\"\nimport { useState, useEffect, useCallback } from \"react\"\nimport intl from \"react-intl-universal\"\nimport { useSelector, useDispatch } from \"react-redux\"\nimport { Icon } from \"@fluentui/react/lib/Icon\"\nimport { ProgressIndicator, IObjectWithKey } from \"@fluentui/react\"\nimport { RootState } from \"../scripts/reducer\"\nimport { fetchItems } from \"../scripts/models/item\"\nimport {\n    toggleMenu,\n    toggleLogMenu,\n    toggleSettings,\n    openViewMenu,\n    openMarkAllMenu,\n} from \"../scripts/models/app\"\nimport { toggleSearch } from \"../scripts/models/page\"\nimport { ViewType , WindowStateListenerType } from \"../schema-types\"\n\nconst Nav: React.FC = () => {\n    const dispatch = useDispatch()\n    const state = useSelector((state: RootState) => state.app)\n    const itemShown = useSelector(\n        (state: RootState) => state.page.itemId && state.page.viewType !== ViewType.List\n    )\n    const [maximized, setMaximized] = useState(window.utils.isMaximized())\n\n    const setBodyFocusState = useCallback((focused: boolean) => {\n        if (focused) document.body.classList.remove(\"blur\")\n        else document.body.classList.add(\"blur\")\n    }, [])\n\n    const setBodyFullscreenState = useCallback((fullscreen: boolean) => {\n        if (fullscreen) document.body.classList.remove(\"not-fullscreen\")\n        else document.body.classList.add(\"not-fullscreen\")\n    }, [])\n\n    const windowStateListener = useCallback(\n        (type: WindowStateListenerType, windowState: boolean) => {\n            switch (type) {\n                case WindowStateListenerType.Maximized:\n                    setMaximized(windowState)\n                    break\n                case WindowStateListenerType.Fullscreen:\n                    setBodyFullscreenState(windowState)\n                    break\n                case WindowStateListenerType.Focused:\n                    setBodyFocusState(windowState)\n                    break\n            }\n        },\n        [setBodyFocusState, setBodyFullscreenState]\n    )\n\n    const canFetch = useCallback(\n        () =>\n            state.sourceInit &&\n            state.feedInit &&\n            !state.syncing &&\n            !state.fetchingItems,\n        [state.sourceInit, state.feedInit, state.syncing, state.fetchingItems]\n    )\n\n    const fetch = useCallback(() => {\n        if (canFetch()) dispatch(fetchItems())\n    }, [canFetch, dispatch])\n\n    const menu = useCallback(() => dispatch(toggleMenu()), [dispatch])\n    const logs = useCallback(() => dispatch(toggleLogMenu()), [dispatch])\n    const search = useCallback(() => dispatch(toggleSearch()), [dispatch])\n    const settings = useCallback(() => dispatch(toggleSettings()), [dispatch])\n    const markAll = useCallback(() => dispatch(openMarkAllMenu()), [dispatch])\n    const views = useCallback(() => {\n        if (state.contextMenu.event !== \"#view-toggle\") {\n            dispatch(openViewMenu())\n        }\n    }, [state.contextMenu.event, dispatch])\n\n    const navShortcutsHandler = useCallback(\n        (e: KeyboardEvent | IObjectWithKey) => {\n            if (!state.settings.display) {\n                switch (e.key) {\n                    case \"F1\":\n                        menu()\n                        break\n                    case \"F2\":\n                        search()\n                        break\n                    case \"F5\":\n                        fetch()\n                        break\n                    case \"F6\":\n                        markAll()\n                        break\n                    case \"F7\":\n                        if (!itemShown) logs()\n                        break\n                    case \"F8\":\n                        if (!itemShown) views()\n                        break\n                    case \"F9\":\n                        if (!itemShown) settings()\n                        break\n                }\n            }\n        },\n        [state.settings.display, itemShown, menu, search, fetch, markAll, logs, views, settings]\n    )\n\n    useEffect(() => {\n        setBodyFocusState(window.utils.isFocused())\n        setBodyFullscreenState(window.utils.isFullscreen())\n        window.utils.addWindowStateListener(windowStateListener)\n\n        return () => {\n            // Cleanup will be handled by the event listener removal effect\n        }\n    }, [setBodyFocusState, setBodyFullscreenState, windowStateListener])\n\n    useEffect(() => {\n        document.addEventListener(\"keydown\", navShortcutsHandler)\n        if (window.utils.platform === \"darwin\")\n            window.utils.addTouchBarEventsListener(navShortcutsHandler)\n\n        return () => {\n            document.removeEventListener(\"keydown\", navShortcutsHandler)\n        }\n    }, [navShortcutsHandler])\n\n    const minimize = () => {\n        window.utils.minimizeWindow()\n    }\n\n    const maximize = () => {\n        window.utils.maximizeWindow()\n        setMaximized(!maximized)\n    }\n\n    const close = () => {\n        window.utils.closeWindow()\n    }\n\n    const fetching = () => (!canFetch() ? \" fetching\" : \"\")\n\n    const getClassNames = () => {\n        const classNames = new Array<string>()\n        if (state.settings.display) classNames.push(\"hide-btns\")\n        if (state.menu) classNames.push(\"menu-on\")\n        if (itemShown) classNames.push(\"item-on\")\n        return classNames.join(\" \")\n    }\n\n    const getProgress = () => {\n        return state.fetchingTotal > 0\n            ? state.fetchingProgress / state.fetchingTotal\n            : null\n    }\n\n    return (\n        <nav className={getClassNames()}>\n            <div className=\"btn-group\">\n                <a\n                    className=\"btn hide-wide\"\n                    title={intl.get(\"nav.menu\")}\n                    onClick={menu}>\n                    <Icon\n                        iconName={\n                            window.utils.platform === \"darwin\"\n                                ? \"SidePanel\"\n                                : \"GlobalNavButton\"\n                        }\n                    />\n                </a>\n            </div>\n            <span className=\"title\">{state.title}</span>\n            <div className=\"btn-group\" style={{ float: \"right\" }}>\n                <a\n                    className={\"btn\" + fetching()}\n                    onClick={fetch}\n                    title={intl.get(\"nav.refresh\")}>\n                    <Icon iconName=\"Refresh\" />\n                </a>\n                <a\n                    className=\"btn\"\n                    id=\"mark-all-toggle\"\n                    onClick={markAll}\n                    title={intl.get(\"nav.markAllRead\")}\n                    onMouseDown={e => {\n                        if (\n                            state.contextMenu.event ===\n                            \"#mark-all-toggle\"\n                        )\n                            e.stopPropagation()\n                    }}>\n                    <Icon iconName=\"InboxCheck\" />\n                </a>\n                <a\n                    className=\"btn\"\n                    id=\"log-toggle\"\n                    title={intl.get(\"nav.notifications\")}\n                    onClick={logs}>\n                    {state.logMenu.notify ? (\n                        <Icon iconName=\"RingerSolid\" />\n                    ) : (\n                        <Icon iconName=\"Ringer\" />\n                    )}\n                </a>\n                <a\n                    className=\"btn\"\n                    id=\"view-toggle\"\n                    title={intl.get(\"nav.view\")}\n                    onClick={views}\n                    onMouseDown={e => {\n                        if (\n                            state.contextMenu.event ===\n                            \"#view-toggle\"\n                        )\n                            e.stopPropagation()\n                    }}>\n                    <Icon iconName=\"View\" />\n                </a>\n                <a\n                    className=\"btn\"\n                    title={intl.get(\"nav.settings\")}\n                    onClick={settings}>\n                    <Icon iconName=\"Settings\" />\n                </a>\n                <span className=\"seperator\"></span>\n                <a\n                    className=\"btn system\"\n                    title={intl.get(\"nav.minimize\")}\n                    onClick={minimize}\n                    style={{ fontSize: 12 }}>\n                    <Icon iconName=\"Remove\" />\n                </a>\n                <a\n                    className=\"btn system\"\n                    title={intl.get(\"nav.maximize\")}\n                    onClick={maximize}>\n                    {maximized ? (\n                        <Icon\n                            iconName=\"ChromeRestore\"\n                            style={{ fontSize: 11 }}\n                        />\n                    ) : (\n                        <Icon\n                            iconName=\"Checkbox\"\n                            style={{ fontSize: 10 }}\n                        />\n                    )}\n                </a>\n                <a\n                    className=\"btn system close\"\n                    title={intl.get(\"close\")}\n                    onClick={close}>\n                    <Icon iconName=\"Cancel\" />\n                </a>\n            </div>\n            {!canFetch() && (\n                <ProgressIndicator\n                    className=\"progress\"\n                    percentComplete={getProgress()}\n                />\n            )}\n        </nav>\n    )\n}\n\nexport default Nav\n"
  },
  {
    "path": "src/components/page.tsx",
    "content": "import * as React from \"react\"\nimport { FeedContainer } from \"../containers/feed-container\"\nimport { AnimationClassNames, Icon, FocusTrapZone } from \"@fluentui/react\"\nimport ArticleContainer from \"../containers/article-container\"\nimport { ViewType } from \"../schema-types\"\nimport ArticleSearch from \"./utils/article-search\"\n\ntype PageProps = {\n    menuOn: boolean\n    contextOn: boolean\n    settingsOn: boolean\n    feeds: string[]\n    itemId: number\n    itemFromFeed: boolean\n    viewType: ViewType\n    dismissItem: () => void\n    offsetItem: (offset: number) => void\n}\n\nclass Page extends React.Component<PageProps> {\n    offsetItem = (event: React.MouseEvent, offset: number) => {\n        event.stopPropagation()\n        this.props.offsetItem(offset)\n    }\n    prevItem = (event: React.MouseEvent) => this.offsetItem(event, -1)\n    nextItem = (event: React.MouseEvent) => this.offsetItem(event, 1)\n\n    render = () =>\n        this.props.viewType !== ViewType.List ? (\n            <>\n                {this.props.settingsOn ? null : (\n                    <div\n                        key=\"card\"\n                        className={\n                            \"main\" + (this.props.menuOn ? \" menu-on\" : \"\")\n                        }>\n                        <ArticleSearch />\n                        {this.props.feeds.map(fid => (\n                            <FeedContainer\n                                viewType={this.props.viewType}\n                                feedId={fid}\n                                key={fid + this.props.viewType}\n                            />\n                        ))}\n                    </div>\n                )}\n                {this.props.itemId && (\n                    <FocusTrapZone\n                        disabled={this.props.contextOn}\n                        ignoreExternalFocusing={true}\n                        isClickableOutsideFocusTrap={true}\n                        className=\"article-container\"\n                        onClick={this.props.dismissItem}>\n                        <div\n                            className=\"article-wrapper\"\n                            onClick={e => e.stopPropagation()}>\n                            <ArticleContainer itemId={this.props.itemId} />\n                        </div>\n                        {this.props.itemFromFeed && (\n                            <>\n                                <div className=\"btn-group prev\">\n                                    <a className=\"btn\" onClick={this.prevItem}>\n                                        <Icon iconName=\"Back\" />\n                                    </a>\n                                </div>\n                                <div className=\"btn-group next\">\n                                    <a className=\"btn\" onClick={this.nextItem}>\n                                        <Icon iconName=\"Forward\" />\n                                    </a>\n                                </div>\n                            </>\n                        )}\n                    </FocusTrapZone>\n                )}\n            </>\n        ) : (\n            <>\n                {this.props.settingsOn ? null : (\n                    <div\n                        key=\"list\"\n                        className={\n                            \"list-main\" + (this.props.menuOn ? \" menu-on\" : \"\")\n                        }>\n                        <ArticleSearch />\n                        <div className=\"list-feed-container\">\n                            {this.props.feeds.map(fid => (\n                                <FeedContainer\n                                    viewType={this.props.viewType}\n                                    feedId={fid}\n                                    key={fid}\n                                />\n                            ))}\n                        </div>\n                        {this.props.itemId ? (\n                            <div className=\"side-article-wrapper\">\n                                <ArticleContainer itemId={this.props.itemId} />\n                            </div>\n                        ) : (\n                            <div className=\"side-logo-wrapper\">\n                                <img\n                                    className=\"light\"\n                                    src=\"icons/logo-outline.svg\"\n                                />\n                                <img\n                                    className=\"dark\"\n                                    src=\"icons/logo-outline-dark.svg\"\n                                />\n                            </div>\n                        )}\n                    </div>\n                )}\n            </>\n        )\n}\n\nexport default Page\n"
  },
  {
    "path": "src/components/root.tsx",
    "content": "import * as React from \"react\"\nimport { connect } from \"react-redux\"\nimport { closeContextMenu } from \"../scripts/models/app\"\nimport PageContainer from \"../containers/page-container\"\nimport MenuContainer from \"../containers/menu-container\"\nimport Nav from \"./nav\"\nimport SettingsContainer from \"../containers/settings-container\"\nimport { RootState } from \"../scripts/reducer\"\nimport { ContextMenu } from \"./context-menu\"\nimport LogMenu from \"./log-menu\"\n\nconst Root = ({ locale, dispatch }) =>\n    locale && (\n        <div\n            id=\"root\"\n            key={locale}\n            onMouseDown={() => dispatch(closeContextMenu())}>\n            <Nav />\n            <PageContainer />\n            <LogMenu />\n            <MenuContainer />\n            <SettingsContainer />\n            <ContextMenu />\n        </div>\n    )\n\nconst getLocale = (state: RootState) => ({ locale: state.app.locale })\nexport default connect(getLocale)(Root)\n"
  },
  {
    "path": "src/components/settings/about.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { Stack, Link } from \"@fluentui/react\"\n\nclass AboutTab extends React.Component {\n    render = () => (\n        <div className=\"tab-body\">\n            <Stack className=\"settings-about\" horizontalAlign=\"center\">\n                <img src=\"icons/logo.svg\" style={{ width: 120, height: 120 }} />\n                <h3 style={{ fontWeight: 600 }}>Fluent Reader</h3>\n                <small>\n                    {intl.get(\"settings.version\")} {window.utils.getVersion()}\n                </small>\n                <p className=\"settings-hint\">\n                    Copyright © 2020 Haoyuan Liu. All rights reserved.\n                </p>\n                <Stack\n                    horizontal\n                    horizontalAlign=\"center\"\n                    tokens={{ childrenGap: 12 }}>\n                    <small>\n                        <Link\n                            onClick={() =>\n                                window.utils.openExternal(\n                                    \"https://github.com/yang991178/fluent-reader/wiki/Support#keyboard-shortcuts\"\n                                )\n                            }>\n                            {intl.get(\"settings.shortcuts\")}\n                        </Link>\n                    </small>\n                    <small>\n                        <Link\n                            onClick={() =>\n                                window.utils.openExternal(\n                                    \"https://github.com/yang991178/fluent-reader\"\n                                )\n                            }>\n                            {intl.get(\"settings.openSource\")}\n                        </Link>\n                    </small>\n                    <small>\n                        <Link\n                            onClick={() =>\n                                window.utils.openExternal(\n                                    \"https://github.com/yang991178/fluent-reader/issues\"\n                                )\n                            }>\n                            {intl.get(\"settings.feedback\")}\n                        </Link>\n                    </small>\n                </Stack>\n            </Stack>\n        </div>\n    )\n}\n\nexport default AboutTab\n"
  },
  {
    "path": "src/components/settings/app.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport {\n    urlTest,\n    byteToMB,\n    calculateItemSize,\n    getSearchEngineName,\n} from \"../../scripts/utils\"\nimport { ThemeSettings, SearchEngines } from \"../../schema-types\"\nimport {\n    getThemeSettings,\n    setThemeSettings,\n    exportAll,\n} from \"../../scripts/settings\"\nimport {\n    Stack,\n    Label,\n    Toggle,\n    TextField,\n    DefaultButton,\n    ChoiceGroup,\n    IChoiceGroupOption,\n    Dropdown,\n    IDropdownOption,\n    PrimaryButton,\n} from \"@fluentui/react\"\nimport DangerButton from \"../utils/danger-button\"\n\ntype AppTabProps = {\n    setLanguage: (option: string) => void\n    setFetchInterval: (interval: number) => void\n    deleteArticles: (days: number) => Promise<void>\n    importAll: () => Promise<void>\n}\n\ntype AppTabState = {\n    pacStatus: boolean\n    pacUrl: string\n    themeSettings: ThemeSettings\n    itemSize: string\n    cacheSize: string\n    deleteIndex: string\n}\n\nclass AppTab extends React.Component<AppTabProps, AppTabState> {\n    constructor(props) {\n        super(props)\n        this.state = {\n            pacStatus: window.settings.getProxyStatus(),\n            pacUrl: window.settings.getProxy(),\n            themeSettings: getThemeSettings(),\n            itemSize: null,\n            cacheSize: null,\n            deleteIndex: null,\n        }\n        this.getItemSize()\n        this.getCacheSize()\n    }\n\n    getCacheSize = () => {\n        window.utils.getCacheSize().then(size => {\n            this.setState({ cacheSize: byteToMB(size) })\n        })\n    }\n    getItemSize = () => {\n        calculateItemSize().then(size => {\n            this.setState({ itemSize: byteToMB(size) })\n        })\n    }\n\n    clearCache = () => {\n        window.utils.clearCache().then(() => {\n            this.getCacheSize()\n        })\n    }\n\n    themeChoices = (): IChoiceGroupOption[] => [\n        { key: ThemeSettings.Default, text: intl.get(\"followSystem\") },\n        { key: ThemeSettings.Light, text: intl.get(\"app.lightTheme\") },\n        { key: ThemeSettings.Dark, text: intl.get(\"app.darkTheme\") },\n    ]\n\n    fetchIntervalOptions = (): IDropdownOption[] => [\n        { key: 0, text: intl.get(\"app.never\") },\n        { key: 10, text: intl.get(\"time.minute\", { m: 10 }) },\n        { key: 15, text: intl.get(\"time.minute\", { m: 15 }) },\n        { key: 20, text: intl.get(\"time.minute\", { m: 20 }) },\n        { key: 30, text: intl.get(\"time.minute\", { m: 30 }) },\n        { key: 45, text: intl.get(\"time.minute\", { m: 45 }) },\n        { key: 60, text: intl.get(\"time.hour\", { h: 1 }) },\n    ]\n    onFetchIntervalChanged = (item: IDropdownOption) => {\n        this.props.setFetchInterval(item.key as number)\n    }\n\n    searchEngineOptions = (): IDropdownOption[] =>\n        [\n            SearchEngines.Google,\n            SearchEngines.Bing,\n            SearchEngines.Baidu,\n            SearchEngines.DuckDuckGo,\n        ].map(engine => ({\n            key: engine,\n            text: getSearchEngineName(engine),\n        }))\n    onSearchEngineChanged = (item: IDropdownOption) => {\n        window.settings.setSearchEngine(item.key as number)\n    }\n\n    deleteOptions = (): IDropdownOption[] => [\n        { key: \"7\", text: intl.get(\"app.daysAgo\", { days: 7 }) },\n        { key: \"14\", text: intl.get(\"app.daysAgo\", { days: 14 }) },\n        { key: \"21\", text: intl.get(\"app.daysAgo\", { days: 21 }) },\n        { key: \"28\", text: intl.get(\"app.daysAgo\", { days: 28 }) },\n        { key: \"0\", text: intl.get(\"app.deleteAll\") },\n    ]\n\n    deleteChange = (_, item: IDropdownOption) => {\n        this.setState({ deleteIndex: item ? String(item.key) : null })\n    }\n\n    confirmDelete = () => {\n        this.setState({ itemSize: null })\n        this.props\n            .deleteArticles(parseInt(this.state.deleteIndex))\n            .then(() => this.getItemSize())\n    }\n\n    languageOptions = (): IDropdownOption[] => [\n        { key: \"default\", text: intl.get(\"followSystem\") },\n        { key: \"de\", text: \"Deutsch\" },\n        { key: \"en-US\", text: \"English\" },\n        { key: \"es\", text: \"Español\" },\n        { key: \"cs\", text: \"Čeština\" },\n        { key: \"fr-FR\", text: \"Français\" },\n        { key: \"it\", text: \"Italiano\" },\n        { key: \"nl\", text: \"Nederlands\" },\n        { key: \"pt-BR\", text: \"Português do Brasil\" },\n        { key: \"pt-PT\", text: \"Português de Portugal\" },\n        { key: \"fi-FI\", text: \"Suomi\" },\n        { key: \"sv\", text: \"Svenska\" },\n        { key: \"tr\", text: \"Türkçe\" },\n        { key: \"uk\", text: \"Українська\" },\n        { key: \"ru\", text: \"Русский\" },\n        { key: \"ko\", text: \"한글\" },\n        { key: \"ja\", text: \"日本語\" },\n        { key: \"zh-CN\", text: \"中文（简体）\" },\n        { key: \"zh-TW\", text: \"中文（繁體）\" },\n    ]\n\n    toggleStatus = () => {\n        window.settings.toggleProxyStatus()\n        this.setState({\n            pacStatus: window.settings.getProxyStatus(),\n            pacUrl: window.settings.getProxy(),\n        })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-ignore\n        this.setState({ [name]: event.target.value.trim() })\n    }\n\n    setUrl = (event: React.FormEvent) => {\n        event.preventDefault()\n        if (urlTest(this.state.pacUrl))\n            window.settings.setProxy(this.state.pacUrl)\n    }\n\n    onThemeChange = (_, option: IChoiceGroupOption) => {\n        setThemeSettings(option.key as ThemeSettings)\n        this.setState({ themeSettings: option.key as ThemeSettings })\n    }\n\n    render = () => (\n        <div className=\"tab-body\">\n            <Label>{intl.get(\"app.language\")}</Label>\n            <Stack horizontal>\n                <Stack.Item>\n                    <Dropdown\n                        defaultSelectedKey={window.settings.getLocaleSettings()}\n                        options={this.languageOptions()}\n                        onChanged={option =>\n                            this.props.setLanguage(String(option.key))\n                        }\n                        style={{ width: 200 }}\n                    />\n                </Stack.Item>\n            </Stack>\n\n            <ChoiceGroup\n                label={intl.get(\"app.theme\")}\n                options={this.themeChoices()}\n                onChange={this.onThemeChange}\n                selectedKey={this.state.themeSettings}\n            />\n\n            <Label>{intl.get(\"app.fetchInterval\")}</Label>\n            <Stack horizontal>\n                <Stack.Item>\n                    <Dropdown\n                        defaultSelectedKey={window.settings.getFetchInterval()}\n                        options={this.fetchIntervalOptions()}\n                        onChanged={this.onFetchIntervalChanged}\n                        style={{ width: 200 }}\n                    />\n                </Stack.Item>\n            </Stack>\n\n            <Label>{intl.get(\"searchEngine.name\")}</Label>\n            <Stack horizontal>\n                <Stack.Item>\n                    <Dropdown\n                        defaultSelectedKey={window.settings.getSearchEngine()}\n                        options={this.searchEngineOptions()}\n                        onChanged={this.onSearchEngineChanged}\n                        style={{ width: 200 }}\n                    />\n                </Stack.Item>\n            </Stack>\n\n            <Stack horizontal verticalAlign=\"baseline\">\n                <Stack.Item grow>\n                    <Label>{intl.get(\"app.enableProxy\")}</Label>\n                </Stack.Item>\n                <Stack.Item>\n                    <Toggle\n                        checked={this.state.pacStatus}\n                        onChange={this.toggleStatus}\n                    />\n                </Stack.Item>\n            </Stack>\n            {this.state.pacStatus && (\n                <form onSubmit={this.setUrl}>\n                    <Stack horizontal>\n                        <Stack.Item grow>\n                            <TextField\n                                required\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"app.badUrl\")\n                                }\n                                placeholder={intl.get(\"app.pac\")}\n                                name=\"pacUrl\"\n                                onChange={this.handleInputChange}\n                                value={this.state.pacUrl}\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            <DefaultButton\n                                disabled={!urlTest(this.state.pacUrl)}\n                                type=\"sumbit\"\n                                text={intl.get(\"app.setPac\")}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <span className=\"settings-hint up\">\n                        {intl.get(\"app.pacHint\")}\n                    </span>\n                </form>\n            )}\n\n            <Label>{intl.get(\"app.cleanup\")}</Label>\n            <Stack horizontal>\n                <Stack.Item grow>\n                    <Dropdown\n                        placeholder={intl.get(\"app.deleteChoices\")}\n                        options={this.deleteOptions()}\n                        selectedKey={this.state.deleteIndex}\n                        onChange={this.deleteChange}\n                    />\n                </Stack.Item>\n                <Stack.Item>\n                    <DangerButton\n                        disabled={\n                            this.state.itemSize === null ||\n                            this.state.deleteIndex === null\n                        }\n                        text={intl.get(\"app.confirmDelete\")}\n                        onClick={this.confirmDelete}\n                    />\n                </Stack.Item>\n            </Stack>\n            <span className=\"settings-hint up\">\n                {this.state.itemSize\n                    ? intl.get(\"app.itemSize\", { size: this.state.itemSize })\n                    : intl.get(\"app.calculatingSize\")}\n            </span>\n            <Stack horizontal>\n                <Stack.Item>\n                    <DefaultButton\n                        text={intl.get(\"app.cache\")}\n                        disabled={\n                            this.state.cacheSize === null ||\n                            this.state.cacheSize === \"0MB\"\n                        }\n                        onClick={this.clearCache}\n                    />\n                </Stack.Item>\n            </Stack>\n            <span className=\"settings-hint up\">\n                {this.state.cacheSize\n                    ? intl.get(\"app.cacheSize\", { size: this.state.cacheSize })\n                    : intl.get(\"app.calculatingSize\")}\n            </span>\n\n            <Label>{intl.get(\"app.data\")}</Label>\n            <Stack horizontal>\n                <Stack.Item>\n                    <PrimaryButton\n                        onClick={exportAll}\n                        text={intl.get(\"app.backup\")}\n                    />\n                </Stack.Item>\n                <Stack.Item>\n                    <DefaultButton\n                        onClick={this.props.importAll}\n                        text={intl.get(\"app.restore\")}\n                    />\n                </Stack.Item>\n            </Stack>\n        </div>\n    )\n}\n\nexport default AppTab\n"
  },
  {
    "path": "src/components/settings/groups.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { SourceGroup } from \"../../schema-types\"\nimport { SourceState, RSSSource } from \"../../scripts/models/source\"\nimport {\n    IColumn,\n    Selection,\n    SelectionMode,\n    DetailsList,\n    Label,\n    Stack,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Dropdown,\n    IDropdownOption,\n    CommandBarButton,\n    MarqueeSelection,\n    IDragDropEvents,\n    MessageBar,\n    MessageBarType,\n    MessageBarButton,\n} from \"@fluentui/react\"\nimport DangerButton from \"../utils/danger-button\"\n\ntype GroupsTabProps = {\n    sources: SourceState\n    groups: SourceGroup[]\n    serviceOn: boolean\n    createGroup: (name: string) => void\n    updateGroup: (group: SourceGroup) => void\n    addToGroup: (groupIndex: number, sid: number) => void\n    deleteGroup: (groupIndex: number) => void\n    removeFromGroup: (groupIndex: number, sids: number[]) => void\n    reorderGroups: (groups: SourceGroup[]) => void\n    importGroups: () => Promise<void>\n}\n\ntype GroupsTabState = {\n    [formName: string]: any\n    selectedGroup: SourceGroup\n    selectedSources: RSSSource[]\n    dropdownIndex: number\n    manageGroup: boolean\n}\n\nclass GroupsTab extends React.Component<GroupsTabProps, GroupsTabState> {\n    groupSelection: Selection\n    groupDragDropEvents: IDragDropEvents\n    groupDraggedItem: SourceGroup\n    groupDraggedIndex = -1\n    sourcesSelection: Selection\n    sourcesDragDropEvents: IDragDropEvents\n    sourcesDraggedItem: RSSSource\n    sourcesDraggedIndex = -1\n\n    constructor(props) {\n        super(props)\n        this.state = {\n            editGroupName: \"\",\n            newGroupName: \"\",\n            selectedGroup: null,\n            selectedSources: null,\n            dropdownIndex: null,\n            manageGroup: false,\n        }\n        this.groupDragDropEvents = this.getGroupDragDropEvents()\n        this.sourcesDragDropEvents = this.getSourcesDragDropEvents()\n        this.groupSelection = new Selection({\n            getKey: g => (g as SourceGroup).index,\n            onSelectionChanged: () => {\n                let g = this.groupSelection.getSelectedCount()\n                    ? (this.groupSelection.getSelection()[0] as SourceGroup)\n                    : null\n                this.setState({\n                    selectedGroup: g,\n                    editGroupName: g && g.isMultiple ? g.name : \"\",\n                })\n            },\n        })\n        this.sourcesSelection = new Selection({\n            getKey: s => (s as RSSSource).sid,\n            onSelectionChanged: () => {\n                let sources = this.sourcesSelection.getSelectedCount()\n                    ? (this.sourcesSelection.getSelection() as RSSSource[])\n                    : null\n                this.setState({\n                    selectedSources: sources,\n                })\n            },\n        })\n    }\n\n    groupColumns = (): IColumn[] => [\n        {\n            key: \"type\",\n            name: intl.get(\"groups.type\"),\n            minWidth: 40,\n            maxWidth: 40,\n            data: \"string\",\n            onRender: (g: SourceGroup) => (\n                <>\n                    {g.isMultiple\n                        ? intl.get(\"groups.group\")\n                        : intl.get(\"groups.source\")}\n                </>\n            ),\n        },\n        {\n            key: \"capacity\",\n            name: intl.get(\"groups.capacity\"),\n            minWidth: 40,\n            maxWidth: 60,\n            data: \"string\",\n            onRender: (g: SourceGroup) => (\n                <>{g.isMultiple ? g.sids.length : \"\"}</>\n            ),\n        },\n        {\n            key: \"name\",\n            name: intl.get(\"name\"),\n            minWidth: 200,\n            data: \"string\",\n            isRowHeader: true,\n            onRender: (g: SourceGroup) => (\n                <>\n                    {g.isMultiple ? g.name : this.props.sources[g.sids[0]].name}\n                </>\n            ),\n        },\n    ]\n\n    sourceColumns: IColumn[] = [\n        {\n            key: \"favicon\",\n            name: intl.get(\"icon\"),\n            fieldName: \"name\",\n            isIconOnly: true,\n            iconName: \"ImagePixel\",\n            minWidth: 16,\n            maxWidth: 16,\n            onRender: (s: RSSSource) =>\n                s.iconurl && <img src={s.iconurl} className=\"favicon\" />,\n        },\n        {\n            key: \"name\",\n            name: intl.get(\"name\"),\n            fieldName: \"name\",\n            minWidth: 200,\n            data: \"string\",\n            isRowHeader: true,\n        },\n        {\n            key: \"url\",\n            name: \"URL\",\n            fieldName: \"url\",\n            minWidth: 280,\n            data: \"string\",\n        },\n    ]\n\n    getGroupDragDropEvents = (): IDragDropEvents => ({\n        canDrop: () => true,\n        canDrag: () => true,\n        onDrop: (item?: SourceGroup) => {\n            if (this.groupDraggedItem) {\n                this.reorderGroups(item)\n            }\n        },\n        onDragStart: (item?: SourceGroup, itemIndex?: number) => {\n            this.groupDraggedItem = item\n            this.groupDraggedIndex = itemIndex!\n        },\n        onDragEnd: () => {\n            this.groupDraggedItem = undefined\n            this.groupDraggedIndex = -1\n        },\n    })\n\n    reorderGroups = (item: SourceGroup) => {\n        let draggedItem = this.groupSelection.isIndexSelected(\n            this.groupDraggedIndex\n        )\n            ? (this.groupSelection.getSelection()[0] as SourceGroup)\n            : this.groupDraggedItem!\n\n        let insertIndex = item.index\n        let groups = this.props.groups.filter(g => g.index != draggedItem.index)\n\n        groups.splice(insertIndex, 0, draggedItem)\n        this.groupSelection.setAllSelected(false)\n        this.props.reorderGroups(groups)\n    }\n\n    getSourcesDragDropEvents = (): IDragDropEvents => ({\n        canDrop: () => true,\n        canDrag: () => true,\n        onDrop: (item?: RSSSource) => {\n            if (this.sourcesDraggedItem) {\n                this.reorderSources(item)\n            }\n        },\n        onDragStart: (item?: RSSSource, itemIndex?: number) => {\n            this.sourcesDraggedItem = item\n            this.sourcesDraggedIndex = itemIndex!\n        },\n        onDragEnd: () => {\n            this.sourcesDraggedItem = undefined\n            this.sourcesDraggedIndex = -1\n        },\n    })\n\n    reorderSources = (item: RSSSource) => {\n        let draggedItems = this.sourcesSelection.isIndexSelected(\n            this.sourcesDraggedIndex\n        )\n            ? (this.sourcesSelection.getSelection() as RSSSource[]).map(\n                  s => s.sid\n              )\n            : [this.sourcesDraggedItem!.sid]\n\n        let insertIndex = this.state.selectedGroup.sids.indexOf(item.sid)\n        let items = this.state.selectedGroup.sids.filter(\n            sid => !draggedItems.includes(sid)\n        )\n\n        items.splice(insertIndex, 0, ...draggedItems)\n\n        let group = { ...this.state.selectedGroup, sids: items }\n        this.props.updateGroup(group)\n        this.setState({ selectedGroup: group })\n    }\n\n    manageGroup = (g: SourceGroup) => {\n        if (g.isMultiple) {\n            this.setState({\n                selectedGroup: g,\n                editGroupName: g && g.isMultiple ? g.name : \"\",\n                manageGroup: true,\n            })\n        }\n    }\n\n    dropdownOptions = () =>\n        this.props.groups\n            .filter(g => g.isMultiple)\n            .map(g => ({\n                key: g.index,\n                text: g.name,\n            }))\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        this.setState({ [name]: event.target.value })\n    }\n\n    validateNewGroupName = (v: string) => {\n        const name = v.trim()\n        if (name.length == 0) {\n            return intl.get(\"emptyName\")\n        }\n        for (let group of this.props.groups) {\n            if (group.isMultiple && group.name === name) {\n                return intl.get(\"groups.exist\")\n            }\n        }\n        return \"\"\n    }\n\n    createGroup = (event: React.FormEvent) => {\n        event.preventDefault()\n        let trimmed = this.state.newGroupName.trim()\n        if (this.validateNewGroupName(trimmed) === \"\")\n            this.props.createGroup(trimmed)\n    }\n\n    addToGroup = () => {\n        this.props.addToGroup(\n            this.state.dropdownIndex,\n            this.state.selectedGroup.sids[0]\n        )\n    }\n\n    removeFromGroup = () => {\n        this.props.removeFromGroup(\n            this.state.selectedGroup.index,\n            this.state.selectedSources.map(s => s.sid)\n        )\n        this.setState({ selectedSources: null })\n    }\n\n    deleteGroup = () => {\n        this.props.deleteGroup(this.state.selectedGroup.index)\n        this.groupSelection.setIndexSelected(\n            this.state.selectedGroup.index,\n            false,\n            false\n        )\n        this.setState({ selectedGroup: null })\n    }\n\n    updateGroupName = () => {\n        let group = this.state.selectedGroup\n        group = { ...group, name: this.state.editGroupName.trim() }\n        this.props.updateGroup(group)\n    }\n\n    dropdownChange = (_, item: IDropdownOption) => {\n        this.setState({ dropdownIndex: item ? Number(item.key) : null })\n    }\n\n    render = () => (\n        <div className=\"tab-body\">\n            {this.state.manageGroup && this.state.selectedGroup && (\n                <>\n                    <Stack\n                        horizontal\n                        horizontalAlign=\"space-between\"\n                        style={{ height: 40 }}>\n                        <CommandBarButton\n                            text={intl.get(\"groups.exitGroup\")}\n                            iconProps={{ iconName: \"BackToWindow\" }}\n                            onClick={() =>\n                                this.setState({ manageGroup: false })\n                            }\n                        />\n                        {this.state.selectedSources != null && (\n                            <CommandBarButton\n                                text={intl.get(\"groups.deleteSource\")}\n                                onClick={this.removeFromGroup}\n                                iconProps={{\n                                    iconName: \"RemoveFromShoppingList\",\n                                    style: { color: \"#d13438\" },\n                                }}\n                            />\n                        )}\n                    </Stack>\n\n                    <MarqueeSelection\n                        selection={this.sourcesSelection}\n                        isDraggingConstrainedToRoot={true}>\n                        <DetailsList\n                            compact={true}\n                            items={this.state.selectedGroup.sids.map(\n                                sid => this.props.sources[sid]\n                            )}\n                            columns={this.sourceColumns}\n                            dragDropEvents={this.sourcesDragDropEvents}\n                            setKey=\"multiple\"\n                            selection={this.sourcesSelection}\n                            selectionMode={SelectionMode.multiple}\n                        />\n                    </MarqueeSelection>\n\n                    <span className=\"settings-hint\">\n                        {intl.get(\"groups.sourceHint\")}\n                    </span>\n                </>\n            )}\n            {!this.state.manageGroup || !this.state.selectedGroup ? (\n                <>\n                    {this.props.serviceOn && (\n                        <MessageBar\n                            messageBarType={MessageBarType.info}\n                            isMultiline={false}\n                            actions={\n                                <MessageBarButton\n                                    text={intl.get(\"service.importGroups\")}\n                                    onClick={this.props.importGroups}\n                                />\n                            }>\n                            {intl.get(\"service.groupsWarning\")}\n                        </MessageBar>\n                    )}\n                    <form onSubmit={this.createGroup}>\n                        <Label htmlFor=\"newGroupName\">\n                            {intl.get(\"groups.create\")}\n                        </Label>\n                        <Stack horizontal>\n                            <Stack.Item grow>\n                                <TextField\n                                    onGetErrorMessage={\n                                        this.validateNewGroupName\n                                    }\n                                    validateOnLoad={false}\n                                    placeholder={intl.get(\"groups.enterName\")}\n                                    value={this.state.newGroupName}\n                                    id=\"newGroupName\"\n                                    name=\"newGroupName\"\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                            <Stack.Item>\n                                <PrimaryButton\n                                    disabled={\n                                        this.validateNewGroupName(\n                                            this.state.newGroupName\n                                        ) !== \"\"\n                                    }\n                                    type=\"sumbit\"\n                                    text={intl.get(\"create\")}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                    </form>\n\n                    <DetailsList\n                        compact={true}\n                        items={this.props.groups}\n                        columns={this.groupColumns()}\n                        setKey=\"selected\"\n                        onItemInvoked={this.manageGroup}\n                        dragDropEvents={this.groupDragDropEvents}\n                        selection={this.groupSelection}\n                        selectionMode={SelectionMode.single}\n                    />\n\n                    {this.state.selectedGroup ? (\n                        this.state.selectedGroup.isMultiple ? (\n                            <>\n                                <Label>\n                                    {intl.get(\"groups.selectedGroup\")}\n                                </Label>\n                                <Stack horizontal>\n                                    <Stack.Item grow>\n                                        <TextField\n                                            onGetErrorMessage={v =>\n                                                v.trim().length == 0\n                                                    ? intl.get(\"emptyName\")\n                                                    : \"\"\n                                            }\n                                            validateOnLoad={false}\n                                            placeholder={intl.get(\n                                                \"groups.enterName\"\n                                            )}\n                                            value={this.state.editGroupName}\n                                            name=\"editGroupName\"\n                                            onChange={this.handleInputChange}\n                                        />\n                                    </Stack.Item>\n                                    <Stack.Item>\n                                        <DefaultButton\n                                            disabled={\n                                                this.state.editGroupName.trim()\n                                                    .length == 0\n                                            }\n                                            onClick={this.updateGroupName}\n                                            text={intl.get(\"groups.editName\")}\n                                        />\n                                    </Stack.Item>\n                                    <Stack.Item>\n                                        <DangerButton\n                                            key={this.state.selectedGroup.index}\n                                            onClick={this.deleteGroup}\n                                            text={intl.get(\n                                                \"groups.deleteGroup\"\n                                            )}\n                                        />\n                                    </Stack.Item>\n                                </Stack>\n                            </>\n                        ) : (\n                            <>\n                                <Label>\n                                    {intl.get(\"groups.selectedSource\")}\n                                </Label>\n                                <Stack horizontal>\n                                    <Stack.Item grow>\n                                        <Dropdown\n                                            placeholder={intl.get(\n                                                \"groups.chooseGroup\"\n                                            )}\n                                            selectedKey={\n                                                this.state.dropdownIndex\n                                            }\n                                            options={this.dropdownOptions()}\n                                            onChange={this.dropdownChange}\n                                        />\n                                    </Stack.Item>\n                                    <Stack.Item>\n                                        <DefaultButton\n                                            disabled={\n                                                this.state.dropdownIndex ===\n                                                null\n                                            }\n                                            onClick={this.addToGroup}\n                                            text={intl.get(\"groups.addToGroup\")}\n                                        />\n                                    </Stack.Item>\n                                </Stack>\n                            </>\n                        )\n                    ) : (\n                        <span className=\"settings-hint\">\n                            {intl.get(\"groups.groupHint\")}\n                        </span>\n                    )}\n                </>\n            ) : null}\n        </div>\n    )\n}\n\nexport default GroupsTab\n"
  },
  {
    "path": "src/components/settings/rules.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { SourceState, RSSSource } from \"../../scripts/models/source\"\nimport {\n    Stack,\n    Label,\n    Dropdown,\n    IDropdownOption,\n    TextField,\n    PrimaryButton,\n    Icon,\n    DropdownMenuItemType,\n    DefaultButton,\n    DetailsList,\n    IColumn,\n    CommandBar,\n    ICommandBarItemProps,\n    Selection,\n    SelectionMode,\n    MarqueeSelection,\n    IDragDropEvents,\n    Link,\n    IIconProps,\n} from \"@fluentui/react\"\nimport { SourceRule, RuleActions } from \"../../scripts/models/rule\"\nimport { FilterType } from \"../../scripts/models/feed\"\nimport { MyParserItem, validateRegex } from \"../../scripts/utils\"\nimport { RSSItem } from \"../../scripts/models/item\"\n\nconst actionKeyMap = {\n    \"r-true\": \"article.markRead\",\n    \"r-false\": \"article.markUnread\",\n    \"s-true\": \"article.star\",\n    \"s-false\": \"article.unstar\",\n    \"h-true\": \"article.hide\",\n    \"h-false\": \"article.unhide\",\n    \"n-true\": \"article.notify\",\n    \"n-false\": \"article.dontNotify\",\n}\n\ntype RulesTabProps = {\n    sources: SourceState\n    updateSourceRules: (source: RSSSource, rules: SourceRule[]) => void\n}\n\ntype RulesTabState = {\n    sid: string\n    selectedRules: number[]\n    editIndex: number\n    regex: string\n    searchType: number\n    caseSensitive: boolean\n    match: boolean\n    actionKeys: string[]\n    mockTitle: string\n    mockCreator: string\n    mockContent: string\n    mockResult: string\n}\n\nclass RulesTab extends React.Component<RulesTabProps, RulesTabState> {\n    rulesSelection: Selection\n    rulesDragDropEvents: IDragDropEvents\n    rulesDraggedItem: SourceRule\n    rulesDraggedIndex = -1\n\n    constructor(props) {\n        super(props)\n        this.state = {\n            sid: null,\n            selectedRules: [],\n            editIndex: -1,\n            regex: \"\",\n            searchType: 0,\n            caseSensitive: false,\n            match: true,\n            actionKeys: [],\n            mockTitle: \"\",\n            mockCreator: \"\",\n            mockContent: \"\",\n            mockResult: \"\",\n        }\n        this.rulesSelection = new Selection({\n            getKey: (_, i) => i,\n            onSelectionChanged: () => {\n                this.setState({\n                    selectedRules: this.rulesSelection.getSelectedIndices(),\n                })\n            },\n        })\n        this.rulesDragDropEvents = this.getRulesDragDropEvents()\n    }\n\n    getRulesDragDropEvents = (): IDragDropEvents => ({\n        canDrop: () => true,\n        canDrag: () => true,\n        onDrop: (item?: SourceRule) => {\n            if (this.rulesDraggedItem) {\n                this.reorderRules(item)\n            }\n        },\n        onDragStart: (item?: SourceRule, itemIndex?: number) => {\n            this.rulesDraggedItem = item\n            this.rulesDraggedIndex = itemIndex!\n        },\n        onDragEnd: () => {\n            this.rulesDraggedItem = undefined\n            this.rulesDraggedIndex = -1\n        },\n    })\n\n    reorderRules = (item: SourceRule) => {\n        let rules = this.getSourceRules()\n        let draggedItems = this.rulesSelection.isIndexSelected(\n            this.rulesDraggedIndex\n        )\n            ? (this.rulesSelection.getSelection() as SourceRule[])\n            : [this.rulesDraggedItem]\n\n        let insertIndex = rules.indexOf(item)\n        let items = rules.filter(r => !draggedItems.includes(r))\n\n        items.splice(insertIndex, 0, ...draggedItems)\n        this.rulesSelection.setAllSelected(false)\n        let source = this.props.sources[parseInt(this.state.sid)]\n        this.props.updateSourceRules(source, items)\n    }\n\n    initRuleEdit = (rule: SourceRule = null) => {\n        let searchType = 0\n        if (rule) {\n            if (rule.filter.type & FilterType.FullSearch) searchType = 1\n            else if (rule.filter.type & FilterType.CreatorSearch) searchType = 2\n        }\n        this.setState({\n            regex: rule ? rule.filter.search : \"\",\n            searchType: searchType,\n            caseSensitive: rule\n                ? !(rule.filter.type & FilterType.CaseInsensitive)\n                : false,\n            match: rule ? rule.match : true,\n            actionKeys: rule ? RuleActions.toKeys(rule.actions) : [],\n        })\n    }\n\n    getSourceRules = () => this.props.sources[parseInt(this.state.sid)].rules\n\n    ruleColumns = (): IColumn[] => [\n        {\n            isRowHeader: true,\n            key: \"regex\",\n            name: intl.get(\"rules.regex\"),\n            minWidth: 100,\n            maxWidth: 200,\n            onRender: (rule: SourceRule) => rule.filter.search,\n        },\n        {\n            key: \"actions\",\n            name: intl.get(\"rules.action\"),\n            minWidth: 100,\n            onRender: (rule: SourceRule) =>\n                RuleActions.toKeys(rule.actions)\n                    .map(k => intl.get(actionKeyMap[k]))\n                    .join(\", \"),\n        },\n    ]\n\n    handleInputChange = event => {\n        const name = event.target.name as \"regex\"\n        this.setState({ [name]: event.target.value })\n    }\n\n    sourceOptions = (): IDropdownOption[] =>\n        Object.entries(this.props.sources).map(([sid, s]) => ({\n            key: sid,\n            text: s.name,\n            data: { icon: s.iconurl },\n        }))\n    onRenderSourceOption = (option: IDropdownOption) => (\n        <div>\n            {option.data && option.data.icon && (\n                <img src={option.data.icon} className=\"favicon dropdown\" />\n            )}\n            <span>{option.text}</span>\n        </div>\n    )\n    onRenderSourceTitle = (options: IDropdownOption[]) => {\n        return this.onRenderSourceOption(options[0])\n    }\n    onSourceOptionChange = (_, item: IDropdownOption) => {\n        this.initRuleEdit()\n        this.rulesSelection.setAllSelected(false)\n        this.setState({\n            sid: item.key as string,\n            selectedRules: [],\n            editIndex: -1,\n            mockTitle: \"\",\n            mockCreator: \"\",\n            mockContent: \"\",\n            mockResult: \"\",\n        })\n    }\n\n    searchOptions = (): IDropdownOption[] => [\n        { key: 0, text: intl.get(\"rules.title\") },\n        { key: 1, text: intl.get(\"rules.fullSearch\") },\n        { key: 2, text: intl.get(\"rules.creator\") },\n    ]\n    onSearchOptionChange = (_, item: IDropdownOption) => {\n        this.setState({ searchType: item.key as number })\n    }\n\n    matchOptions = (): IDropdownOption[] => [\n        { key: 1, text: intl.get(\"rules.match\") },\n        { key: 0, text: intl.get(\"rules.notMatch\") },\n    ]\n    onMatchOptionChange = (_, item: IDropdownOption) => {\n        this.setState({ match: Boolean(item.key) })\n    }\n\n    actionOptions = (): IDropdownOption[] =>\n        [\n            ...Object.entries(actionKeyMap).map(([k, t], i) => {\n                if (k.includes(\"-false\")) {\n                    return [\n                        { key: k, text: intl.get(t) },\n                        {\n                            key: i,\n                            text: \"-\",\n                            itemType: DropdownMenuItemType.Divider,\n                        },\n                    ]\n                } else {\n                    return [{ key: k, text: intl.get(t) }]\n                }\n            }),\n        ].flat(1)\n\n    onActionOptionChange = (_, item: IDropdownOption) => {\n        if (item.selected) {\n            this.setState(prevState => {\n                let [a, f] = (item.key as string).split(\"-\")\n                let keys = prevState.actionKeys.filter(\n                    k => !k.startsWith(`${a}-`)\n                )\n                keys.push(item.key as string)\n                return { actionKeys: keys }\n            })\n        } else {\n            this.setState(prevState => ({\n                actionKeys: prevState.actionKeys.filter(k => k !== item.key),\n            }))\n        }\n    }\n\n    validateRegexField = (value: string) => {\n        if (value.length === 0) return intl.get(\"emptyField\")\n        else if (validateRegex(value) === null)\n            return intl.get(\"rules.badRegex\")\n        else return \"\"\n    }\n\n    saveRule = () => {\n        let filterType = FilterType.Default | FilterType.ShowHidden\n        if (!this.state.caseSensitive) filterType |= FilterType.CaseInsensitive\n        if (this.state.searchType === 1) filterType |= FilterType.FullSearch\n        else if (this.state.searchType === 2)\n            filterType |= FilterType.CreatorSearch\n        let rule = new SourceRule(\n            this.state.regex,\n            this.state.actionKeys,\n            filterType,\n            this.state.match\n        )\n        let source = this.props.sources[parseInt(this.state.sid)]\n        let rules = source.rules ? [...source.rules] : []\n        if (this.state.editIndex === -1) {\n            rules.push(rule)\n        } else {\n            rules.splice(this.state.editIndex, 1, rule)\n        }\n        this.props.updateSourceRules(source, rules)\n        this.setState({ editIndex: -1 })\n        this.initRuleEdit()\n    }\n    newRule = () => {\n        this.initRuleEdit()\n        this.setState({ editIndex: this.getSourceRules().length })\n    }\n    editRule = (rule: SourceRule, index: number) => {\n        this.initRuleEdit(rule)\n        this.setState({ editIndex: index })\n    }\n    deleteRules = () => {\n        let rules = this.getSourceRules()\n        for (let i of this.state.selectedRules) rules[i] = null\n        let source = this.props.sources[parseInt(this.state.sid)]\n        this.props.updateSourceRules(\n            source,\n            rules.filter(r => r !== null)\n        )\n        this.initRuleEdit()\n    }\n\n    commandBarItems = (): ICommandBarItemProps[] => [\n        {\n            key: \"new\",\n            text: intl.get(\"rules.new\"),\n            iconProps: { iconName: \"Add\" },\n            onClick: this.newRule,\n        },\n    ]\n    commandBarFarItems = (): ICommandBarItemProps[] => {\n        let items = []\n        if (this.state.selectedRules.length === 1) {\n            let index = this.state.selectedRules[0]\n            items.push({\n                key: \"edit\",\n                text: intl.get(\"edit\"),\n                iconProps: { iconName: \"Edit\" },\n                onClick: () =>\n                    this.editRule(this.getSourceRules()[index], index),\n            })\n        }\n        if (this.state.selectedRules.length > 0) {\n            items.push({\n                key: \"del\",\n                text: intl.get(\"delete\"),\n                iconProps: { iconName: \"Delete\", style: { color: \"#d13438\" } },\n                onClick: this.deleteRules,\n            })\n        }\n        return items\n    }\n\n    testMockItem = () => {\n        let parsed = { title: this.state.mockTitle }\n        let source = this.props.sources[parseInt(this.state.sid)]\n        let item = new RSSItem(parsed as MyParserItem, source)\n        item.snippet = this.state.mockContent\n        item.creator = this.state.mockCreator\n        SourceRule.applyAll(this.getSourceRules(), item)\n        let result = []\n        result.push(\n            intl.get(item.hasRead ? \"article.markRead\" : \"article.markUnread\")\n        )\n        if (item.starred) result.push(intl.get(\"article.star\"))\n        if (item.hidden) result.push(intl.get(\"article.hide\"))\n        if (item.notify) result.push(intl.get(\"article.notify\"))\n        this.setState({ mockResult: result.join(\", \") })\n    }\n\n    toggleCaseSensitivity = () => {\n        this.setState({ caseSensitive: !this.state.caseSensitive })\n    }\n    regexCaseIconProps = (): IIconProps => ({\n        title: intl.get(\"context.caseSensitive\"),\n        children: \"Aa\",\n        style: {\n            fontSize: 12,\n            fontStyle: \"normal\",\n            cursor: \"pointer\",\n            pointerEvents: \"unset\",\n            color: this.state.caseSensitive\n                ? \"var(--black)\"\n                : \"var(--neutralTertiary)\",\n            textDecoration: this.state.caseSensitive ? \"underline\" : \"\",\n        },\n        onClick: this.toggleCaseSensitivity,\n    })\n\n    render = () => (\n        <div className=\"tab-body\">\n            <Stack horizontal tokens={{ childrenGap: 16 }}>\n                <Stack.Item>\n                    <Label>{intl.get(\"rules.source\")}</Label>\n                </Stack.Item>\n                <Stack.Item grow>\n                    <Dropdown\n                        placeholder={intl.get(\"rules.selectSource\")}\n                        options={this.sourceOptions()}\n                        onRenderOption={this.onRenderSourceOption}\n                        onRenderTitle={this.onRenderSourceTitle}\n                        selectedKey={this.state.sid}\n                        onChange={this.onSourceOptionChange}\n                    />\n                </Stack.Item>\n            </Stack>\n\n            {this.state.sid ? (\n                this.state.editIndex > -1 ||\n                !this.getSourceRules() ||\n                this.getSourceRules().length === 0 ? (\n                    <>\n                        <Label>\n                            {intl.get(\n                                this.state.editIndex >= 0 &&\n                                    this.state.editIndex <\n                                        this.getSourceRules().length\n                                    ? \"edit\"\n                                    : \"rules.new\"\n                            )}\n                        </Label>\n                        <Stack horizontal>\n                            <Stack.Item>\n                                <Label>{intl.get(\"rules.if\")}</Label>\n                            </Stack.Item>\n                            <Stack.Item>\n                                <Dropdown\n                                    options={this.searchOptions()}\n                                    selectedKey={this.state.searchType}\n                                    onChange={this.onSearchOptionChange}\n                                    style={{ width: 140 }}\n                                />\n                            </Stack.Item>\n                            <Stack.Item>\n                                <Dropdown\n                                    options={this.matchOptions()}\n                                    selectedKey={this.state.match ? 1 : 0}\n                                    onChange={this.onMatchOptionChange}\n                                    style={{ width: 130 }}\n                                />\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <TextField\n                                    name=\"regex\"\n                                    placeholder={intl.get(\"rules.regex\")}\n                                    iconProps={this.regexCaseIconProps()}\n                                    value={this.state.regex}\n                                    onGetErrorMessage={this.validateRegexField}\n                                    validateOnLoad={false}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                        <Stack horizontal>\n                            <Stack.Item>\n                                <Label>{intl.get(\"rules.then\")}</Label>\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <Dropdown\n                                    multiSelect\n                                    placeholder={intl.get(\"rules.selectAction\")}\n                                    options={this.actionOptions()}\n                                    selectedKeys={this.state.actionKeys}\n                                    onChange={this.onActionOptionChange}\n                                    onRenderCaretDown={() => (\n                                        <Icon iconName=\"CirclePlus\" />\n                                    )}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                        <Stack horizontal>\n                            <Stack.Item>\n                                <PrimaryButton\n                                    disabled={\n                                        this.state.regex.length == 0 ||\n                                        validateRegex(this.state.regex) ===\n                                            null ||\n                                        this.state.actionKeys.length == 0\n                                    }\n                                    text={intl.get(\"confirm\")}\n                                    onClick={this.saveRule}\n                                />\n                            </Stack.Item>\n                            {this.state.editIndex > -1 && (\n                                <Stack.Item>\n                                    <DefaultButton\n                                        text={intl.get(\"cancel\")}\n                                        onClick={() =>\n                                            this.setState({ editIndex: -1 })\n                                        }\n                                    />\n                                </Stack.Item>\n                            )}\n                        </Stack>\n                    </>\n                ) : (\n                    <>\n                        <CommandBar\n                            items={this.commandBarItems()}\n                            farItems={this.commandBarFarItems()}\n                        />\n                        <MarqueeSelection\n                            selection={this.rulesSelection}\n                            isDraggingConstrainedToRoot>\n                            <DetailsList\n                                compact\n                                columns={this.ruleColumns()}\n                                items={this.getSourceRules()}\n                                onItemInvoked={this.editRule}\n                                dragDropEvents={this.rulesDragDropEvents}\n                                setKey=\"selected\"\n                                selection={this.rulesSelection}\n                                selectionMode={SelectionMode.multiple}\n                            />\n                        </MarqueeSelection>\n                        <span className=\"settings-hint up\">\n                            {intl.get(\"rules.hint\")}\n                        </span>\n\n                        <Label>{intl.get(\"rules.test\")}</Label>\n                        <Stack horizontal>\n                            <Stack.Item grow>\n                                <TextField\n                                    name=\"mockTitle\"\n                                    placeholder={intl.get(\"rules.title\")}\n                                    value={this.state.mockTitle}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <TextField\n                                    name=\"mockCreator\"\n                                    placeholder={intl.get(\"rules.creator\")}\n                                    value={this.state.mockCreator}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                        <Stack horizontal>\n                            <Stack.Item grow>\n                                <TextField\n                                    name=\"mockContent\"\n                                    placeholder={intl.get(\"rules.content\")}\n                                    value={this.state.mockContent}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                            <Stack.Item>\n                                <PrimaryButton\n                                    text={intl.get(\"confirm\")}\n                                    onClick={this.testMockItem}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                        <span className=\"settings-hint up\">\n                            {this.state.mockResult}\n                        </span>\n                    </>\n                )\n            ) : (\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 64 }}>\n                    <Stack\n                        className=\"settings-rules-icons\"\n                        horizontal\n                        tokens={{ childrenGap: 12 }}>\n                        <Icon iconName=\"Filter\" />\n                        <Icon iconName=\"FavoriteStar\" />\n                        <Icon iconName=\"Ringer\" />\n                        <Icon iconName=\"More\" />\n                    </Stack>\n                    <span className=\"settings-hint\">\n                        {intl.get(\"rules.intro\")}\n                        <Link\n                            onClick={() =>\n                                window.utils.openExternal(\n                                    \"https://github.com/yang991178/fluent-reader/wiki/Support#rules\"\n                                )\n                            }\n                            style={{ marginLeft: 6 }}>\n                            {intl.get(\"rules.help\")}\n                        </Link>\n                    </span>\n                </Stack>\n            )}\n        </div>\n    )\n}\n\nexport default RulesTab\n"
  },
  {
    "path": "src/components/settings/service.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigs, SyncService } from \"../../schema-types\"\nimport { Stack, Icon, Link, Dropdown, IDropdownOption } from \"@fluentui/react\"\nimport FeverConfigsTab from \"./services/fever\"\nimport FeedbinConfigsTab from \"./services/feedbin\"\nimport GReaderConfigsTab from \"./services/greader\"\nimport InoreaderConfigsTab from \"./services/inoreader\"\nimport MinifluxConfigsTab from \"./services/miniflux\"\nimport NextcloudConfigsTab from \"./services/nextcloud\"\n\ntype ServiceTabProps = {\n    configs: ServiceConfigs\n    save: (configs: ServiceConfigs) => void\n    sync: () => Promise<void>\n    remove: () => Promise<void>\n    blockActions: () => void\n    authenticate: (configs: ServiceConfigs) => Promise<boolean>\n    reauthenticate: (configs: ServiceConfigs) => Promise<ServiceConfigs>\n}\n\nexport type ServiceConfigsTabProps = ServiceTabProps & {\n    exit: () => void\n}\n\ntype ServiceTabState = {\n    type: SyncService\n}\n\nexport class ServiceTab extends React.Component<\n    ServiceTabProps,\n    ServiceTabState\n> {\n    constructor(props: ServiceTabProps) {\n        super(props)\n        this.state = {\n            type: props.configs.type,\n        }\n    }\n\n    serviceOptions = (): IDropdownOption[] => [\n        { key: SyncService.Fever, text: \"Fever API\" },\n        { key: SyncService.Feedbin, text: \"Feedbin\" },\n        { key: SyncService.GReader, text: \"Google Reader API (Beta)\" },\n        { key: SyncService.Inoreader, text: \"Inoreader\" },\n        { key: SyncService.Miniflux, text: \"Miniflux\" },\n        { key: SyncService.Nextcloud, text: \"Nextcloud News API\" },\n        { key: -1, text: intl.get(\"service.suggest\") },\n    ]\n\n    onServiceOptionChange = (_, option: IDropdownOption) => {\n        if (option.key === -1) {\n            window.utils.openExternal(\n                \"https://github.com/yang991178/fluent-reader/issues/23\"\n            )\n        } else {\n            this.setState({ type: option.key as number })\n        }\n    }\n\n    exitConfigsTab = () => {\n        this.setState({ type: SyncService.None })\n    }\n\n    getConfigsTab = () => {\n        switch (this.state.type) {\n            case SyncService.Fever:\n                return (\n                    <FeverConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            case SyncService.Feedbin:\n                return (\n                    <FeedbinConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            case SyncService.GReader:\n                return (\n                    <GReaderConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            case SyncService.Inoreader:\n                return (\n                    <InoreaderConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            case SyncService.Miniflux:\n                return (\n                    <MinifluxConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            case SyncService.Nextcloud:\n                return (\n                    <NextcloudConfigsTab\n                        {...this.props}\n                        exit={this.exitConfigsTab}\n                    />\n                )\n            default:\n                return null\n        }\n    }\n\n    render = () => (\n        <div className=\"tab-body\">\n            {this.state.type === SyncService.None ? (\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 64 }}>\n                    <Stack\n                        className=\"settings-rules-icons\"\n                        horizontal\n                        tokens={{ childrenGap: 12 }}>\n                        <Icon iconName=\"ThisPC\" />\n                        <Icon iconName=\"Sync\" />\n                        <Icon iconName=\"Cloud\" />\n                    </Stack>\n                    <span className=\"settings-hint\">\n                        {intl.get(\"service.intro\")}\n                        <Link\n                            onClick={() =>\n                                window.utils.openExternal(\n                                    \"https://github.com/yang991178/fluent-reader/wiki/Support#services\"\n                                )\n                            }\n                            style={{ marginLeft: 6 }}>\n                            {intl.get(\"rules.help\")}\n                        </Link>\n                    </span>\n                    <Dropdown\n                        placeHolder={intl.get(\"service.select\")}\n                        options={this.serviceOptions()}\n                        selectedKey={null}\n                        onChange={this.onServiceOptionChange}\n                        style={{ marginTop: 32, width: 180 }}\n                    />\n                </Stack>\n            ) : (\n                this.getConfigsTab()\n            )}\n        </div>\n    )\n}\n"
  },
  {
    "path": "src/components/settings/services/feedbin.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { FeedbinConfigs } from \"../../../scripts/models/services/feedbin\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Icon,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport { urlTest } from \"../../../scripts/utils\"\nimport LiteExporter from \"./lite-exporter\"\n\ntype FeedbinConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    importGroups: boolean\n}\n\nclass FeedbinConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    FeedbinConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as FeedbinConfigs\n        this.state = {\n            existing: configs.type === SyncService.Feedbin,\n            endpoint: configs.endpoint || \"https://api.feedbin.me/v2/\",\n            username: configs.username || \"\",\n            password: \"\",\n            fetchLimit: configs.fetchLimit || 250,\n            importGroups: true,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        { key: 1500, text: intl.get(\"service.fetchLimitNum\", { count: 1500 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            urlTest(this.state.endpoint.trim()) &&\n            (this.state.existing ||\n                (this.state.username && this.state.password))\n        )\n    }\n\n    save = async () => {\n        let configs: FeedbinConfigs\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n            } as FeedbinConfigs\n            if (this.state.password) configs.password = this.state.password\n        } else {\n            configs = {\n                type: SyncService.Feedbin,\n                endpoint: this.state.endpoint,\n                username: this.state.username,\n                password: this.state.password,\n                fetchLimit: this.state.fetchLimit,\n            }\n            if (this.state.importGroups) configs.importGroups = true\n        }\n        this.props.blockActions()\n        const valid = await this.props.authenticate(configs)\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <svg\n                        style={{\n                            fill: \"var(--black)\",\n                            width: 32,\n                            userSelect: \"none\",\n                        }}\n                        viewBox=\"0 0 120 120\">\n                        <path d=\"M116.4,87.2c-22.5-0.1-96.9-0.1-112.4,0c-4.9,0-4.8-22.5,0-23.3c15.6-2.5,60.3,0,60.3,0s16.1,16.3,20.8,16.3  c4.8,0,16.1-16.3,16.1-16.3s12.8-2.3,15.2,0C120.3,67.9,121.2,87.3,116.4,87.2z\" />\n                        <path d=\"M110.9,108.8L110.9,108.8c-19.1,2.5-83.6,1.9-103,0c-4.3-0.4-1.5-13.6-1.5-13.6h108.1  C114.4,95.2,116.3,108.1,110.9,108.8z\" />\n                        <path d=\"M58.1,9.9C30.6,6.2,7.9,29.1,7.9,51.3l102.6,1C110.6,30.2,85.4,13.6,58.1,9.9z\" />\n                    </svg>\n                    <Label style={{ margin: \"8px 0 36px\" }}>Feedbin</Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"sources.badUrl\")\n                                }\n                                validateOnLoad={false}\n                                name=\"endpoint\"\n                                value={this.state.endpoint}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>Email</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                disabled={this.state.existing}\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"username\"\n                                value={this.state.username}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.password\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                type=\"password\"\n                                placeholder={\n                                    this.state.existing\n                                        ? intl.get(\"service.unchanged\")\n                                        : \"\"\n                                }\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"password\"\n                                value={this.state.password}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.existing && (\n                        <Checkbox\n                            label={intl.get(\"service.importGroups\")}\n                            checked={this.state.importGroups}\n                            onChange={(_, c) =>\n                                this.setState({ importGroups: c })\n                            }\n                        />\n                    )}\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                    {this.state.existing && (\n                        <LiteExporter serviceConfigs={this.props.configs} />\n                    )}\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default FeedbinConfigsTab\n"
  },
  {
    "path": "src/components/settings/services/fever.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport md5 from \"js-md5\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { FeverConfigs } from \"../../../scripts/models/services/fever\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Icon,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport { urlTest } from \"../../../scripts/utils\"\nimport LiteExporter from \"./lite-exporter\"\n\ntype FeverConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    importGroups: boolean\n}\n\nclass FeverConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    FeverConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as FeverConfigs\n        this.state = {\n            existing: configs.type === SyncService.Fever,\n            endpoint: configs.endpoint || \"\",\n            username: configs.username || \"\",\n            password: \"\",\n            fetchLimit: configs.fetchLimit || 250,\n            importGroups: true,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        { key: 1500, text: intl.get(\"service.fetchLimitNum\", { count: 1500 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            urlTest(this.state.endpoint.trim()) &&\n            (this.state.existing ||\n                (this.state.username && this.state.password))\n        )\n    }\n\n    save = async () => {\n        let configs: FeverConfigs\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n            } as FeverConfigs\n            if (this.state.password)\n                configs.apiKey = md5(\n                    `${configs.username}:${this.state.password}`\n                )\n        } else {\n            configs = {\n                type: SyncService.Fever,\n                endpoint: this.state.endpoint,\n                username: this.state.username,\n                fetchLimit: this.state.fetchLimit,\n                apiKey: md5(`${this.state.username}:${this.state.password}`),\n            }\n            if (this.state.importGroups) configs.importGroups = true\n        }\n        this.props.blockActions()\n        const valid = await this.props.authenticate(configs)\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <Icon\n                        iconName=\"Calories\"\n                        style={{\n                            color: \"var(--black)\",\n                            fontSize: 32,\n                            userSelect: \"none\",\n                        }}\n                    />\n                    <Label style={{ margin: \"8px 0 36px\" }}>Fever API</Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"sources.badUrl\")\n                                }\n                                validateOnLoad={false}\n                                name=\"endpoint\"\n                                value={this.state.endpoint}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.username\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                disabled={this.state.existing}\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"username\"\n                                value={this.state.username}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.password\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                type=\"password\"\n                                placeholder={\n                                    this.state.existing\n                                        ? intl.get(\"service.unchanged\")\n                                        : \"\"\n                                }\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"password\"\n                                value={this.state.password}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.existing && (\n                        <Checkbox\n                            label={intl.get(\"service.importGroups\")}\n                            checked={this.state.importGroups}\n                            onChange={(_, c) =>\n                                this.setState({ importGroups: c })\n                            }\n                        />\n                    )}\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                    {this.state.existing && (\n                        <LiteExporter serviceConfigs={this.props.configs} />\n                    )}\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default FeverConfigsTab\n"
  },
  {
    "path": "src/components/settings/services/greader.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { GReaderConfigs } from \"../../../scripts/models/services/greader\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Icon,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport { urlTest } from \"../../../scripts/utils\"\nimport LiteExporter from \"./lite-exporter\"\n\ntype GReaderConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    importGroups: boolean\n}\n\nclass GReaderConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    GReaderConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as GReaderConfigs\n        this.state = {\n            existing: configs.type === SyncService.GReader,\n            endpoint: configs.endpoint || \"\",\n            username: configs.username || \"\",\n            password: \"\",\n            fetchLimit: configs.fetchLimit || 250,\n            importGroups: true,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        { key: 1500, text: intl.get(\"service.fetchLimitNum\", { count: 1500 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            urlTest(this.state.endpoint.trim()) &&\n            (this.state.existing ||\n                (this.state.username && this.state.password))\n        )\n    }\n\n    save = async () => {\n        let configs: GReaderConfigs\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n            } as GReaderConfigs\n            if (this.state.password) configs.password = this.state.password\n        } else {\n            configs = {\n                type: SyncService.GReader,\n                endpoint: this.state.endpoint,\n                username: this.state.username,\n                password: this.state.password,\n                fetchLimit: this.state.fetchLimit,\n                useInt64: !this.state.endpoint.endsWith(\"theoldreader.com\"),\n            }\n            if (this.state.importGroups) configs.importGroups = true\n        }\n        this.props.blockActions()\n        configs = (await this.props.reauthenticate(configs)) as GReaderConfigs\n        const valid = await this.props.authenticate(configs)\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <Icon\n                        iconName=\"Communications\"\n                        style={{\n                            color: \"var(--black)\",\n                            transform: \"rotate(220deg)\",\n                            fontSize: 32,\n                            userSelect: \"none\",\n                        }}\n                    />\n                    <Label style={{ margin: \"8px 0 36px\" }}>\n                        Google Reader API\n                    </Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"sources.badUrl\")\n                                }\n                                validateOnLoad={false}\n                                name=\"endpoint\"\n                                value={this.state.endpoint}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.username\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                disabled={this.state.existing}\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"username\"\n                                value={this.state.username}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.password\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                type=\"password\"\n                                placeholder={\n                                    this.state.existing\n                                        ? intl.get(\"service.unchanged\")\n                                        : \"\"\n                                }\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"password\"\n                                value={this.state.password}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.existing && (\n                        <Checkbox\n                            label={intl.get(\"service.importGroups\")}\n                            checked={this.state.importGroups}\n                            onChange={(_, c) =>\n                                this.setState({ importGroups: c })\n                            }\n                        />\n                    )}\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                    {this.state.existing && (\n                        <LiteExporter serviceConfigs={this.props.configs} />\n                    )}\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default GReaderConfigsTab\n"
  },
  {
    "path": "src/components/settings/services/inoreader.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { GReaderConfigs } from \"../../../scripts/models/services/greader\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n    MessageBarButton,\n    Link,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport LiteExporter from \"./lite-exporter\"\n\ntype GReaderConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    username: string\n    password: string\n    apiId: string\n    apiKey: string\n    removeAd: boolean\n    fetchLimit: number\n}\n\nconst endpointOptions: IDropdownOption[] = [\n    \"https://www.inoreader.com\",\n    \"https://www.innoreader.com\",\n    \"https://jp.inoreader.com\",\n].map(s => ({ key: s, text: s }))\n\nconst openSupport = () =>\n    window.utils.openExternal(\n        \"https://github.com/yang991178/fluent-reader/wiki/Support#inoreader\"\n    )\n\nclass InoreaderConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    GReaderConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as GReaderConfigs\n        this.state = {\n            existing: configs.type === SyncService.Inoreader,\n            endpoint: configs.endpoint || \"https://www.inoreader.com\",\n            username: configs.username || \"\",\n            password: \"\",\n            apiId: configs.inoreaderId || \"\",\n            apiKey: configs.inoreaderKey || \"\",\n            removeAd:\n                configs.removeInoreaderAd === undefined\n                    ? true\n                    : configs.removeInoreaderAd,\n            fetchLimit: configs.fetchLimit || 250,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n    onEndpointChange = (_, option: IDropdownOption) => {\n        this.setState({ endpoint: option.key as string })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            (this.state.existing ||\n                (this.state.username && this.state.password)) &&\n            this.state.apiId &&\n            this.state.apiKey\n        )\n    }\n\n    save = async () => {\n        let configs: GReaderConfigs\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n                inoreaderId: this.state.apiId,\n                inoreaderKey: this.state.apiKey,\n                removeInoreaderAd: this.state.removeAd,\n            } as GReaderConfigs\n            if (this.state.password) configs.password = this.state.password\n        } else {\n            configs = {\n                type: SyncService.Inoreader,\n                endpoint: this.state.endpoint,\n                username: this.state.username,\n                password: this.state.password,\n                inoreaderId: this.state.apiId,\n                inoreaderKey: this.state.apiKey,\n                removeInoreaderAd: this.state.removeAd,\n                fetchLimit: this.state.fetchLimit,\n                importGroups: true,\n                useInt64: true,\n            }\n        }\n        this.props.blockActions()\n        configs = (await this.props.reauthenticate(configs)) as GReaderConfigs\n        const valid = await this.props.authenticate(configs)\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    createKey = () =>\n        window.utils.openExternal(\n            this.state.endpoint + \"/all_articles#preferences-developer\"\n        )\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                <MessageBar\n                    messageBarType={MessageBarType.severeWarning}\n                    isMultiline={false}\n                    actions={\n                        <MessageBarButton\n                            text={intl.get(\"create\")}\n                            onClick={this.createKey}\n                        />\n                    }>\n                    {intl.get(\"service.rateLimitWarning\")}\n                    <Link onClick={openSupport} style={{ marginLeft: 6 }}>\n                        {intl.get(\"rules.help\")}\n                    </Link>\n                </MessageBar>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <svg\n                        style={{\n                            fill: \"var(--black)\",\n                            width: 36,\n                            userSelect: \"none\",\n                        }}\n                        viewBox=\"0 0 72 72\">\n                        <path\n                            transform=\"translate(-1250.000000, -1834.000000)\"\n                            d=\"M1286,1834 C1305.88225,1834 1322,1850.11775 1322,1870 C1322,1889.88225 1305.88225,1906 1286,1906 C1266.11775,1906 1250,1889.88225 1250,1870 C1250,1850.11775 1266.11775,1834 1286,1834 Z M1278.01029,1864.98015 C1270.82534,1864.98015 1265,1870.80399 1265,1877.98875 C1265,1885.17483 1270.82534,1891 1278.01029,1891 C1285.19326,1891 1291.01859,1885.17483 1291.01859,1877.98875 C1291.01859,1870.80399 1285.19326,1864.98015 1278.01029,1864.98015 Z M1281.67908,1870.54455 C1283.73609,1870.54455 1285.40427,1872.21533 1285.40427,1874.2703 C1285.40427,1876.33124 1283.73609,1877.9987 1281.67908,1877.9987 C1279.61941,1877.9987 1277.94991,1876.33124 1277.94991,1874.2703 C1277.94991,1872.21533 1279.61941,1870.54455 1281.67908,1870.54455 Z M1278.01003,1855.78714 L1278.01003,1860.47435 C1287.66605,1860.47435 1295.52584,1868.33193 1295.52584,1877.98901 L1295.52584,1877.98901 L1300.21451,1877.98901 C1300.21451,1865.74746 1290.25391,1855.78714 1278.01003,1855.78714 L1278.01003,1855.78714 Z M1278.01009,1846 L1278.01009,1850.68721 C1285.30188,1850.68721 1292.15771,1853.5278 1297.31618,1858.68479 C1302.47398,1863.84179 1305.31067,1870.69942 1305.31067,1877.98901 L1305.31067,1877.98901 L1310,1877.98901 C1310,1869.44534 1306.67162,1861.41192 1300.6293,1855.36845 C1294.58632,1849.32696 1286.55533,1846 1278.01009,1846 L1278.01009,1846 Z\"></path>\n                    </svg>\n                    <Label style={{ margin: \"8px 0 36px\" }}>Inoreader</Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={endpointOptions}\n                                selectedKey={this.state.endpoint}\n                                onChange={this.onEndpointChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.username\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                disabled={this.state.existing}\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"username\"\n                                value={this.state.username}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.password\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                type=\"password\"\n                                placeholder={\n                                    this.state.existing\n                                        ? intl.get(\"service.unchanged\")\n                                        : \"\"\n                                }\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"password\"\n                                value={this.state.password}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>API ID</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"apiId\"\n                                value={this.state.apiId}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>API Key</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"apiKey\"\n                                value={this.state.apiKey}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Checkbox\n                        label={intl.get(\"service.removeAd\")}\n                        checked={this.state.removeAd}\n                        onChange={(_, c) => this.setState({ removeAd: c })}\n                    />\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                    {this.state.existing && (\n                        <LiteExporter serviceConfigs={this.props.configs} />\n                    )}\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default InoreaderConfigsTab\n"
  },
  {
    "path": "src/components/settings/services/lite-exporter.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport {\n    Stack,\n    ContextualMenuItemType,\n    DefaultButton,\n    IContextualMenuProps,\n    DirectionalHint,\n} from \"@fluentui/react\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { renderShareQR } from \"../../context-menu\"\nimport { platformCtrl } from \"../../../scripts/utils\"\nimport { FeverConfigs } from \"../../../scripts/models/services/fever\"\nimport { GReaderConfigs } from \"../../../scripts/models/services/greader\"\nimport { FeedbinConfigs } from \"../../../scripts/models/services/feedbin\"\n\ntype LiteExporterProps = {\n    serviceConfigs: ServiceConfigs\n}\n\nconst LEARN_MORE_URL =\n    \"https://github.com/yang991178/fluent-reader/wiki/Support#mobile-app\"\n\nconst LiteExporter: React.FunctionComponent<LiteExporterProps> = props => {\n    let url = \"https://hyliu.me/fr2l/?\"\n    const params = new URLSearchParams()\n    switch (props.serviceConfigs.type) {\n        case SyncService.Fever: {\n            const configs = props.serviceConfigs as FeverConfigs\n            params.set(\"t\", \"f\")\n            params.set(\"e\", configs.endpoint)\n            params.set(\"u\", configs.username)\n            params.set(\"k\", configs.apiKey)\n            break\n        }\n        case SyncService.GReader:\n        case SyncService.Inoreader: {\n            const configs = props.serviceConfigs as GReaderConfigs\n            params.set(\"t\", configs.type == SyncService.GReader ? \"g\" : \"i\")\n            params.set(\"e\", configs.endpoint)\n            params.set(\"u\", configs.username)\n            params.set(\"p\", btoa(configs.password))\n            if (configs.inoreaderId) {\n                params.set(\"i\", configs.inoreaderId)\n                params.set(\"k\", configs.inoreaderKey)\n            }\n            break\n        }\n        case SyncService.Feedbin: {\n            const configs = props.serviceConfigs as FeedbinConfigs\n            params.set(\"t\", \"fb\")\n            params.set(\"e\", configs.endpoint)\n            params.set(\"u\", configs.username)\n            params.set(\"p\", btoa(configs.password))\n            break\n        }\n    }\n    url += params.toString()\n    const menuProps: IContextualMenuProps = {\n        directionalHint: DirectionalHint.bottomCenter,\n        items: [\n            { key: \"qr\", url: url, onRender: renderShareQR },\n            { key: \"divider_1\", itemType: ContextualMenuItemType.Divider },\n            {\n                key: \"openInBrowser\",\n                text: intl.get(\"rules.help\"),\n                iconProps: { iconName: \"NavigateExternalInline\" },\n                onClick: e => {\n                    window.utils.openExternal(LEARN_MORE_URL, platformCtrl(e))\n                },\n            },\n        ],\n    }\n    return (\n        <Stack style={{ marginTop: 32 }}>\n            <DefaultButton\n                text={intl.get(\"service.exportToLite\")}\n                onRenderMenuIcon={() => <></>}\n                menuProps={menuProps}\n            />\n        </Stack>\n    )\n}\n\nexport default LiteExporter\n"
  },
  {
    "path": "src/components/settings/services/miniflux.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Icon,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport { urlTest } from \"../../../scripts/utils\"\nimport { MinifluxConfigs } from \"../../../scripts/models/services/miniflux\"\n\ntype MinifluxConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    apiKeyAuth: boolean\n    username: string\n    password: string\n    apiKey: string\n    fetchLimit: number\n    importGroups: boolean\n}\n\nclass MinifluxConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    MinifluxConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as MinifluxConfigs\n        this.state = {\n            existing: configs.type === SyncService.Miniflux,\n            endpoint: configs.endpoint || \"\",\n            apiKeyAuth: true,\n            username: \"\",\n            password: \"\",\n            apiKey: \"\",\n            fetchLimit: configs.fetchLimit || 250,\n            importGroups: true,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        { key: 1500, text: intl.get(\"service.fetchLimitNum\", { count: 1500 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n\n    authenticationOptions = (): IDropdownOption[] => [\n        { key: \"apiKey\", text: \"API Key\" /*intl.get(\"service.password\")*/ },\n        {\n            key: \"userPass\",\n            text:\n                intl.get(\"service.username\") +\n                \"/\" +\n                intl.get(\"service.password\"),\n        },\n    ]\n    onAuthenticationOptionsChange = (_, option: IDropdownOption) => {\n        this.setState({ apiKeyAuth: option.key == \"apiKey\" })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            urlTest(this.state.endpoint.trim()) &&\n            (this.state.existing ||\n                this.state.apiKey ||\n                (this.state.username && this.state.password))\n        )\n    }\n\n    save = async () => {\n        let configs: MinifluxConfigs\n\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n            } as MinifluxConfigs\n\n            if (this.state.apiKey || this.state.password)\n                configs.authKey = this.state.apiKeyAuth\n                    ? this.state.apiKey\n                    : Buffer.from(\n                          this.state.username + \":\" + this.state.password,\n                          \"binary\"\n                      ).toString(\"base64\")\n        } else {\n            configs = {\n                type: SyncService.Miniflux,\n                endpoint: this.state.endpoint,\n                apiKeyAuth: this.state.apiKeyAuth,\n                authKey: this.state.apiKeyAuth\n                    ? this.state.apiKey\n                    : Buffer.from(\n                          this.state.username + \":\" + this.state.password,\n                          \"binary\"\n                      ).toString(\"base64\"),\n                fetchLimit: this.state.fetchLimit,\n            }\n\n            if (this.state.importGroups) configs.importGroups = true\n        }\n\n        this.props.blockActions()\n        const valid = await this.props.authenticate(configs)\n\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <Icon\n                        iconName=\"MarkDownLanguage\"\n                        style={{\n                            color: \"var(--black)\",\n                            fontSize: 32,\n                            userSelect: \"none\",\n                        }}\n                    />\n                    <Label style={{ margin: \"8px 0 36px\" }}>Miniflux</Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"sources.badUrl\")\n                                }\n                                validateOnLoad={false}\n                                name=\"endpoint\"\n                                value={this.state.endpoint}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"groups.type\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.authenticationOptions()}\n                                selectedKey={\n                                    this.state.apiKeyAuth\n                                        ? \"apiKey\"\n                                        : \"userPass\"\n                                }\n                                onChange={this.onAuthenticationOptionsChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {this.state.apiKeyAuth && (\n                        <Stack className=\"login-form\" horizontal>\n                            <Stack.Item>\n                                <Label>{intl.get(\"service.password\")}</Label>\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <TextField\n                                    type=\"password\"\n                                    placeholder={\n                                        this.state.existing\n                                            ? intl.get(\"service.unchanged\")\n                                            : \"\"\n                                    }\n                                    onGetErrorMessage={this.checkNotEmpty}\n                                    validateOnLoad={false}\n                                    name=\"apiKey\"\n                                    value={this.state.apiKey}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                    )}\n                    {!this.state.apiKeyAuth && (\n                        <Stack className=\"login-form\" horizontal>\n                            <Stack.Item>\n                                <Label>{intl.get(\"service.username\")}</Label>\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <TextField\n                                    disabled={this.state.existing}\n                                    onGetErrorMessage={this.checkNotEmpty}\n                                    validateOnLoad={false}\n                                    name=\"username\"\n                                    value={this.state.username}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                    )}\n                    {!this.state.apiKeyAuth && (\n                        <Stack className=\"login-form\" horizontal>\n                            <Stack.Item>\n                                <Label>{intl.get(\"service.password\")}</Label>\n                            </Stack.Item>\n                            <Stack.Item grow>\n                                <TextField\n                                    type=\"password\"\n                                    placeholder={\n                                        this.state.existing\n                                            ? intl.get(\"service.unchanged\")\n                                            : \"\"\n                                    }\n                                    onGetErrorMessage={this.checkNotEmpty}\n                                    validateOnLoad={false}\n                                    name=\"password\"\n                                    value={this.state.password}\n                                    onChange={this.handleInputChange}\n                                />\n                            </Stack.Item>\n                        </Stack>\n                    )}\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.existing && (\n                        <Checkbox\n                            label={intl.get(\"service.importGroups\")}\n                            checked={this.state.importGroups}\n                            onChange={(_, c) =>\n                                this.setState({ importGroups: c })\n                            }\n                        />\n                    )}\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default MinifluxConfigsTab\n"
  },
  {
    "path": "src/components/settings/services/nextcloud.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { ServiceConfigsTabProps } from \"../service\"\nimport { NextcloudConfigs } from \"../../../scripts/models/services/nextcloud\"\nimport { SyncService } from \"../../../schema-types\"\nimport {\n    Stack,\n    Icon,\n    Label,\n    TextField,\n    PrimaryButton,\n    DefaultButton,\n    Checkbox,\n    MessageBar,\n    MessageBarType,\n    Dropdown,\n    IDropdownOption,\n} from \"@fluentui/react\"\nimport DangerButton from \"../../utils/danger-button\"\nimport { urlTest } from \"../../../scripts/utils\"\n\ntype NextcloudConfigsTabState = {\n    existing: boolean\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    importGroups: boolean\n}\n\nclass NextcloudConfigsTab extends React.Component<\n    ServiceConfigsTabProps,\n    NextcloudConfigsTabState\n> {\n    constructor(props: ServiceConfigsTabProps) {\n        super(props)\n        const configs = props.configs as NextcloudConfigs\n        this.state = {\n            existing: configs.type === SyncService.Nextcloud,\n            endpoint: configs.endpoint || \"https://nextcloud.com/\",\n            username: configs.username || \"\",\n            password: \"\",\n            fetchLimit: configs.fetchLimit || 250,\n            importGroups: true,\n        }\n    }\n\n    fetchLimitOptions = (): IDropdownOption[] => [\n        { key: 250, text: intl.get(\"service.fetchLimitNum\", { count: 250 }) },\n        { key: 500, text: intl.get(\"service.fetchLimitNum\", { count: 500 }) },\n        { key: 750, text: intl.get(\"service.fetchLimitNum\", { count: 750 }) },\n        { key: 1000, text: intl.get(\"service.fetchLimitNum\", { count: 1000 }) },\n        { key: 1500, text: intl.get(\"service.fetchLimitNum\", { count: 1500 }) },\n        {\n            key: Number.MAX_SAFE_INTEGER,\n            text: intl.get(\"service.fetchUnlimited\"),\n        },\n    ]\n    onFetchLimitOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ fetchLimit: option.key as number })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        // @ts-expect-error\n        this.setState({ [name]: event.target.value })\n    }\n\n    checkNotEmpty = (v: string) => {\n        return !this.state.existing && v.length == 0\n            ? intl.get(\"emptyField\")\n            : \"\"\n    }\n\n    validateForm = () => {\n        return (\n            urlTest(this.state.endpoint.trim()) &&\n            (this.state.existing ||\n                (this.state.username && this.state.password))\n        )\n    }\n\n    save = async () => {\n        let configs: NextcloudConfigs\n        if (this.state.existing) {\n            configs = {\n                ...this.props.configs,\n                endpoint: this.state.endpoint,\n                fetchLimit: this.state.fetchLimit,\n            } as NextcloudConfigs\n            if (this.state.password) configs.password = this.state.password\n        } else {\n            configs = {\n                type: SyncService.Nextcloud,\n                endpoint: this.state.endpoint + \"index.php/apps/news/api/v1-3\",\n                username: this.state.username,\n                password: this.state.password,\n                fetchLimit: this.state.fetchLimit,\n            }\n            if (this.state.importGroups) configs.importGroups = true\n        }\n        this.props.blockActions()\n        const valid = await this.props.authenticate(configs)\n        if (valid) {\n            this.props.save(configs)\n            this.setState({ existing: true })\n            this.props.sync()\n        } else {\n            this.props.blockActions()\n            window.utils.showErrorBox(\n                intl.get(\"service.failure\"),\n                intl.get(\"service.failureHint\")\n            )\n        }\n    }\n\n    remove = async () => {\n        this.props.exit()\n        await this.props.remove()\n    }\n\n    render() {\n        return (\n            <>\n                {!this.state.existing && (\n                    <MessageBar messageBarType={MessageBarType.warning}>\n                        {intl.get(\"service.overwriteWarning\")}\n                    </MessageBar>\n                )}\n                <Stack horizontalAlign=\"center\" style={{ marginTop: 48 }}>\n                    <Icon\n                        iconName=\"AlignLeft\"\n                        style={{\n                            color: \"var(--black)\",\n                            fontSize: 32,\n                            userSelect: \"none\",\n                        }}\n                    />\n                    <Label style={{ margin: \"8px 0 36px\" }}>Nextcloud</Label>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.endpoint\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                onGetErrorMessage={v =>\n                                    urlTest(v.trim())\n                                        ? \"\"\n                                        : intl.get(\"sources.badUrl\")\n                                }\n                                validateOnLoad={false}\n                                name=\"endpoint\"\n                                value={this.state.endpoint}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.username\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                disabled={this.state.existing}\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"username\"\n                                value={this.state.username}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.password\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <TextField\n                                type=\"password\"\n                                placeholder={\n                                    this.state.existing\n                                        ? intl.get(\"service.unchanged\")\n                                        : \"\"\n                                }\n                                onGetErrorMessage={this.checkNotEmpty}\n                                validateOnLoad={false}\n                                name=\"password\"\n                                value={this.state.password}\n                                onChange={this.handleInputChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    <Stack className=\"login-form\" horizontal>\n                        <Stack.Item>\n                            <Label>{intl.get(\"service.fetchLimit\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item grow>\n                            <Dropdown\n                                options={this.fetchLimitOptions()}\n                                selectedKey={this.state.fetchLimit}\n                                onChange={this.onFetchLimitOptionChange}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.existing && (\n                        <Checkbox\n                            label={intl.get(\"service.importGroups\")}\n                            checked={this.state.importGroups}\n                            onChange={(_, c) =>\n                                this.setState({ importGroups: c })\n                            }\n                        />\n                    )}\n                    <Stack horizontal style={{ marginTop: 32 }}>\n                        <Stack.Item>\n                            <PrimaryButton\n                                disabled={!this.validateForm()}\n                                onClick={this.save}\n                                text={\n                                    this.state.existing\n                                        ? intl.get(\"edit\")\n                                        : intl.get(\"confirm\")\n                                }\n                            />\n                        </Stack.Item>\n                        <Stack.Item>\n                            {this.state.existing ? (\n                                <DangerButton\n                                    onClick={this.remove}\n                                    text={intl.get(\"delete\")}\n                                />\n                            ) : (\n                                <DefaultButton\n                                    onClick={this.props.exit}\n                                    text={intl.get(\"cancel\")}\n                                />\n                            )}\n                        </Stack.Item>\n                    </Stack>\n                </Stack>\n            </>\n        )\n    }\n}\n\nexport default NextcloudConfigsTab\n"
  },
  {
    "path": "src/components/settings/sources.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport {\n    Label,\n    DefaultButton,\n    TextField,\n    Stack,\n    PrimaryButton,\n    DetailsList,\n    IColumn,\n    SelectionMode,\n    Selection,\n    IChoiceGroupOption,\n    ChoiceGroup,\n    IDropdownOption,\n    Dropdown,\n    MessageBar,\n    MessageBarType,\n    Toggle,\n} from \"@fluentui/react\"\nimport {\n    SourceState,\n    RSSSource,\n    SourceOpenTarget,\n} from \"../../scripts/models/source\"\nimport { urlTest } from \"../../scripts/utils\"\nimport DangerButton from \"../utils/danger-button\"\n\ntype SourcesTabProps = {\n    sources: SourceState\n    serviceOn: boolean\n    sids: number[]\n    acknowledgeSIDs: () => void\n    addSource: (url: string) => void\n    updateSourceName: (source: RSSSource, name: string) => void\n    updateSourceIcon: (source: RSSSource, iconUrl: string) => Promise<void>\n    updateSourceOpenTarget: (\n        source: RSSSource,\n        target: SourceOpenTarget\n    ) => void\n    updateFetchFrequency: (source: RSSSource, frequency: number) => void\n    deleteSource: (source: RSSSource) => void\n    deleteSources: (sources: RSSSource[]) => void\n    importOPML: () => void\n    exportOPML: () => void\n    toggleSourceHidden: (source: RSSSource) => void\n}\n\ntype SourcesTabState = {\n    [formName: string]: string\n} & {\n    selectedSource: RSSSource\n    selectedSources: RSSSource[]\n}\n\nconst enum EditDropdownKeys {\n    Name = \"n\",\n    Icon = \"i\",\n    Url = \"u\",\n}\n\nclass SourcesTab extends React.Component<SourcesTabProps, SourcesTabState> {\n    selection: Selection\n\n    constructor(props) {\n        super(props)\n        this.state = {\n            newUrl: \"\",\n            newSourceName: \"\",\n            selectedSource: null,\n            selectedSources: null,\n        }\n        this.selection = new Selection({\n            getKey: s => (s as RSSSource).sid,\n            onSelectionChanged: () => {\n                let count = this.selection.getSelectedCount()\n                let sources = count\n                    ? (this.selection.getSelection() as RSSSource[])\n                    : null\n                this.setState({\n                    selectedSource: count === 1 ? sources[0] : null,\n                    selectedSources: count > 1 ? sources : null,\n                    newSourceName: count === 1 ? sources[0].name : \"\",\n                    newSourceIcon: count === 1 ? sources[0].iconurl || \"\" : \"\",\n                    sourceEditOption: EditDropdownKeys.Name,\n                })\n            },\n        })\n    }\n\n    componentDidMount = () => {\n        if (this.props.sids.length > 0) {\n            for (let sid of this.props.sids) {\n                this.selection.setKeySelected(String(sid), true, false)\n            }\n            this.props.acknowledgeSIDs()\n        }\n    }\n\n    columns = (): IColumn[] => [\n        {\n            key: \"favicon\",\n            name: intl.get(\"icon\"),\n            fieldName: \"name\",\n            isIconOnly: true,\n            iconName: \"ImagePixel\",\n            minWidth: 16,\n            maxWidth: 16,\n            onRender: (s: RSSSource) =>\n                s.iconurl && <img src={s.iconurl} className=\"favicon\" />,\n        },\n        {\n            key: \"name\",\n            name: intl.get(\"name\"),\n            fieldName: \"name\",\n            minWidth: 200,\n            data: \"string\",\n            isRowHeader: true,\n        },\n        {\n            key: \"url\",\n            name: \"URL\",\n            fieldName: \"url\",\n            minWidth: 280,\n            data: \"string\",\n        },\n    ]\n\n    sourceEditOptions = (): IDropdownOption[] => [\n        { key: EditDropdownKeys.Name, text: intl.get(\"name\") },\n        { key: EditDropdownKeys.Icon, text: intl.get(\"icon\") },\n        { key: EditDropdownKeys.Url, text: \"URL\" },\n    ]\n\n    onSourceEditOptionChange = (_, option: IDropdownOption) => {\n        this.setState({ sourceEditOption: option.key as string })\n    }\n\n    fetchFrequencyOptions = (): IDropdownOption[] => [\n        { key: \"0\", text: intl.get(\"sources.unlimited\") },\n        { key: \"15\", text: intl.get(\"time.minute\", { m: 15 }) },\n        { key: \"30\", text: intl.get(\"time.minute\", { m: 30 }) },\n        { key: \"60\", text: intl.get(\"time.hour\", { h: 1 }) },\n        { key: \"120\", text: intl.get(\"time.hour\", { h: 2 }) },\n        { key: \"180\", text: intl.get(\"time.hour\", { h: 3 }) },\n        { key: \"360\", text: intl.get(\"time.hour\", { h: 6 }) },\n        { key: \"720\", text: intl.get(\"time.hour\", { h: 12 }) },\n        { key: \"1440\", text: intl.get(\"time.day\", { d: 1 }) },\n    ]\n\n    onFetchFrequencyChange = (_, option: IDropdownOption) => {\n        let frequency = parseInt(option.key as string)\n        this.props.updateFetchFrequency(this.state.selectedSource, frequency)\n        this.setState({\n            selectedSource: {\n                ...this.state.selectedSource,\n                fetchFrequency: frequency,\n            } as RSSSource,\n        })\n    }\n\n    sourceOpenTargetChoices = (): IChoiceGroupOption[] => [\n        {\n            key: String(SourceOpenTarget.Local),\n            text: intl.get(\"sources.rssText\"),\n        },\n        {\n            key: String(SourceOpenTarget.FullContent),\n            text: intl.get(\"article.loadFull\"),\n        },\n        {\n            key: String(SourceOpenTarget.Webpage),\n            text: intl.get(\"sources.loadWebpage\"),\n        },\n        {\n            key: String(SourceOpenTarget.External),\n            text: intl.get(\"openExternal\"),\n        },\n    ]\n\n    updateSourceName = () => {\n        let newName = this.state.newSourceName.trim()\n        this.props.updateSourceName(this.state.selectedSource, newName)\n        this.setState({\n            selectedSource: {\n                ...this.state.selectedSource,\n                name: newName,\n            } as RSSSource,\n        })\n    }\n\n    updateSourceIcon = () => {\n        let newIcon = this.state.newSourceIcon.trim()\n        this.props.updateSourceIcon(this.state.selectedSource, newIcon)\n        this.setState({\n            selectedSource: { ...this.state.selectedSource, iconurl: newIcon },\n        })\n    }\n\n    handleInputChange = event => {\n        const name: string = event.target.name\n        this.setState({ [name]: event.target.value })\n    }\n\n    addSource = (event: React.FormEvent) => {\n        event.preventDefault()\n        let trimmed = this.state.newUrl.trim()\n        if (urlTest(trimmed)) this.props.addSource(trimmed)\n    }\n\n    onOpenTargetChange = (_, option: IChoiceGroupOption) => {\n        let newTarget = parseInt(option.key) as SourceOpenTarget\n        this.props.updateSourceOpenTarget(this.state.selectedSource, newTarget)\n        this.setState({\n            selectedSource: {\n                ...this.state.selectedSource,\n                openTarget: newTarget,\n            } as RSSSource,\n        })\n    }\n\n    onToggleHidden = () => {\n        this.props.toggleSourceHidden(this.state.selectedSource)\n        this.setState({\n            selectedSource: {\n                ...this.state.selectedSource,\n                hidden: !this.state.selectedSource.hidden,\n            } as RSSSource,\n        })\n    }\n\n    render = () => (\n        <div className=\"tab-body\">\n            {this.props.serviceOn && (\n                <MessageBar messageBarType={MessageBarType.info}>\n                    {intl.get(\"sources.serviceWarning\")}\n                </MessageBar>\n            )}\n            <Label>{intl.get(\"sources.opmlFile\")}</Label>\n            <Stack horizontal>\n                <Stack.Item>\n                    <PrimaryButton\n                        onClick={this.props.importOPML}\n                        text={intl.get(\"sources.import\")}\n                    />\n                </Stack.Item>\n                <Stack.Item>\n                    <DefaultButton\n                        onClick={this.props.exportOPML}\n                        text={intl.get(\"sources.export\")}\n                    />\n                </Stack.Item>\n            </Stack>\n\n            <form onSubmit={this.addSource}>\n                <Label htmlFor=\"newUrl\">{intl.get(\"sources.add\")}</Label>\n                <Stack horizontal>\n                    <Stack.Item grow>\n                        <TextField\n                            onGetErrorMessage={v =>\n                                urlTest(v.trim())\n                                    ? \"\"\n                                    : intl.get(\"sources.badUrl\")\n                            }\n                            validateOnLoad={false}\n                            placeholder={intl.get(\"sources.inputUrl\")}\n                            value={this.state.newUrl}\n                            id=\"newUrl\"\n                            name=\"newUrl\"\n                            onChange={this.handleInputChange}\n                        />\n                    </Stack.Item>\n                    <Stack.Item>\n                        <PrimaryButton\n                            disabled={!urlTest(this.state.newUrl.trim())}\n                            type=\"submit\"\n                            text={intl.get(\"add\")}\n                        />\n                    </Stack.Item>\n                </Stack>\n            </form>\n\n            <DetailsList\n                compact={Object.keys(this.props.sources).length >= 10}\n                items={Object.values(this.props.sources)}\n                columns={this.columns()}\n                getKey={s => s.sid}\n                setKey=\"selected\"\n                selection={this.selection}\n                selectionMode={SelectionMode.multiple}\n            />\n\n            {this.state.selectedSource && (\n                <>\n                    {this.state.selectedSource.serviceRef && (\n                        <MessageBar messageBarType={MessageBarType.info}>\n                            {intl.get(\"sources.serviceManaged\")}\n                        </MessageBar>\n                    )}\n                    <Label>{intl.get(\"sources.selected\")}</Label>\n                    <Stack horizontal>\n                        <Stack.Item>\n                            <Dropdown\n                                options={this.sourceEditOptions()}\n                                selectedKey={this.state.sourceEditOption}\n                                onChange={this.onSourceEditOptionChange}\n                                style={{ width: 120 }}\n                            />\n                        </Stack.Item>\n                        {this.state.sourceEditOption ===\n                            EditDropdownKeys.Name && (\n                            <>\n                                <Stack.Item grow>\n                                    <TextField\n                                        onGetErrorMessage={v =>\n                                            v.trim().length == 0\n                                                ? intl.get(\"emptyName\")\n                                                : \"\"\n                                        }\n                                        validateOnLoad={false}\n                                        placeholder={intl.get(\"sources.name\")}\n                                        value={this.state.newSourceName}\n                                        name=\"newSourceName\"\n                                        onChange={this.handleInputChange}\n                                    />\n                                </Stack.Item>\n                                <Stack.Item>\n                                    <DefaultButton\n                                        disabled={\n                                            this.state.newSourceName.trim()\n                                                .length == 0\n                                        }\n                                        onClick={this.updateSourceName}\n                                        text={intl.get(\"sources.editName\")}\n                                    />\n                                </Stack.Item>\n                            </>\n                        )}\n                        {this.state.sourceEditOption ===\n                            EditDropdownKeys.Icon && (\n                            <>\n                                <Stack.Item grow>\n                                    <TextField\n                                        onGetErrorMessage={v =>\n                                            urlTest(v.trim())\n                                                ? \"\"\n                                                : intl.get(\"sources.badUrl\")\n                                        }\n                                        validateOnLoad={false}\n                                        placeholder={intl.get(\n                                            \"sources.inputUrl\"\n                                        )}\n                                        value={this.state.newSourceIcon}\n                                        name=\"newSourceIcon\"\n                                        onChange={this.handleInputChange}\n                                    />\n                                </Stack.Item>\n                                <Stack.Item>\n                                    <DefaultButton\n                                        disabled={\n                                            !urlTest(\n                                                this.state.newSourceIcon.trim()\n                                            )\n                                        }\n                                        onClick={this.updateSourceIcon}\n                                        text={intl.get(\"edit\")}\n                                    />\n                                </Stack.Item>\n                            </>\n                        )}\n                        {this.state.sourceEditOption ===\n                            EditDropdownKeys.Url && (\n                            <>\n                                <Stack.Item grow>\n                                    <TextField\n                                        disabled\n                                        value={this.state.selectedSource.url}\n                                    />\n                                </Stack.Item>\n                                <Stack.Item>\n                                    <DefaultButton\n                                        onClick={() =>\n                                            window.utils.writeClipboard(\n                                                this.state.selectedSource.url\n                                            )\n                                        }\n                                        text={intl.get(\"context.copy\")}\n                                    />\n                                </Stack.Item>\n                            </>\n                        )}\n                    </Stack>\n                    {!this.state.selectedSource.serviceRef && (\n                        <>\n                            <Label>{intl.get(\"sources.fetchFrequency\")}</Label>\n                            <Stack>\n                                <Stack.Item>\n                                    <Dropdown\n                                        options={this.fetchFrequencyOptions()}\n                                        selectedKey={\n                                            this.state.selectedSource\n                                                .fetchFrequency\n                                                ? String(\n                                                      this.state.selectedSource\n                                                          .fetchFrequency\n                                                  )\n                                                : \"0\"\n                                        }\n                                        onChange={this.onFetchFrequencyChange}\n                                        style={{ width: 200 }}\n                                    />\n                                </Stack.Item>\n                            </Stack>\n                        </>\n                    )}\n                    <ChoiceGroup\n                        label={intl.get(\"sources.openTarget\")}\n                        options={this.sourceOpenTargetChoices()}\n                        selectedKey={String(\n                            this.state.selectedSource.openTarget\n                        )}\n                        onChange={this.onOpenTargetChange}\n                    />\n                    <Stack horizontal verticalAlign=\"baseline\">\n                        <Stack.Item grow>\n                            <Label>{intl.get(\"sources.hidden\")}</Label>\n                        </Stack.Item>\n                        <Stack.Item>\n                            <Toggle\n                                checked={this.state.selectedSource.hidden}\n                                onChange={this.onToggleHidden}\n                            />\n                        </Stack.Item>\n                    </Stack>\n                    {!this.state.selectedSource.serviceRef && (\n                        <Stack horizontal>\n                            <Stack.Item>\n                                <DangerButton\n                                    onClick={() =>\n                                        this.props.deleteSource(\n                                            this.state.selectedSource\n                                        )\n                                    }\n                                    key={this.state.selectedSource.sid}\n                                    text={intl.get(\"sources.delete\")}\n                                />\n                            </Stack.Item>\n                            <Stack.Item>\n                                <span className=\"settings-hint\">\n                                    {intl.get(\"sources.deleteWarning\")}\n                                </span>\n                            </Stack.Item>\n                        </Stack>\n                    )}\n                </>\n            )}\n            {this.state.selectedSources &&\n                (this.state.selectedSources.filter(s => s.serviceRef).length ===\n                0 ? (\n                    <>\n                        <Label>{intl.get(\"sources.selectedMulti\")}</Label>\n                        <Stack horizontal>\n                            <Stack.Item>\n                                <DangerButton\n                                    onClick={() =>\n                                        this.props.deleteSources(\n                                            this.state.selectedSources\n                                        )\n                                    }\n                                    text={intl.get(\"sources.delete\")}\n                                />\n                            </Stack.Item>\n                            <Stack.Item>\n                                <span className=\"settings-hint\">\n                                    {intl.get(\"sources.deleteWarning\")}\n                                </span>\n                            </Stack.Item>\n                        </Stack>\n                    </>\n                ) : (\n                    <MessageBar messageBarType={MessageBarType.info}>\n                        {intl.get(\"sources.serviceManaged\")}\n                    </MessageBar>\n                ))}\n        </div>\n    )\n}\n\nexport default SourcesTab\n"
  },
  {
    "path": "src/components/settings.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { Icon } from \"@fluentui/react/lib/Icon\"\nimport { AnimationClassNames } from \"@fluentui/react/lib/Styling\"\nimport AboutTab from \"./settings/about\"\nimport { Pivot, PivotItem, Spinner, FocusTrapZone } from \"@fluentui/react\"\nimport SourcesTabContainer from \"../containers/settings/sources-container\"\nimport GroupsTabContainer from \"../containers/settings/groups-container\"\nimport AppTabContainer from \"../containers/settings/app-container\"\nimport RulesTabContainer from \"../containers/settings/rules-container\"\nimport ServiceTabContainer from \"../containers/settings/service-container\"\nimport { initTouchBarWithTexts } from \"../scripts/utils\"\n\ntype SettingsProps = {\n    display: boolean\n    blocked: boolean\n    exitting: boolean\n    close: () => void\n}\n\nclass Settings extends React.Component<SettingsProps> {\n    constructor(props) {\n        super(props)\n    }\n\n    onKeyDown = (event: KeyboardEvent) => {\n        if (event.key === \"Escape\" && !this.props.exitting) this.props.close()\n    }\n\n    componentDidUpdate = (prevProps: SettingsProps) => {\n        if (this.props.display !== prevProps.display) {\n            if (this.props.display) {\n                if (window.utils.platform === \"darwin\")\n                    window.utils.destroyTouchBar()\n                document.body.addEventListener(\"keydown\", this.onKeyDown)\n            } else {\n                if (window.utils.platform === \"darwin\") initTouchBarWithTexts()\n                document.body.removeEventListener(\"keydown\", this.onKeyDown)\n            }\n        }\n    }\n\n    render = () =>\n        this.props.display && (\n            <div className=\"settings-container\">\n                <div\n                    className=\"btn-group\"\n                    style={{\n                        position: \"absolute\",\n                        top: 70,\n                        left: \"calc(50% - 404px)\",\n                    }}>\n                    <a\n                        className={\n                            \"btn\" + (this.props.exitting ? \" disabled\" : \"\")\n                        }\n                        title={intl.get(\"settings.exit\")}\n                        onClick={this.props.close}>\n                        <Icon iconName=\"Back\" />\n                    </a>\n                </div>\n                <div className={\"settings \" + AnimationClassNames.slideUpIn20}>\n                    {this.props.blocked && (\n                        <FocusTrapZone\n                            isClickableOutsideFocusTrap={true}\n                            className=\"loading\">\n                            <Spinner\n                                label={intl.get(\"settings.fetching\")}\n                                tabIndex={0}\n                            />\n                        </FocusTrapZone>\n                    )}\n                    <Pivot>\n                        <PivotItem\n                            headerText={intl.get(\"settings.sources\")}\n                            itemIcon=\"Source\">\n                            <SourcesTabContainer />\n                        </PivotItem>\n                        <PivotItem\n                            headerText={intl.get(\"settings.grouping\")}\n                            itemIcon=\"GroupList\">\n                            <GroupsTabContainer />\n                        </PivotItem>\n                        <PivotItem\n                            headerText={intl.get(\"settings.rules\")}\n                            itemIcon=\"FilterSettings\">\n                            <RulesTabContainer />\n                        </PivotItem>\n                        <PivotItem\n                            headerText={intl.get(\"settings.service\")}\n                            itemIcon=\"CloudImportExport\">\n                            <ServiceTabContainer />\n                        </PivotItem>\n                        <PivotItem\n                            headerText={intl.get(\"settings.app\")}\n                            itemIcon=\"Settings\">\n                            <AppTabContainer />\n                        </PivotItem>\n                        <PivotItem\n                            headerText={intl.get(\"settings.about\")}\n                            itemIcon=\"Info\">\n                            <AboutTab />\n                        </PivotItem>\n                    </Pivot>\n                </div>\n            </div>\n        )\n}\n\nexport default Settings\n"
  },
  {
    "path": "src/components/utils/ResizeObserver.d.ts",
    "content": "/**\n * The **ResizeObserver** interface reports changes to the dimensions of an\n * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element)'s content\n * or border box, or the bounding box of an\n * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement).\n *\n * > **Note**: The content box is the box in which content can be placed,\n * > meaning the border box minus the padding and border width. The border box\n * > encompasses the content, padding, and border. See\n * > [The box model](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model)\n * > for further explanation.\n *\n * `ResizeObserver` avoids infinite callback loops and cyclic dependencies that\n * are often created when resizing via a callback function. It does this by only\n * processing elements deeper in the DOM in subsequent frames. Implementations\n * should, if they follow the specification, invoke resize events before paint\n * and after layout.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver\n */\ndeclare class ResizeObserver {\n    /**\n     * The **ResizeObserver** constructor creates a new `ResizeObserver` object,\n     * which can be used to report changes to the content or border box of an\n     * `Element` or the bounding box of an `SVGElement`.\n     *\n     * @example\n     * var ResizeObserver = new ResizeObserver(callback)\n     *\n     * @param callback\n     * The function called whenever an observed resize occurs. The function is\n     * called with two parameters:\n     * * **entries**\n     *   An array of\n     *   [ResizeObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n     *   objects that can be used to access the new dimensions of the element\n     *   after each change.\n     * * **observer**\n     *   A reference to the `ResizeObserver` itself, so it will definitely be\n     *   accessible from inside the callback, should you need it. This could be\n     *   used for example to automatically unobserve the observer when a certain\n     *   condition is reached, but you can omit it if you don't need it.\n     *\n     * The callback will generally follow a pattern along the lines of:\n     * ```js\n     * function(entries, observer) {\n     *   for (let entry of entries) {\n     *     // Do something to each entry\n     *     // and possibly something to the observer itself\n     *   }\n     * }\n     * ```\n     *\n     * The following snippet is taken from the\n     * [resize-observer-text.html](https://mdn.github.io/dom-examples/resize-observer/resize-observer-text.html)\n     * ([see source](https://github.com/mdn/dom-examples/blob/master/resize-observer/resize-observer-text.html))\n     * example:\n     * @example\n     * const resizeObserver = new ResizeObserver(entries => {\n     *   for (let entry of entries) {\n     *     if(entry.contentBoxSize) {\n     *       h1Elem.style.fontSize = Math.max(1.5, entry.contentBoxSize.inlineSize/200) + 'rem';\n     *       pElem.style.fontSize = Math.max(1, entry.contentBoxSize.inlineSize/600) + 'rem';\n     *     } else {\n     *       h1Elem.style.fontSize = Math.max(1.5, entry.contentRect.width/200) + 'rem';\n     *       pElem.style.fontSize = Math.max(1, entry.contentRect.width/600) + 'rem';\n     *     }\n     *   }\n     * });\n     *\n     * resizeObserver.observe(divElem);\n     */\n    constructor(callback: ResizeObserverCallback)\n\n    /**\n     * The **disconnect()** method of the\n     * [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n     * interface unobserves all observed\n     * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n     * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement)\n     * targets.\n     */\n    disconnect: () => void\n\n    /**\n     * The `observe()` method of the\n     * [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n     * interface starts observing the specified\n     * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n     * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement).\n     *\n     * @example\n     * resizeObserver.observe(target, options);\n     *\n     * @param target\n     * A reference to an\n     * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n     * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement)\n     * to be observed.\n     *\n     * @param options\n     * An options object allowing you to set options for the observation.\n     * Currently this only has one possible option that can be set.\n     */\n    observe: (target: Element, options?: ResizeObserverObserveOptions) => void\n\n    /**\n     * The **unobserve()** method of the\n     * [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n     * interface ends the observing of a specified\n     * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n     * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement).\n     */\n    unobserve: (target: Element) => void\n}\n\ninterface ResizeObserverObserveOptions {\n    /**\n     * Sets which box model the observer will observe changes to. Possible values\n     * are `content-box` (the default), and `border-box`.\n     *\n     * @default \"content-box\"\n     */\n    box?: \"content-box\" | \"border-box\"\n}\n\n/**\n * The function called whenever an observed resize occurs. The function is\n * called with two parameters:\n *\n * @param entries\n * An array of\n * [ResizeObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n * objects that can be used to access the new dimensions of the element after\n * each change.\n *\n * @param observer\n * A reference to the `ResizeObserver` itself, so it will definitely be\n * accessible from inside the callback, should you need it. This could be used\n * for example to automatically unobserve the observer when a certain condition\n * is reached, but you can omit it if you don't need it.\n *\n * The callback will generally follow a pattern along the lines of:\n * @example\n * function(entries, observer) {\n *   for (let entry of entries) {\n *     // Do something to each entry\n *     // and possibly something to the observer itself\n *   }\n * }\n *\n * @example\n * const resizeObserver = new ResizeObserver(entries => {\n *   for (let entry of entries) {\n *     if(entry.contentBoxSize) {\n *       h1Elem.style.fontSize = Math.max(1.5, entry.contentBoxSize.inlineSize/200) + 'rem';\n *       pElem.style.fontSize = Math.max(1, entry.contentBoxSize.inlineSize/600) + 'rem';\n *     } else {\n *       h1Elem.style.fontSize = Math.max(1.5, entry.contentRect.width/200) + 'rem';\n *       pElem.style.fontSize = Math.max(1, entry.contentRect.width/600) + 'rem';\n *     }\n *   }\n * });\n *\n * resizeObserver.observe(divElem);\n */\ntype ResizeObserverCallback = (\n    entries: ResizeObserverEntry[],\n    observer: ResizeObserver\n) => void\n\n/**\n * The **ResizeObserverEntry** interface represents the object passed to the\n * [ResizeObserver()](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver)\n * constructor's callback function, which allows you to access the new\n * dimensions of the\n * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement)\n * being observed.\n */\ninterface ResizeObserverEntry {\n    /**\n     * An object containing the new border box size of the observed element when\n     * the callback is run.\n     */\n    readonly borderBoxSize: ResizeObserverEntryBoxSize\n\n    /**\n     * An object containing the new content box size of the observed element when\n     * the callback is run.\n     */\n    readonly contentBoxSize: ResizeObserverEntryBoxSize\n\n    /**\n     * A [DOMRectReadOnly](https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly)\n     * object containing the new size of the observed element when the callback is\n     * run. Note that this is better supported than the above two properties, but\n     * it is left over from an earlier implementation of the Resize Observer API,\n     * is still included in the spec for web compat reasons, and may be deprecated\n     * in future versions.\n     */\n    // node_modules/typescript/lib/lib.dom.d.ts\n    readonly contentRect: DOMRectReadOnly\n\n    /**\n     * A reference to the\n     * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) or\n     * [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement)\n     * being observed.\n     */\n    readonly target: Element\n}\n\n/**\n * The **borderBoxSize** read-only property of the\n * [ResizeObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n * interface returns an object containing the new border box size of the\n * observed element when the callback is run.\n */\ninterface ResizeObserverEntryBoxSize {\n    /**\n     * The length of the observed element's border box in the block dimension. For\n     * boxes with a horizontal\n     * [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode),\n     * this is the vertical dimension, or height; if the writing-mode is vertical,\n     * this is the horizontal dimension, or width.\n     */\n    blockSize: number\n\n    /**\n     * The length of the observed element's border box in the inline dimension.\n     * For boxes with a horizontal\n     * [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode),\n     * this is the horizontal dimension, or width; if the writing-mode is\n     * vertical, this is the vertical dimension, or height.\n     */\n    inlineSize: number\n}\n\ninterface Window {\n    ResizeObserver: typeof ResizeObserver\n}\n"
  },
  {
    "path": "src/components/utils/article-search.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { connect } from \"react-redux\"\nimport { RootState } from \"../../scripts/reducer\"\nimport { SearchBox, ISearchBox, Async } from \"@fluentui/react\"\nimport { AppDispatch, validateRegex } from \"../../scripts/utils\"\nimport { performSearch } from \"../../scripts/models/page\"\n\ntype SearchProps = {\n    searchOn: boolean\n    initQuery: string\n    dispatch: AppDispatch\n}\n\ntype SearchState = {\n    query: string\n}\n\nclass ArticleSearch extends React.Component<SearchProps, SearchState> {\n    debouncedSearch: (query: string) => void\n    inputRef: React.RefObject<ISearchBox>\n\n    constructor(props: SearchProps) {\n        super(props)\n        this.debouncedSearch = new Async().debounce((query: string) => {\n            let regex = validateRegex(query)\n            if (regex !== null) props.dispatch(performSearch(query))\n        }, 750)\n        this.inputRef = React.createRef<ISearchBox>()\n        this.state = { query: props.initQuery }\n    }\n\n    onSearchChange = (_, newValue: string) => {\n        this.debouncedSearch(newValue)\n        this.setState({ query: newValue })\n    }\n\n    componentDidUpdate(prevProps: SearchProps) {\n        if (this.props.searchOn && !prevProps.searchOn) {\n            this.setState({ query: this.props.initQuery })\n            this.inputRef.current.focus()\n        }\n    }\n\n    render() {\n        return (\n            this.props.searchOn && (\n                <SearchBox\n                    componentRef={this.inputRef}\n                    className=\"article-search\"\n                    placeholder={intl.get(\"search\")}\n                    value={this.state.query}\n                    onChange={this.onSearchChange}\n                />\n            )\n        )\n    }\n}\n\nconst getSearchProps = (state: RootState) => ({\n    searchOn: state.page.searchOn,\n    initQuery: state.page.filter.search,\n})\nexport default connect(getSearchProps)(ArticleSearch)\n"
  },
  {
    "path": "src/components/utils/danger-button.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\nimport { PrimaryButton } from \"@fluentui/react\"\n\nclass DangerButton extends PrimaryButton {\n    timerID: NodeJS.Timeout\n\n    state = {\n        confirming: false,\n    }\n\n    clear = () => {\n        this.timerID = null\n        this.setState({ confirming: false })\n    }\n\n    onClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n        if (!this.props.disabled) {\n            if (this.state.confirming) {\n                if (this.props.onClick) this.props.onClick(event)\n                clearTimeout(this.timerID)\n                this.clear()\n            } else {\n                this.setState({ confirming: true })\n                this.timerID = setTimeout(() => {\n                    this.clear()\n                }, 5000)\n            }\n        }\n    }\n\n    componentWillUnmount() {\n        if (this.timerID) clearTimeout(this.timerID)\n    }\n\n    render = () => (\n        <PrimaryButton\n            {...this.props}\n            className={this.props.className + \" danger\"}\n            onClick={this.onClick}\n            text={\n                this.state.confirming\n                    ? intl.get(\"dangerButton\", {\n                          action: this.props.text.toLowerCase(),\n                      })\n                    : this.props.text\n            }>\n            {this.props.children}\n        </PrimaryButton>\n    )\n}\n\nexport default DangerButton\n"
  },
  {
    "path": "src/components/utils/time.tsx",
    "content": "import * as React from \"react\"\nimport intl from \"react-intl-universal\"\n\ninterface TimeProps {\n    date: Date\n}\n\nclass Time extends React.Component<TimeProps> {\n    timerID: NodeJS.Timeout\n    state = { now: new Date() }\n\n    componentDidMount() {\n        this.timerID = setInterval(() => this.tick(), 60000)\n    }\n\n    componentWillUnmount() {\n        clearInterval(this.timerID)\n    }\n\n    tick() {\n        this.setState({ now: new Date() })\n    }\n\n    displayTime(past: Date, now: Date): string {\n        // difference in seconds\n        let diff = (now.getTime() - past.getTime()) / 60000\n        if (diff < 1) return intl.get(\"time.now\")\n        else if (diff < 60) return Math.floor(diff) + intl.get(\"time.m\")\n        else if (diff < 1440) return Math.floor(diff / 60) + intl.get(\"time.h\")\n        else return Math.floor(diff / 1440) + intl.get(\"time.d\")\n    }\n\n    render() {\n        return (\n            <span className=\"time\">\n                {this.displayTime(this.props.date, this.state.now)}\n            </span>\n        )\n    }\n}\n\nexport default Time\n"
  },
  {
    "path": "src/containers/article-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../scripts/reducer\"\nimport {\n    RSSItem,\n    markUnread,\n    markRead,\n    toggleStarred,\n    toggleHidden,\n    itemShortcuts,\n} from \"../scripts/models/item\"\nimport { AppDispatch } from \"../scripts/utils\"\nimport { dismissItem, showOffsetItem } from \"../scripts/models/page\"\nimport Article from \"../components/article\"\nimport {\n    openTextMenu,\n    closeContextMenu,\n    openImageMenu,\n} from \"../scripts/models/app\"\nimport {\n    RSSSource,\n    SourceTextDirection,\n    updateSource,\n} from \"../scripts/models/source\"\n\ntype ArticleContainerProps = {\n    itemId: number\n}\n\nconst getItem = (state: RootState, props: ArticleContainerProps) =>\n    state.items[props.itemId]\nconst getSource = (state: RootState, props: ArticleContainerProps) =>\n    state.sources[state.items[props.itemId].source]\nconst getLocale = (state: RootState) => state.app.locale\n\nconst makeMapStateToProps = () => {\n    return createSelector(\n        [getItem, getSource, getLocale],\n        (item, source, locale) => ({\n            item: item,\n            source: source,\n            locale: locale,\n        })\n    )\n}\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => {\n    return {\n        shortcuts: (item: RSSItem, e: KeyboardEvent) =>\n            dispatch(itemShortcuts(item, e)),\n        dismiss: () => dispatch(dismissItem()),\n        offsetItem: (offset: number) => dispatch(showOffsetItem(offset)),\n        toggleHasRead: (item: RSSItem) =>\n            dispatch(item.hasRead ? markUnread(item) : markRead(item)),\n        toggleStarred: (item: RSSItem) => dispatch(toggleStarred(item)),\n        toggleHidden: (item: RSSItem) => {\n            if (!item.hidden) dispatch(dismissItem())\n            if (!item.hasRead && !item.hidden) dispatch(markRead(item))\n            dispatch(toggleHidden(item))\n        },\n        textMenu: (position: [number, number], text: string, url: string) =>\n            dispatch(openTextMenu(position, text, url)),\n        imageMenu: (position: [number, number]) =>\n            dispatch(openImageMenu(position)),\n        dismissContextMenu: () => dispatch(closeContextMenu()),\n        updateSourceTextDirection: (\n            source: RSSSource,\n            direction: SourceTextDirection\n        ) => {\n            dispatch(\n                updateSource({ ...source, textDir: direction } as RSSSource)\n            )\n        },\n    }\n}\n\nconst ArticleContainer = connect(\n    makeMapStateToProps,\n    mapDispatchToProps\n)(Article)\nexport default ArticleContainer\n"
  },
  {
    "path": "src/containers/feed-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../scripts/reducer\"\nimport { markRead, RSSItem, itemShortcuts } from \"../scripts/models/item\"\nimport { openItemMenu } from \"../scripts/models/app\"\nimport { loadMore, RSSFeed } from \"../scripts/models/feed\"\nimport { showItem } from \"../scripts/models/page\"\nimport { ViewType } from \"../schema-types\"\nimport { Feed } from \"../components/feeds/feed\"\n\ninterface FeedContainerProps {\n    feedId: string\n    viewType: ViewType\n}\n\nconst getSources = (state: RootState) => state.sources\nconst getItems = (state: RootState) => state.items\nconst getFeed = (state: RootState, props: FeedContainerProps) =>\n    state.feeds[props.feedId]\nconst getFilter = (state: RootState) => state.page.filter\nconst getView = (_, props: FeedContainerProps) => props.viewType\nconst getViewConfigs = (state: RootState) => state.page.viewConfigs\nconst getCurrentItem = (state: RootState) => state.page.itemId\n\nconst makeMapStateToProps = () => {\n    return createSelector(\n        [\n            getSources,\n            getItems,\n            getFeed,\n            getView,\n            getFilter,\n            getViewConfigs,\n            getCurrentItem,\n        ],\n        (sources, items, feed, viewType, filter, viewConfigs, currentItem) => ({\n            feed: feed,\n            items: feed.iids.map(iid => items[iid]),\n            sourceMap: sources,\n            filter: filter,\n            viewType: viewType,\n            viewConfigs: viewConfigs,\n            currentItem: currentItem,\n        })\n    )\n}\nconst mapDispatchToProps = dispatch => {\n    return {\n        shortcuts: (item: RSSItem, e: KeyboardEvent) =>\n            dispatch(itemShortcuts(item, e)),\n        markRead: (item: RSSItem) => dispatch(markRead(item)),\n        contextMenu: (feedId: string, item: RSSItem, e) =>\n            dispatch(openItemMenu(item, feedId, e)),\n        loadMore: (feed: RSSFeed) => dispatch(loadMore(feed)),\n        showItem: (fid: string, item: RSSItem) => dispatch(showItem(fid, item)),\n    }\n}\n\nconst connector = connect(makeMapStateToProps, mapDispatchToProps)\nexport type FeedReduxProps = typeof connector\nexport const FeedContainer = connector(Feed)\n"
  },
  {
    "path": "src/containers/menu-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../scripts/reducer\"\nimport { Menu } from \"../components/menu\"\nimport { toggleMenu, openGroupMenu } from \"../scripts/models/app\"\nimport { toggleGroupExpansion } from \"../scripts/models/group\"\nimport { SourceGroup } from \"../schema-types\"\nimport {\n    selectAllArticles,\n    selectSources,\n    toggleSearch,\n} from \"../scripts/models/page\"\nimport { ViewType } from \"../schema-types\"\nimport { initFeeds } from \"../scripts/models/feed\"\nimport { RSSSource } from \"../scripts/models/source\"\n\nconst getApp = (state: RootState) => state.app\nconst getSources = (state: RootState) => state.sources\nconst getGroups = (state: RootState) => state.groups\nconst getSearchOn = (state: RootState) => state.page.searchOn\nconst getItemOn = (state: RootState) =>\n    state.page.itemId !== null && state.page.viewType !== ViewType.List\n\nconst mapStateToProps = createSelector(\n    [getApp, getSources, getGroups, getSearchOn, getItemOn],\n    (app, sources, groups, searchOn, itemOn) => ({\n        status: app.sourceInit && !app.settings.display,\n        display: app.menu,\n        selected: app.menuKey,\n        sources: sources,\n        groups: groups.map((g, i) => ({ ...g, index: i })),\n        searchOn: searchOn,\n        itemOn: itemOn,\n    })\n)\n\nconst mapDispatchToProps = dispatch => ({\n    toggleMenu: () => dispatch(toggleMenu()),\n    allArticles: (init = false) => {\n        dispatch(selectAllArticles(init)), dispatch(initFeeds())\n    },\n    selectSourceGroup: (group: SourceGroup, menuKey: string) => {\n        dispatch(selectSources(group.sids, menuKey, group.name))\n        dispatch(initFeeds())\n    },\n    selectSource: (source: RSSSource) => {\n        dispatch(selectSources([source.sid], \"s-\" + source.sid, source.name))\n        dispatch(initFeeds())\n    },\n    groupContextMenu: (sids: number[], event: React.MouseEvent) => {\n        dispatch(openGroupMenu(sids, event))\n    },\n    updateGroupExpansion: (\n        event: React.MouseEvent<HTMLElement>,\n        key: string,\n        selected: string\n    ) => {\n        if ((event.target as HTMLElement).tagName === \"I\" || key === selected) {\n            let [type, index] = key.split(\"-\")\n            if (type === \"g\") dispatch(toggleGroupExpansion(parseInt(index)))\n        }\n    },\n    toggleSearch: () => dispatch(toggleSearch()),\n})\n\nconst MenuContainer = connect(mapStateToProps, mapDispatchToProps)(Menu)\nexport default MenuContainer\n"
  },
  {
    "path": "src/containers/page-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../scripts/reducer\"\nimport Page from \"../components/page\"\nimport { AppDispatch } from \"../scripts/utils\"\nimport { dismissItem, showOffsetItem } from \"../scripts/models/page\"\nimport { ContextMenuType } from \"../scripts/models/app\"\n\nconst getPage = (state: RootState) => state.page\nconst getSettings = (state: RootState) => state.app.settings.display\nconst getMenu = (state: RootState) => state.app.menu\nconst getContext = (state: RootState) =>\n    state.app.contextMenu.type != ContextMenuType.Hidden\n\nconst mapStateToProps = createSelector(\n    [getPage, getSettings, getMenu, getContext],\n    (page, settingsOn, menuOn, contextOn) => ({\n        feeds: [page.feedId],\n        settingsOn: settingsOn,\n        menuOn: menuOn,\n        contextOn: contextOn,\n        itemId: page.itemId,\n        itemFromFeed: page.itemFromFeed,\n        viewType: page.viewType,\n    })\n)\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => ({\n    dismissItem: () => dispatch(dismissItem()),\n    offsetItem: (offset: number) => dispatch(showOffsetItem(offset)),\n})\n\nconst PageContainer = connect(mapStateToProps, mapDispatchToProps)(Page)\nexport default PageContainer\n"
  },
  {
    "path": "src/containers/settings/app-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport {\n    initIntl,\n    saveSettings,\n    setupAutoFetch,\n} from \"../../scripts/models/app\"\nimport * as db from \"../../scripts/db\"\nimport AppTab from \"../../components/settings/app\"\nimport { importAll } from \"../../scripts/settings\"\nimport { updateUnreadCounts } from \"../../scripts/models/source\"\nimport { AppDispatch } from \"../../scripts/utils\"\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => ({\n    setLanguage: (option: string) => {\n        window.settings.setLocaleSettings(option)\n        dispatch(initIntl())\n    },\n    setFetchInterval: (interval: number) => {\n        window.settings.setFetchInterval(interval)\n        dispatch(setupAutoFetch())\n    },\n    deleteArticles: async (days: number) => {\n        dispatch(saveSettings())\n        let date = new Date()\n        date.setTime(date.getTime() - days * 86400000)\n        await db.itemsDB\n            .delete()\n            .from(db.items)\n            .where(db.items.date.lt(date))\n            .exec()\n        await dispatch(updateUnreadCounts())\n        dispatch(saveSettings())\n    },\n    importAll: async () => {\n        dispatch(saveSettings())\n        let cancelled = await importAll()\n        if (cancelled) dispatch(saveSettings())\n    },\n})\n\nconst AppTabContainer = connect(null, mapDispatchToProps)(AppTab)\nexport default AppTabContainer\n"
  },
  {
    "path": "src/containers/settings/groups-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../../scripts/reducer\"\nimport GroupsTab from \"../../components/settings/groups\"\nimport {\n    createSourceGroup,\n    updateSourceGroup,\n    addSourceToGroup,\n    deleteSourceGroup,\n    removeSourceFromGroup,\n    reorderSourceGroups,\n} from \"../../scripts/models/group\"\nimport { SourceGroup, SyncService } from \"../../schema-types\"\nimport { importGroups } from \"../../scripts/models/service\"\nimport { AppDispatch } from \"../../scripts/utils\"\n\nconst getSources = (state: RootState) => state.sources\nconst getGroups = (state: RootState) => state.groups\nconst getServiceOn = (state: RootState) =>\n    state.service.type !== SyncService.None\n\nconst mapStateToProps = createSelector(\n    [getSources, getGroups, getServiceOn],\n    (sources, groups, serviceOn) => ({\n        sources: sources,\n        groups: groups.map((g, i) => ({ ...g, index: i })),\n        serviceOn: serviceOn,\n        key: groups.length,\n    })\n)\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => ({\n    createGroup: (name: string) => dispatch(createSourceGroup(name)),\n    updateGroup: (group: SourceGroup) => dispatch(updateSourceGroup(group)),\n    addToGroup: (groupIndex: number, sid: number) =>\n        dispatch(addSourceToGroup(groupIndex, sid)),\n    deleteGroup: (groupIndex: number) =>\n        dispatch(deleteSourceGroup(groupIndex)),\n    removeFromGroup: (groupIndex: number, sids: number[]) =>\n        dispatch(removeSourceFromGroup(groupIndex, sids)),\n    reorderGroups: (groups: SourceGroup[]) =>\n        dispatch(reorderSourceGroups(groups)),\n    importGroups: () => dispatch(importGroups()),\n})\n\nconst GroupsTabContainer = connect(\n    mapStateToProps,\n    mapDispatchToProps\n)(GroupsTab)\nexport default GroupsTabContainer\n"
  },
  {
    "path": "src/containers/settings/rules-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../../scripts/reducer\"\nimport RulesTab from \"../../components/settings/rules\"\nimport { AppDispatch } from \"../../scripts/utils\"\nimport { RSSSource, updateSource } from \"../../scripts/models/source\"\nimport { SourceRule } from \"../../scripts/models/rule\"\n\nconst getSources = (state: RootState) => state.sources\n\nconst mapStateToProps = createSelector([getSources], sources => ({\n    sources: sources,\n}))\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => ({\n    updateSourceRules: (source: RSSSource, rules: SourceRule[]) => {\n        source.rules = rules\n        dispatch(updateSource(source))\n    },\n})\n\nconst RulesTabContainer = connect(mapStateToProps, mapDispatchToProps)(RulesTab)\nexport default RulesTabContainer\n"
  },
  {
    "path": "src/containers/settings/service-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../../scripts/reducer\"\nimport { ServiceTab } from \"../../components/settings/service\"\nimport { AppDispatch } from \"../../scripts/utils\"\nimport { ServiceConfigs } from \"../../schema-types\"\nimport {\n    saveServiceConfigs,\n    getServiceHooksFromType,\n    removeService,\n    syncWithService,\n} from \"../../scripts/models/service\"\nimport { saveSettings } from \"../../scripts/models/app\"\n\nconst getService = (state: RootState) => state.service\n\nconst mapStateToProps = createSelector([getService], service => ({\n    configs: service,\n}))\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => ({\n    save: (configs: ServiceConfigs) => dispatch(saveServiceConfigs(configs)),\n    remove: () => dispatch(removeService()),\n    blockActions: () => dispatch(saveSettings()),\n    sync: () => dispatch(syncWithService()),\n    authenticate: async (configs: ServiceConfigs) => {\n        const hooks = getServiceHooksFromType(configs.type)\n        if (hooks.authenticate) return await hooks.authenticate(configs)\n        else return true\n    },\n    reauthenticate: async (configs: ServiceConfigs) => {\n        const hooks = getServiceHooksFromType(configs.type)\n        try {\n            if (hooks.reauthenticate) return await hooks.reauthenticate(configs)\n        } catch (err) {\n            console.log(err)\n            return configs\n        }\n    },\n})\n\nconst ServiceTabContainer = connect(\n    mapStateToProps,\n    mapDispatchToProps\n)(ServiceTab)\nexport default ServiceTabContainer\n"
  },
  {
    "path": "src/containers/settings/sources-container.tsx",
    "content": "import intl from \"react-intl-universal\"\nimport { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../../scripts/reducer\"\nimport SourcesTab from \"../../components/settings/sources\"\nimport {\n    addSource,\n    RSSSource,\n    updateSource,\n    deleteSource,\n    SourceOpenTarget,\n    deleteSources,\n    toggleSourceHidden,\n} from \"../../scripts/models/source\"\nimport { importOPML, exportOPML } from \"../../scripts/models/group\"\nimport { AppDispatch, validateFavicon } from \"../../scripts/utils\"\nimport { saveSettings, toggleSettings } from \"../../scripts/models/app\"\nimport { SyncService } from \"../../schema-types\"\n\nconst getSources = (state: RootState) => state.sources\nconst getServiceOn = (state: RootState) =>\n    state.service.type !== SyncService.None\nconst getSIDs = (state: RootState) => state.app.settings.sids\n\nconst mapStateToProps = createSelector(\n    [getSources, getServiceOn, getSIDs],\n    (sources, serviceOn, sids) => ({\n        sources: sources,\n        serviceOn: serviceOn,\n        sids: sids,\n    })\n)\n\nconst mapDispatchToProps = (dispatch: AppDispatch) => {\n    return {\n        acknowledgeSIDs: () => dispatch(toggleSettings(true)),\n        addSource: (url: string) => dispatch(addSource(url)),\n        updateSourceName: (source: RSSSource, name: string) => {\n            dispatch(updateSource({ ...source, name: name } as RSSSource))\n        },\n        updateSourceIcon: async (source: RSSSource, iconUrl: string) => {\n            dispatch(saveSettings())\n            if (await validateFavicon(iconUrl)) {\n                dispatch(updateSource({ ...source, iconurl: iconUrl }))\n            } else {\n                window.utils.showErrorBox(intl.get(\"sources.badIcon\"), \"\")\n            }\n            dispatch(saveSettings())\n        },\n        updateSourceOpenTarget: (\n            source: RSSSource,\n            target: SourceOpenTarget\n        ) => {\n            dispatch(\n                updateSource({ ...source, openTarget: target } as RSSSource)\n            )\n        },\n        updateFetchFrequency: (source: RSSSource, frequency: number) => {\n            dispatch(\n                updateSource({\n                    ...source,\n                    fetchFrequency: frequency,\n                } as RSSSource)\n            )\n        },\n        deleteSource: (source: RSSSource) => dispatch(deleteSource(source)),\n        deleteSources: (sources: RSSSource[]) =>\n            dispatch(deleteSources(sources)),\n        importOPML: () => dispatch(importOPML()),\n        exportOPML: () => dispatch(exportOPML()),\n        toggleSourceHidden: (source: RSSSource) =>\n            dispatch(toggleSourceHidden(source)),\n    }\n}\n\nconst SourcesTabContainer = connect(\n    mapStateToProps,\n    mapDispatchToProps\n)(SourcesTab)\nexport default SourcesTabContainer\n"
  },
  {
    "path": "src/containers/settings-container.tsx",
    "content": "import { connect } from \"react-redux\"\nimport { createSelector } from \"reselect\"\nimport { RootState } from \"../scripts/reducer\"\nimport { exitSettings } from \"../scripts/models/app\"\nimport Settings from \"../components/settings\"\n\nconst getApp = (state: RootState) => state.app\n\nconst mapStateToProps = createSelector([getApp], app => ({\n    display: app.settings.display,\n    blocked:\n        !app.sourceInit ||\n        app.syncing ||\n        app.fetchingItems ||\n        app.settings.saving,\n    exitting: app.settings.saving,\n}))\n\nconst mapDispatchToProps = dispatch => {\n    return {\n        close: () => dispatch(exitSettings()),\n    }\n}\n\nconst SettingsContainer = connect(mapStateToProps, mapDispatchToProps)(Settings)\nexport default SettingsContainer\n"
  },
  {
    "path": "src/electron.ts",
    "content": "import { app, ipcMain, Menu, nativeTheme } from \"electron\"\nimport { ThemeSettings, SchemaTypes } from \"./schema-types\"\nimport { store } from \"./main/settings\"\nimport performUpdate from \"./main/update-scripts\"\nimport { WindowManager } from \"./main/window\"\n\nif (!process.mas) {\n    const locked = app.requestSingleInstanceLock()\n    if (!locked) {\n        app.quit()\n    }\n}\n\nif (!app.isPackaged) app.setAppUserModelId(process.execPath)\nelse if (process.platform === \"win32\")\n    app.setAppUserModelId(\"me.hyliu.fluentreader\")\n\nlet restarting = false\n\nfunction init() {\n    performUpdate(store)\n    nativeTheme.themeSource = store.get(\"theme\", ThemeSettings.Default)\n}\n\ninit()\n\nif (process.platform === \"darwin\") {\n    const template = [\n        {\n            label: \"Application\",\n            submenu: [\n                {\n                    label: \"Hide\",\n                    accelerator: \"Command+H\",\n                    click: () => {\n                        app.hide()\n                    },\n                },\n                {\n                    label: \"Quit\",\n                    accelerator: \"Command+Q\",\n                    click: () => {\n                        if (winManager.hasWindow) winManager.mainWindow.close()\n                    },\n                },\n            ],\n        },\n        {\n            label: \"Edit\",\n            submenu: [\n                {\n                    label: \"Undo\",\n                    accelerator: \"CmdOrCtrl+Z\",\n                    selector: \"undo:\",\n                },\n                {\n                    label: \"Redo\",\n                    accelerator: \"Shift+CmdOrCtrl+Z\",\n                    selector: \"redo:\",\n                },\n                { label: \"Cut\", accelerator: \"CmdOrCtrl+X\", selector: \"cut:\" },\n                {\n                    label: \"Copy\",\n                    accelerator: \"CmdOrCtrl+C\",\n                    selector: \"copy:\",\n                },\n                {\n                    label: \"Paste\",\n                    accelerator: \"CmdOrCtrl+V\",\n                    selector: \"paste:\",\n                },\n                {\n                    label: \"Select All\",\n                    accelerator: \"CmdOrCtrl+A\",\n                    selector: \"selectAll:\",\n                },\n            ],\n        },\n        {\n            label: \"Window\",\n            submenu: [\n                {\n                    label: \"Close\",\n                    accelerator: \"Command+W\",\n                    click: () => {\n                        if (winManager.hasWindow) winManager.mainWindow.close()\n                    },\n                },\n                {\n                    label: \"Minimize\",\n                    accelerator: \"Command+M\",\n                    click: () => {\n                        if (winManager.hasWindow())\n                            winManager.mainWindow.minimize()\n                    },\n                },\n                { label: \"Zoom\", click: () => winManager.zoom() },\n            ],\n        },\n    ]\n    Menu.setApplicationMenu(Menu.buildFromTemplate(template))\n} else {\n    Menu.setApplicationMenu(null)\n}\n\nconst winManager = new WindowManager()\n\napp.on(\"window-all-closed\", () => {\n    if (winManager.hasWindow()) {\n        winManager.mainWindow.webContents.session.clearStorageData({\n            storages: [\"cookies\", \"localstorage\"],\n        })\n    }\n    winManager.mainWindow = null\n    if (restarting) {\n        restarting = false\n        winManager.createWindow()\n    } else {\n        app.quit()\n    }\n})\n\nipcMain.handle(\"import-all-settings\", (_, configs: SchemaTypes) => {\n    restarting = true\n    store.clear()\n    for (let [key, value] of Object.entries(configs)) {\n        // @ts-ignore\n        store.set(key, value)\n    }\n    performUpdate(store)\n    nativeTheme.themeSource = store.get(\"theme\", ThemeSettings.Default)\n    setTimeout(\n        () => {\n            winManager.mainWindow.close()\n        },\n        process.platform === \"darwin\" ? 1000 : 0\n    ) // Why ???\n})\n"
  },
  {
    "path": "src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src-elem 'self'; img-src *; style-src 'self' 'unsafe-inline'; font-src 'self' https://static2.sharepointonline.com; connect-src https: http:\">\n    <title>Fluent Reader</title>\n    <link rel=\"stylesheet\" href=\"index.css\">\n  </head>\n  <body>\n    <div id=\"app\" style=\"height: 100%;\"></div>\n  </body>\n</html>"
  },
  {
    "path": "src/index.tsx",
    "content": "import * as React from \"react\"\nimport * as ReactDOM from \"react-dom\"\nimport { Provider } from \"react-redux\"\nimport { initializeIcons } from \"@fluentui/react/lib/Icons\"\nimport Root from \"./components/root\"\nimport { applyThemeSettings } from \"./scripts/settings\"\nimport { initApp, openTextMenu } from \"./scripts/models/app\"\nimport { rootStore } from \"./scripts/reducer\"\n\nwindow.settings.setProxy()\n\napplyThemeSettings()\ninitializeIcons(\"icons/\")\n\nrootStore.dispatch(initApp())\n\nwindow.utils.addMainContextListener((pos, text) => {\n    rootStore.dispatch(openTextMenu(pos, text))\n})\n\nwindow.fontList = [\"\"]\nwindow.utils.initFontList().then(fonts => {\n    window.fontList.push(...fonts)\n})\n\nReactDOM.render(\n    <Provider store={rootStore}>\n        <Root />\n    </Provider>,\n    document.getElementById(\"app\")\n)\n"
  },
  {
    "path": "src/main/settings.ts",
    "content": "import Store = require(\"electron-store\")\nimport {\n    SchemaTypes,\n    SourceGroup,\n    ViewType,\n    ThemeSettings,\n    SearchEngines,\n    SyncService,\n    ServiceConfigs,\n    ViewConfigs,\n} from \"../schema-types\"\nimport { ipcMain, session, nativeTheme, app } from \"electron\"\nimport { WindowManager } from \"./window\"\n\nexport const store = new Store<SchemaTypes>()\n\nconst GROUPS_STORE_KEY = \"sourceGroups\"\nipcMain.handle(\"set-groups\", (_, groups: SourceGroup[]) => {\n    store.set(GROUPS_STORE_KEY, groups)\n})\nipcMain.on(\"get-groups\", event => {\n    event.returnValue = store.get(GROUPS_STORE_KEY, [])\n})\n\nconst MENU_STORE_KEY = \"menuOn\"\nipcMain.on(\"get-menu\", event => {\n    event.returnValue = store.get(MENU_STORE_KEY, false)\n})\nipcMain.handle(\"set-menu\", (_, state: boolean) => {\n    store.set(MENU_STORE_KEY, state)\n})\n\nconst PAC_STORE_KEY = \"pac\"\nconst PAC_STATUS_KEY = \"pacOn\"\nfunction getProxyStatus() {\n    return store.get(PAC_STATUS_KEY, false)\n}\nfunction toggleProxyStatus() {\n    store.set(PAC_STATUS_KEY, !getProxyStatus())\n    setProxy()\n}\nfunction getProxy() {\n    return store.get(PAC_STORE_KEY, \"\")\n}\nfunction setProxy(address = null) {\n    if (!address) {\n        address = getProxy()\n    } else {\n        store.set(PAC_STORE_KEY, address)\n    }\n    if (getProxyStatus()) {\n        let rules = { pacScript: address }\n        session.defaultSession.setProxy(rules)\n        session.fromPartition(\"sandbox\").setProxy(rules)\n    }\n}\nipcMain.on(\"get-proxy-status\", event => {\n    event.returnValue = getProxyStatus()\n})\nipcMain.on(\"toggle-proxy-status\", () => {\n    toggleProxyStatus()\n})\nipcMain.on(\"get-proxy\", event => {\n    event.returnValue = getProxy()\n})\nipcMain.handle(\"set-proxy\", (_, address = null) => {\n    setProxy(address)\n})\n\nconst VIEW_STORE_KEY = \"view\"\nipcMain.on(\"get-view\", event => {\n    event.returnValue = store.get(VIEW_STORE_KEY, ViewType.Cards)\n})\nipcMain.handle(\"set-view\", (_, viewType: ViewType) => {\n    store.set(VIEW_STORE_KEY, viewType)\n})\n\nconst THEME_STORE_KEY = \"theme\"\nipcMain.on(\"get-theme\", event => {\n    event.returnValue = store.get(THEME_STORE_KEY, ThemeSettings.Default)\n})\nipcMain.handle(\"set-theme\", (_, theme: ThemeSettings) => {\n    store.set(THEME_STORE_KEY, theme)\n    nativeTheme.themeSource = theme\n})\nipcMain.on(\"get-theme-dark-color\", event => {\n    event.returnValue = nativeTheme.shouldUseDarkColors\n})\nexport function setThemeListener(manager: WindowManager) {\n    nativeTheme.removeAllListeners()\n    nativeTheme.on(\"updated\", () => {\n        if (manager.hasWindow()) {\n            let contents = manager.mainWindow.webContents\n            if (!contents.isDestroyed()) {\n                contents.send(\"theme-updated\", nativeTheme.shouldUseDarkColors)\n            }\n        }\n    })\n}\n\nconst LOCALE_STORE_KEY = \"locale\"\nipcMain.handle(\"set-locale\", (_, option: string) => {\n    store.set(LOCALE_STORE_KEY, option)\n})\nfunction getLocaleSettings() {\n    return store.get(LOCALE_STORE_KEY, \"default\")\n}\nipcMain.on(\"get-locale-settings\", event => {\n    event.returnValue = getLocaleSettings()\n})\nipcMain.on(\"get-locale\", event => {\n    let setting = getLocaleSettings()\n    let locale = setting === \"default\" ? app.getLocale() : setting\n    event.returnValue = locale\n})\n\nconst FONT_SIZE_STORE_KEY = \"fontSize\"\nipcMain.on(\"get-font-size\", event => {\n    event.returnValue = store.get(FONT_SIZE_STORE_KEY, 16)\n})\nipcMain.handle(\"set-font-size\", (_, size: number) => {\n    store.set(FONT_SIZE_STORE_KEY, size)\n})\n\nconst FONT_STORE_KEY = \"fontFamily\"\nipcMain.on(\"get-font\", event => {\n    event.returnValue = store.get(FONT_STORE_KEY, \"\")\n})\nipcMain.handle(\"set-font\", (_, font: string) => {\n    store.set(FONT_STORE_KEY, font)\n})\n\nipcMain.on(\"get-all-settings\", event => {\n    let output = {}\n    for (let [key, value] of store) {\n        output[key] = value\n    }\n    event.returnValue = output\n})\n\nconst FETCH_INTEVAL_STORE_KEY = \"fetchInterval\"\nipcMain.on(\"get-fetch-interval\", event => {\n    event.returnValue = store.get(FETCH_INTEVAL_STORE_KEY, 0)\n})\nipcMain.handle(\"set-fetch-interval\", (_, interval: number) => {\n    store.set(FETCH_INTEVAL_STORE_KEY, interval)\n})\n\nconst SEARCH_ENGINE_STORE_KEY = \"searchEngine\"\nipcMain.on(\"get-search-engine\", event => {\n    event.returnValue = store.get(SEARCH_ENGINE_STORE_KEY, SearchEngines.Google)\n})\nipcMain.handle(\"set-search-engine\", (_, engine: SearchEngines) => {\n    store.set(SEARCH_ENGINE_STORE_KEY, engine)\n})\n\nconst SERVICE_CONFIGS_STORE_KEY = \"serviceConfigs\"\nipcMain.on(\"get-service-configs\", event => {\n    event.returnValue = store.get(SERVICE_CONFIGS_STORE_KEY, {\n        type: SyncService.None,\n    })\n})\nipcMain.handle(\"set-service-configs\", (_, configs: ServiceConfigs) => {\n    store.set(SERVICE_CONFIGS_STORE_KEY, configs)\n})\n\nconst FILTER_TYPE_STORE_KEY = \"filterType\"\nipcMain.on(\"get-filter-type\", event => {\n    event.returnValue = store.get(FILTER_TYPE_STORE_KEY, null)\n})\nipcMain.handle(\"set-filter-type\", (_, filterType: number) => {\n    store.set(FILTER_TYPE_STORE_KEY, filterType)\n})\n\nconst LIST_CONFIGS_STORE_KEY = \"listViewConfigs\"\nipcMain.on(\"get-view-configs\", (event, view: ViewType) => {\n    switch (view) {\n        case ViewType.List:\n            event.returnValue = store.get(\n                LIST_CONFIGS_STORE_KEY,\n                ViewConfigs.ShowCover\n            )\n            break\n        default:\n            event.returnValue = undefined\n            break\n    }\n})\nipcMain.handle(\n    \"set-view-configs\",\n    (_, view: ViewType, configs: ViewConfigs) => {\n        switch (view) {\n            case ViewType.List:\n                store.set(LIST_CONFIGS_STORE_KEY, configs)\n                break\n        }\n    }\n)\n\nconst NEDB_STATUS_STORE_KEY = \"useNeDB\"\nipcMain.on(\"get-nedb-status\", event => {\n    event.returnValue = store.get(NEDB_STATUS_STORE_KEY, true)\n})\nipcMain.handle(\"set-nedb-status\", (_, flag: boolean) => {\n    store.set(NEDB_STATUS_STORE_KEY, flag)\n})\n"
  },
  {
    "path": "src/main/touchbar.ts",
    "content": "import { TouchBarTexts } from \"../schema-types\"\nimport { BrowserWindow, TouchBar } from \"electron\"\n\nfunction createTouchBarFunctionButton(\n    window: BrowserWindow,\n    text: string,\n    key: string\n) {\n    return new TouchBar.TouchBarButton({\n        label: text,\n        click: () => window.webContents.send(\"touchbar-event\", key),\n    })\n}\n\nexport function initMainTouchBar(texts: TouchBarTexts, window: BrowserWindow) {\n    const touchBar = new TouchBar({\n        items: [\n            createTouchBarFunctionButton(window, texts.menu, \"F1\"),\n            createTouchBarFunctionButton(window, texts.search, \"F2\"),\n            new TouchBar.TouchBarSpacer({ size: \"small\" }),\n            createTouchBarFunctionButton(window, texts.refresh, \"F5\"),\n            createTouchBarFunctionButton(window, texts.markAll, \"F6\"),\n            createTouchBarFunctionButton(window, texts.notifications, \"F7\"),\n        ],\n    })\n    window.setTouchBar(touchBar)\n}\n"
  },
  {
    "path": "src/main/update-scripts.ts",
    "content": "import { app } from \"electron\"\nimport Store = require(\"electron-store\")\nimport { SchemaTypes } from \"../schema-types\"\n\nexport default function performUpdate(store: Store<SchemaTypes>) {\n    let version = store.get(\"version\", null)\n    let useNeDB = store.get(\"useNeDB\", undefined)\n    let currentVersion = app.getVersion()\n\n    if (useNeDB === undefined) {\n        if (version !== null) {\n            const revs = version.split(\".\").map(s => parseInt(s))\n            store.set(\n                \"useNeDB\",\n                (revs[0] === 0 && revs[1] < 8) || !app.isPackaged\n            )\n        } else {\n            store.set(\"useNeDB\", false)\n        }\n    }\n    if (version != currentVersion) {\n        store.set(\"version\", currentVersion)\n    }\n}\n"
  },
  {
    "path": "src/main/utils.ts",
    "content": "import { ipcMain, shell, dialog, app, session, clipboard } from \"electron\"\nimport { WindowManager } from \"./window\"\nimport fs = require(\"fs\")\nimport { ImageCallbackTypes, TouchBarTexts } from \"../schema-types\"\nimport { initMainTouchBar } from \"./touchbar\"\nimport fontList = require(\"font-list\")\n\nexport function setUtilsListeners(manager: WindowManager) {\n    async function openExternal(url: string, background = false) {\n        if (url.startsWith(\"https://\") || url.startsWith(\"http://\")) {\n            if (background && process.platform === \"darwin\") {\n                shell.openExternal(url, { activate: false })\n            } else if (background && manager.hasWindow()) {\n                manager.mainWindow.setAlwaysOnTop(true)\n                await shell.openExternal(url)\n                setTimeout(() => manager.mainWindow.setAlwaysOnTop(false), 1000)\n            } else {\n                shell.openExternal(url)\n            }\n        }\n    }\n\n    app.on(\"web-contents-created\", (_, contents) => {\n        contents.setWindowOpenHandler(details => {\n            if (contents.getType() === \"webview\")\n                openExternal(\n                    details.url,\n                    details.disposition === \"background-tab\"\n                )\n            return {\n                action: manager.hasWindow() ? \"deny\" : \"allow\",\n            }\n        })\n        contents.on(\"will-navigate\", (event, url) => {\n            event.preventDefault()\n            if (contents.getType() === \"webview\") openExternal(url)\n        })\n    })\n\n    ipcMain.on(\"get-version\", event => {\n        event.returnValue = app.getVersion()\n    })\n\n    ipcMain.handle(\"open-external\", (_, url: string, background: boolean) => {\n        openExternal(url, background)\n    })\n\n    ipcMain.handle(\n        \"show-error-box\",\n        async (_, title, content, copy?: string) => {\n            if (manager.hasWindow() && copy != null) {\n                const response = await dialog.showMessageBox(\n                    manager.mainWindow,\n                    {\n                        type: \"error\",\n                        title: title,\n                        message: title,\n                        detail: content,\n                        buttons: [\"OK\", copy],\n                        cancelId: 0,\n                        defaultId: 0,\n                    }\n                )\n                if (response.response === 1) {\n                    clipboard.writeText(`${title}: ${content}`)\n                }\n            } else {\n                dialog.showErrorBox(title, content)\n            }\n        }\n    )\n\n    ipcMain.handle(\n        \"show-message-box\",\n        async (_, title, message, confirm, cancel, defaultCancel, type) => {\n            if (manager.hasWindow()) {\n                let response = await dialog.showMessageBox(manager.mainWindow, {\n                    type: type,\n                    title: title,\n                    message: title,\n                    detail: message,\n                    buttons:\n                        process.platform === \"win32\"\n                            ? [\"Yes\", \"No\"]\n                            : [confirm, cancel],\n                    cancelId: 1,\n                    defaultId: defaultCancel ? 1 : 0,\n                })\n                return response.response === 0\n            } else {\n                return false\n            }\n        }\n    )\n\n    ipcMain.handle(\n        \"show-save-dialog\",\n        async (_, filters: Electron.FileFilter[], path: string) => {\n            ipcMain.removeAllListeners(\"write-save-result\")\n            if (manager.hasWindow()) {\n                let response = await dialog.showSaveDialog(manager.mainWindow, {\n                    defaultPath: path,\n                    filters: filters,\n                })\n                if (!response.canceled) {\n                    ipcMain.handleOnce(\n                        \"write-save-result\",\n                        (_, result, errmsg) => {\n                            fs.writeFile(response.filePath, result, err => {\n                                if (err)\n                                    dialog.showErrorBox(errmsg, String(err))\n                            })\n                        }\n                    )\n                    return true\n                }\n            }\n            return false\n        }\n    )\n\n    ipcMain.handle(\n        \"show-open-dialog\",\n        async (_, filters: Electron.FileFilter[]) => {\n            if (manager.hasWindow()) {\n                let response = await dialog.showOpenDialog(manager.mainWindow, {\n                    filters: filters,\n                    properties: [\"openFile\"],\n                })\n                if (!response.canceled) {\n                    try {\n                        return await fs.promises.readFile(\n                            response.filePaths[0],\n                            \"utf-8\"\n                        )\n                    } catch (err) {\n                        console.log(err)\n                    }\n                }\n            }\n            return null\n        }\n    )\n\n    ipcMain.handle(\"get-cache\", async () => {\n        return await session.defaultSession.getCacheSize()\n    })\n\n    ipcMain.handle(\"clear-cache\", async () => {\n        await session.defaultSession.clearCache()\n    })\n\n    app.on(\"web-contents-created\", (_, contents) => {\n        if (contents.getType() === \"webview\") {\n            contents.on(\n                \"did-fail-load\",\n                (event, code, desc, validated, isMainFrame) => {\n                    if (isMainFrame && manager.hasWindow()) {\n                        manager.mainWindow.webContents.send(\n                            \"webview-error\",\n                            desc\n                        )\n                    }\n                }\n            )\n            contents.on(\"context-menu\", (_, params) => {\n                if (\n                    (params.hasImageContents ||\n                        params.selectionText ||\n                        params.linkURL) &&\n                    manager.hasWindow()\n                ) {\n                    if (params.hasImageContents) {\n                        ipcMain.removeHandler(\"image-callback\")\n                        ipcMain.handleOnce(\n                            \"image-callback\",\n                            (_, type: ImageCallbackTypes) => {\n                                switch (type) {\n                                    case ImageCallbackTypes.OpenExternal:\n                                    case ImageCallbackTypes.OpenExternalBg:\n                                        openExternal(\n                                            params.srcURL,\n                                            type ===\n                                                ImageCallbackTypes.OpenExternalBg\n                                        )\n                                        break\n                                    case ImageCallbackTypes.SaveAs:\n                                        contents.session.downloadURL(\n                                            params.srcURL\n                                        )\n                                        break\n                                    case ImageCallbackTypes.Copy:\n                                        contents.copyImageAt(params.x, params.y)\n                                        break\n                                    case ImageCallbackTypes.CopyLink:\n                                        clipboard.writeText(params.srcURL)\n                                        break\n                                }\n                            }\n                        )\n                        manager.mainWindow.webContents.send(\n                            \"webview-context-menu\",\n                            [params.x, params.y]\n                        )\n                    } else {\n                        manager.mainWindow.webContents.send(\n                            \"webview-context-menu\",\n                            [params.x, params.y],\n                            params.selectionText,\n                            params.linkURL\n                        )\n                    }\n                    contents\n                        .executeJavaScript(\n                            `new Promise(resolve => {\n                        const dismiss = () => {\n                            document.removeEventListener(\"mousedown\", dismiss)\n                            document.removeEventListener(\"scroll\", dismiss)                            \n                            resolve()\n                        }\n                        document.addEventListener(\"mousedown\", dismiss)\n                        document.addEventListener(\"scroll\", dismiss)\n                    })`\n                        )\n                        .then(() => {\n                            if (manager.hasWindow()) {\n                                manager.mainWindow.webContents.send(\n                                    \"webview-context-menu\"\n                                )\n                            }\n                        })\n                }\n            })\n            contents.on(\"before-input-event\", (_, input) => {\n                if (manager.hasWindow()) {\n                    let contents = manager.mainWindow.webContents\n                    contents.send(\"webview-keydown\", input)\n                }\n            })\n        }\n    })\n\n    ipcMain.handle(\"write-clipboard\", (_, text) => {\n        clipboard.writeText(text)\n    })\n\n    ipcMain.handle(\"close-window\", () => {\n        if (manager.hasWindow()) manager.mainWindow.close()\n    })\n\n    ipcMain.handle(\"minimize-window\", () => {\n        if (manager.hasWindow()) manager.mainWindow.minimize()\n    })\n\n    ipcMain.handle(\"maximize-window\", () => {\n        manager.zoom()\n    })\n\n    ipcMain.on(\"is-maximized\", event => {\n        event.returnValue =\n            Boolean(manager.mainWindow) && manager.mainWindow.isMaximized()\n    })\n\n    ipcMain.on(\"is-focused\", event => {\n        event.returnValue =\n            manager.hasWindow() && manager.mainWindow.isFocused()\n    })\n\n    ipcMain.on(\"is-fullscreen\", event => {\n        event.returnValue =\n            manager.hasWindow() && manager.mainWindow.isFullScreen()\n    })\n\n    ipcMain.handle(\"request-focus\", () => {\n        if (manager.hasWindow()) {\n            const win = manager.mainWindow\n            if (win.isMinimized()) win.restore()\n            if (process.platform === \"win32\") {\n                win.setAlwaysOnTop(true)\n                win.setAlwaysOnTop(false)\n            }\n            win.focus()\n        }\n    })\n\n    ipcMain.handle(\"request-attention\", () => {\n        if (manager.hasWindow() && !manager.mainWindow.isFocused()) {\n            if (process.platform === \"win32\") {\n                manager.mainWindow.flashFrame(true)\n                manager.mainWindow.once(\"focus\", () => {\n                    manager.mainWindow.flashFrame(false)\n                })\n            } else if (process.platform === \"darwin\") {\n                app.dock.bounce()\n            }\n        }\n    })\n\n    ipcMain.handle(\"touchbar-init\", (_, texts: TouchBarTexts) => {\n        if (manager.hasWindow()) initMainTouchBar(texts, manager.mainWindow)\n    })\n    ipcMain.handle(\"touchbar-destroy\", () => {\n        if (manager.hasWindow()) manager.mainWindow.setTouchBar(null)\n    })\n\n    ipcMain.handle(\"init-font-list\", () => {\n        return fontList.getFonts({\n            disableQuoting: true,\n        })\n    })\n}\n"
  },
  {
    "path": "src/main/window.ts",
    "content": "import windowStateKeeper = require(\"electron-window-state\")\nimport { BrowserWindow, nativeTheme, app } from \"electron\"\nimport path = require(\"path\")\nimport { setThemeListener } from \"./settings\"\nimport { setUtilsListeners } from \"./utils\"\n\nexport class WindowManager {\n    mainWindow: BrowserWindow = null\n    private mainWindowState: windowStateKeeper.State\n\n    constructor() {\n        this.init()\n    }\n\n    private init = () => {\n        app.on(\"ready\", () => {\n            this.mainWindowState = windowStateKeeper({\n                defaultWidth: 1200,\n                defaultHeight: 700,\n            })\n            this.setListeners()\n            this.createWindow()\n        })\n    }\n\n    private setListeners = () => {\n        setThemeListener(this)\n        setUtilsListeners(this)\n\n        app.on(\"second-instance\", () => {\n            if (this.mainWindow !== null) {\n                this.mainWindow.focus()\n            }\n        })\n\n        app.on(\"activate\", () => {\n            if (this.mainWindow === null) {\n                this.createWindow()\n            }\n        })\n    }\n\n    createWindow = () => {\n        if (!this.hasWindow()) {\n            this.mainWindow = new BrowserWindow({\n                title: \"Fluent Reader\",\n                backgroundColor:\n                    process.platform === \"darwin\"\n                        ? \"#00000000\"\n                        : nativeTheme.shouldUseDarkColors\n                        ? \"#282828\"\n                        : \"#faf9f8\",\n                vibrancy: \"sidebar\",\n                x: this.mainWindowState.x,\n                y: this.mainWindowState.y,\n                width: this.mainWindowState.width,\n                height: this.mainWindowState.height,\n                minWidth: 992,\n                minHeight: 600,\n                frame: process.platform === \"darwin\",\n                titleBarStyle: \"hiddenInset\",\n                fullscreenable: process.platform === \"darwin\",\n                show: false,\n                webPreferences: {\n                    webviewTag: true,\n                    contextIsolation: true,\n                    spellcheck: false,\n                    preload: path.join(\n                        app.getAppPath(),\n                        (app.isPackaged ? \"dist/\" : \"\") + \"preload.js\"\n                    ),\n                },\n            })\n            this.mainWindowState.manage(this.mainWindow)\n            this.mainWindow.on(\"ready-to-show\", () => {\n                this.mainWindow.show()\n                this.mainWindow.focus()\n                if (!app.isPackaged) this.mainWindow.webContents.openDevTools()\n            })\n            this.mainWindow.loadFile(\n                (app.isPackaged ? \"dist/\" : \"\") + \"index.html\"\n            )\n\n            this.mainWindow.on(\"maximize\", () => {\n                this.mainWindow.webContents.send(\"maximized\")\n            })\n            this.mainWindow.on(\"unmaximize\", () => {\n                this.mainWindow.webContents.send(\"unmaximized\")\n            })\n            this.mainWindow.on(\"enter-full-screen\", () => {\n                this.mainWindow.webContents.send(\"enter-fullscreen\")\n            })\n            this.mainWindow.on(\"leave-full-screen\", () => {\n                this.mainWindow.webContents.send(\"leave-fullscreen\")\n            })\n            this.mainWindow.on(\"focus\", () => {\n                this.mainWindow.webContents.send(\"window-focus\")\n            })\n            this.mainWindow.on(\"blur\", () => {\n                this.mainWindow.webContents.send(\"window-blur\")\n            })\n            this.mainWindow.webContents.on(\"context-menu\", (_, params) => {\n                if (params.selectionText) {\n                    this.mainWindow.webContents.send(\n                        \"window-context-menu\",\n                        [params.x, params.y],\n                        params.selectionText\n                    )\n                }\n            })\n        }\n    }\n\n    zoom = () => {\n        if (this.hasWindow()) {\n            if (this.mainWindow.isMaximized()) {\n                this.mainWindow.unmaximize()\n            } else {\n                this.mainWindow.maximize()\n            }\n        }\n    }\n\n    hasWindow = () => {\n        return this.mainWindow !== null && !this.mainWindow.isDestroyed()\n    }\n}\n"
  },
  {
    "path": "src/preload.ts",
    "content": "import { contextBridge } from \"electron\"\nimport settingsBridge from \"./bridges/settings\"\nimport utilsBridge from \"./bridges/utils\"\n\ncontextBridge.exposeInMainWorld(\"settings\", settingsBridge)\ncontextBridge.exposeInMainWorld(\"utils\", utilsBridge)\n"
  },
  {
    "path": "src/schema-types.ts",
    "content": "export class SourceGroup {\n    isMultiple: boolean\n    sids: number[]\n    name?: string\n    expanded?: boolean\n    index?: number // available only from menu or groups tab container\n\n    constructor(sids: number[], name: string = null) {\n        name = (name && name.trim()) || \"Source group\"\n        if (sids.length == 1) {\n            this.isMultiple = false\n        } else {\n            this.isMultiple = true\n            this.name = name\n            this.expanded = true\n        }\n        this.sids = sids\n    }\n}\n\nexport const enum ViewType {\n    Cards,\n    List,\n    Magazine,\n    Compact,\n    Customized,\n}\n\nexport const enum ViewConfigs {\n    ShowCover = 1 << 0,\n    ShowSnippet = 1 << 1,\n    FadeRead = 1 << 2,\n}\n\nexport const enum ThemeSettings {\n    Default = \"system\",\n    Light = \"light\",\n    Dark = \"dark\",\n}\n\nexport const enum SearchEngines {\n    Google,\n    Bing,\n    Baidu,\n    DuckDuckGo,\n}\n\nexport const enum ImageCallbackTypes {\n    OpenExternal,\n    OpenExternalBg,\n    SaveAs,\n    Copy,\n    CopyLink,\n}\n\nexport const enum SyncService {\n    None,\n    Fever,\n    Feedbin,\n    GReader,\n    Inoreader,\n    Miniflux,\n    Nextcloud,\n}\nexport interface ServiceConfigs {\n    type: SyncService\n    importGroups?: boolean\n}\n\nexport const enum WindowStateListenerType {\n    Maximized,\n    Focused,\n    Fullscreen,\n}\n\nexport interface TouchBarTexts {\n    menu: string\n    search: string\n    refresh: string\n    markAll: string\n    notifications: string\n}\n\nexport type SchemaTypes = {\n    version: string\n    theme: ThemeSettings\n    pac: string\n    pacOn: boolean\n    view: ViewType\n    locale: string\n    sourceGroups: SourceGroup[]\n    fontSize: number\n    fontFamily: string\n    menuOn: boolean\n    fetchInterval: number\n    searchEngine: SearchEngines\n    serviceConfigs: ServiceConfigs\n    filterType: number\n    listViewConfigs: ViewConfigs\n    useNeDB: boolean\n}\n"
  },
  {
    "path": "src/scripts/db.ts",
    "content": "import intl from \"react-intl-universal\"\nimport Datastore from \"nedb\"\nimport lf from \"lovefield\"\nimport { RSSSource } from \"./models/source\"\nimport { RSSItem } from \"./models/item\"\n\nconst sdbSchema = lf.schema.create(\"sourcesDB\", 3)\nsdbSchema\n    .createTable(\"sources\")\n    .addColumn(\"sid\", lf.Type.INTEGER)\n    .addPrimaryKey([\"sid\"], false)\n    .addColumn(\"url\", lf.Type.STRING)\n    .addColumn(\"iconurl\", lf.Type.STRING)\n    .addColumn(\"name\", lf.Type.STRING)\n    .addColumn(\"openTarget\", lf.Type.NUMBER)\n    .addColumn(\"lastFetched\", lf.Type.DATE_TIME)\n    .addColumn(\"serviceRef\", lf.Type.STRING)\n    .addColumn(\"fetchFrequency\", lf.Type.NUMBER)\n    .addColumn(\"rules\", lf.Type.OBJECT)\n    .addColumn(\"textDir\", lf.Type.NUMBER)\n    .addColumn(\"hidden\", lf.Type.BOOLEAN)\n    .addNullable([\"iconurl\", \"serviceRef\", \"rules\"])\n    .addIndex(\"idxURL\", [\"url\"], true)\n\nconst idbSchema = lf.schema.create(\"itemsDB\", 1)\nidbSchema\n    .createTable(\"items\")\n    .addColumn(\"_id\", lf.Type.INTEGER)\n    .addPrimaryKey([\"_id\"], true)\n    .addColumn(\"source\", lf.Type.INTEGER)\n    .addColumn(\"title\", lf.Type.STRING)\n    .addColumn(\"link\", lf.Type.STRING)\n    .addColumn(\"date\", lf.Type.DATE_TIME)\n    .addColumn(\"fetchedDate\", lf.Type.DATE_TIME)\n    .addColumn(\"thumb\", lf.Type.STRING)\n    .addColumn(\"content\", lf.Type.STRING)\n    .addColumn(\"snippet\", lf.Type.STRING)\n    .addColumn(\"creator\", lf.Type.STRING)\n    .addColumn(\"hasRead\", lf.Type.BOOLEAN)\n    .addColumn(\"starred\", lf.Type.BOOLEAN)\n    .addColumn(\"hidden\", lf.Type.BOOLEAN)\n    .addColumn(\"notify\", lf.Type.BOOLEAN)\n    .addColumn(\"serviceRef\", lf.Type.STRING)\n    .addNullable([\"thumb\", \"creator\", \"serviceRef\"])\n    .addIndex(\"idxDate\", [\"date\"], false, lf.Order.DESC)\n    .addIndex(\"idxService\", [\"serviceRef\"], false)\n\nexport let sourcesDB: lf.Database\nexport let sources: lf.schema.Table\nexport let itemsDB: lf.Database\nexport let items: lf.schema.Table\n\nasync function onUpgradeSourceDB(rawDb: lf.raw.BackStore) {\n    const version = rawDb.getVersion()\n    if (version < 2) {\n        await rawDb.addTableColumn(\"sources\", \"textDir\", 0)\n    }\n    if (version < 3) {\n        await rawDb.addTableColumn(\"sources\", \"hidden\", false)\n    }\n}\n\nexport async function init() {\n    sourcesDB = await sdbSchema.connect({ onUpgrade: onUpgradeSourceDB })\n    sources = sourcesDB.getSchema().table(\"sources\")\n    itemsDB = await idbSchema.connect()\n    items = itemsDB.getSchema().table(\"items\")\n    if (window.settings.getNeDBStatus()) {\n        await migrateNeDB()\n    }\n}\n\nasync function migrateNeDB() {\n    try {\n        const sdb = new Datastore<RSSSource>({\n            filename: \"sources\",\n            autoload: true,\n            onload: err => {\n                if (err) window.console.log(err)\n            },\n        })\n        const idb = new Datastore<RSSItem>({\n            filename: \"items\",\n            autoload: true,\n            onload: err => {\n                if (err) window.console.log(err)\n            },\n        })\n        const sourceDocs = await new Promise<RSSSource[]>(resolve => {\n            sdb.find({}, (_, docs) => {\n                resolve(docs)\n            })\n        })\n        const itemDocs = await new Promise<RSSItem[]>(resolve => {\n            idb.find({}, (_, docs) => {\n                resolve(docs)\n            })\n        })\n        const sRows = sourceDocs.map(doc => {\n            if (doc.serviceRef !== undefined)\n                doc.serviceRef = String(doc.serviceRef)\n            // @ts-ignore\n            delete doc._id\n            if (!doc.fetchFrequency) doc.fetchFrequency = 0\n            doc.textDir = 0\n            doc.hidden = false\n            return sources.createRow(doc)\n        })\n        const iRows = itemDocs.map(doc => {\n            if (doc.serviceRef !== undefined)\n                doc.serviceRef = String(doc.serviceRef)\n            if (!doc.title) doc.title = intl.get(\"article.untitled\")\n            if (!doc.content) doc.content = \"\"\n            if (!doc.snippet) doc.snippet = \"\"\n            delete doc._id\n            doc.starred = Boolean(doc.starred)\n            doc.hidden = Boolean(doc.hidden)\n            doc.notify = Boolean(doc.notify)\n            return items.createRow(doc)\n        })\n        await Promise.all([\n            sourcesDB.insert().into(sources).values(sRows).exec(),\n            itemsDB.insert().into(items).values(iRows).exec(),\n        ])\n        window.settings.setNeDBStatus(false)\n        sdb.remove({}, { multi: true }, () => {\n            sdb.persistence.compactDatafile()\n        })\n        idb.remove({}, { multi: true }, () => {\n            idb.persistence.compactDatafile()\n        })\n    } catch (err) {\n        window.utils.showErrorBox(\n            \"An error has occured during update. Please report this error on GitHub.\",\n            String(err)\n        )\n        window.utils.closeWindow()\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/README.md",
    "content": "## Internationalization\n\nCurrently, Fluent Reader supports the following languages.\n\n| Locale | Language | Credit |\n| --- | --- | --- |\n| en-US | English | [@yang991178](https://github.com/yang991178) |\n| cs | Čeština | [@vikdevelop](https://github.com/vikdevelop) |\n| es | Español | [@kant](https://github.com/kant) |\n| fr-FR | Français | [@Toinane](https://github.com/Toinane) |\n| fi-FI | Suomi | [@SUPERHAMSTERI](https://github.com/SUPERHAMSTERI) |\n| zh-CN | 中文（简体） | [@yang991178](https://github.com/yang991178) |\n| zh-TW | 中文（繁體） | [@jerryc127](https://github.com/jerryc127) |\n| ja | 日本語 | [@tiancheng2000](https://github.com/tiancheng2000) |\n| de | Deutsch | [@NoNamePro0](https://github.com/NoNamePro0) |\n| sv | Svenska | [@eson57](https://github.com/eson57) |\n| tr | Türkçe | [@mustafagenc](https://github.com/mustafagenc) |\n| uk | Ukrainian | [@thevllad](https://github.com/thevllad) |\n| nl | Nederlands | [@Vistaus](https://github.com/Vistaus) |\n| it | Italiano | [@andrewasd](https://github.com/andrewasd) |\n| pt-BR | Português do Brasil | [@fabianski7](https://github.com/fabianski7) |\n| pt-PT | Português de Portugal | [@0x1336](https://github.com/0x1336) |\n| ko | 한글 | [@1drive](https://github.com/1drive) |\n| ru | Russian | [@nxblnd](https://github.com/nxblnd) |\n\nRefer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization. \n"
  },
  {
    "path": "src/scripts/i18n/_locales.ts",
    "content": "import en_US from \"./en-US.json\"\nimport cs from \"./cs.json\"\nimport zh_CN from \"./zh-CN.json\"\nimport zh_TW from \"./zh-TW.json\"\nimport ja from \"./ja.json\"\nimport fr_FR from \"./fr-FR.json\"\nimport de from \"./de.json\"\nimport nl from \"./nl.json\"\nimport es from \"./es.json\"\nimport sv from \"./sv.json\"\nimport tr from \"./tr.json\"\nimport it from \"./it.json\"\nimport uk from \"./uk.json\"\nimport ru from \"./ru.json\"\nimport pt_BR from \"./pt-BR.json\"\nimport fi_FI from \"./fi-FI.json\"\nimport ko from \"./ko.json\"\nimport pt_PT from \"./pt-PT.json\"\n\nconst locales = {\n    \"en-US\": en_US,\n    \"cs\": cs,\n    \"zh-CN\": zh_CN,\n    \"zh-TW\": zh_TW,\n    \"ja\": ja,\n    \"fr-FR\": fr_FR,\n    \"de\": de,\n    \"nl\": nl,\n    \"es\": es,\n    \"sv\": sv,\n    \"tr\": tr,\n    \"it\": it,\n    \"uk\": uk,\n    \"ru\": ru,\n    \"pt-BR\": pt_BR,\n    \"fi-FI\": fi_FI,\n    \"ko\": ko,\n    \"pt-PT\": pt_PT,\n}\n\nexport default locales\n"
  },
  {
    "path": "src/scripts/i18n/cs.json",
    "content": "{\n    \"allArticles\": \"Všechny články\",\n    \"add\": \"Přidat\",\n    \"create\": \"Vytvořit\",\n    \"icon\": \"Ikona\",\n    \"name\": \"Název\",\n    \"openExternal\": \"Otevřít externě\",\n    \"emptyName\": \"Toto pole nesmí být prázdné.\",\n    \"emptyField\": \"Toto pole nesmí být prázdné.\",\n    \"edit\": \"Upravit\",\n    \"delete\": \"Odstranit\",\n    \"followSystem\": \"Podle systému\",\n    \"more\": \"Více\",\n    \"close\": \"Zavřít\",\n    \"search\": \"Hledat\",\n    \"loadMore\": \"Načíst více\",\n    \"dangerButton\": \"Potvrdit {action}?\",\n    \"confirmMarkAll\": \"Opravdu chcete označit všechny články na této stránce jako přečtené?\",\n    \"confirm\": \"Potvrdit\",\n    \"cancel\": \"Zrušit\",\n    \"default\": \"Výchozí\",\n    \"time\": {\n        \"now\": \"nyní\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minute} other {# minutes}}\",\n        \"hour\": \"{h, plural, =1 {# hour} other {# hours}}\",\n        \"day\": \"{d, plural, =1 {# day} other {# days}}\"\n    },\n    \"log\": {\n        \"empty\": \"Žádné notifikace\",\n        \"fetchFailure\": \"Nepodařilo se načíst zdroj \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Úspěšně načten {count, plural, =1 {# article} other {# articles}}.\",\n        \"networkError\": \"Došlo k chybě sítě.\",\n        \"parseError\": \"Při analýze kanálu XML došlo k chybě.\",\n        \"syncFailure\": \"Došlo k chybě při synchronizaci se službou\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Načíst znovu\",\n        \"markAllRead\": \"Označit vše jako přečtené\",\n        \"notifications\": \"Notifikace\",\n        \"view\": \"Zobrazit\",\n        \"settings\": \"Nastavení\",\n        \"minimize\": \"Maximalizovat\",\n        \"maximize\": \"Minimalizovat\"\n    },\n    \"menu\": {\n        \"close\": \"Zavřít menu\",\n        \"subscriptions\": \"Odběry\"\n    },\n    \"article\": {\n        \"error\": \"Nepodařilo se načíst článek.\",\n        \"reload\": \"Načíst znovu?\",\n        \"empty\": \"Žádné články\",\n        \"untitled\": \"(Bez titulku)\",\n        \"hide\": \"Skrýt článek\",\n        \"unhide\": \"Odkrýt článek\",\n        \"markRead\": \"Označit jako přečtené\",\n        \"markUnread\": \"Označit jako nepřečtené\",\n        \"markAbove\": \"Označte výše uvedené jako přečtené\",\n        \"markBelow\": \"Označte níže uvedené jako přečtené\",\n        \"star\": \"Ohvězdičkovat\",\n        \"unstar\": \"Odstranit hvězdu\",\n        \"fontSize\": \"Velikost písma\",\n        \"loadWebpage\": \"Načíst webovou stránku\",\n        \"loadFull\": \"Načíst všechen obsah\",\n        \"notify\": \"Upozornit, pokud je načteno na pozadí\",\n        \"dontNotify\": \"Neupozorňovat\",\n        \"textDir\": \"Směr textu\",\n        \"LTR\": \"Zleva doprava\",\n        \"RTL\": \"Zprava doleva\",\n        \"Vertical\": \"Vertikálně\",\n        \"font\": \"Písmo\"\n    },\n    \"context\": {\n        \"share\": \"Sdílet\",\n        \"read\": \"Číst\",\n        \"copyTitle\": \"Kopírovat titulek\",\n        \"copyURL\": \"Kopírovat odkaz\",\n        \"copy\": \"Kopírovat\",\n        \"search\": \"Hledat \\\"{text}\\\" on {engine}\",\n        \"view\": \"Zobrazit\",\n        \"cardView\": \"Karty\",\n        \"listView\": \"Seznam\",\n        \"magazineView\": \"Časopis\",\n        \"compactView\": \"Kompaktní\",\n        \"filter\": \"Filtrování\",\n        \"unreadOnly\": \"Jen nepřečtené\",\n        \"starredOnly\": \"Jen ohvězdičkované\",\n        \"fullSearch\": \"Vyhledat v plném textu\",\n        \"showHidden\": \"Zobrazit skryté články\",\n        \"manageSources\": \"Spravovat zdroje\",\n        \"saveImageAs\": \"Uložit obrázek jako …\",\n        \"copyImage\": \"Kopírovat obrázek\",\n        \"copyImageURL\": \"Kopírovat adresu obrázku\",\n        \"caseSensitive\": \"Rozlišovat velká a malá písmena\",\n        \"showCover\": \"Zobrazit kryt\",\n        \"showSnippet\": \"Zobrazit úryvek\",\n        \"fadeRead\": \" Vyblednout čtenné články\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Vyhledávač\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Došlo k chybě při zapisování souboru.\",\n        \"name\": \"Nastavení\",\n        \"fetching\": \"Probíhá aktualizace zdrojů, prosím vyčkejte …\",\n        \"exit\": \"Opustit nastavení\",\n        \"sources\": \"Zdroje\",\n        \"grouping\": \"Skupiny\",\n        \"rules\": \"Pravidla\",\n        \"service\": \"Služba\",\n        \"app\": \"Předvolby\",\n        \"about\": \"O aplikaci\",\n        \"version\": \"Verze\",\n        \"shortcuts\": \"Zkratky\",\n        \"openSource\": \"Otevřený zdrojový kód\",\n        \"feedback\": \"Zpětná vazba\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Zde importované nebo přidané zdroje nebudou synchronizovány s vaší službou.\",\n        \"serviceManaged\": \"Tento zdroj spravuje vaše služba.\",\n        \"untitled\": \"Zdroj\",\n        \"errorAdd\": \"Došlo k chybě při přidávání zdroje.\",\n        \"errorParse\": \"Při analýze souboru OPML došlo k chybě.\",\n        \"errorParseHint\": \"Ujistěte se, že soubor není poškozený a je kódován pomocí UTF-8.\",\n        \"errorImport\": \"Objevila se chyba při importování {count, plural, =1 {# source} other {# sources}}.\",\n        \"exist\": \"Tento zdroj již existuje.\",\n        \"opmlFile\": \"Soubor OPML\",\n        \"name\": \"Název zdroje\",\n        \"editName\": \"Upravit název\",\n        \"fetchFrequency\": \"Limit frekvence načítání\",\n        \"unlimited\": \"Neomezené\",\n        \"openTarget\": \"Výchozí otevřený cíl pro články\",\n        \"delete\": \"Odstranit zdroj\",\n        \"add\": \"Přidat zdroj\",\n        \"import\": \"Importovat\",\n        \"export\": \"Exportovat\",\n        \"rssText\": \"Celý text RSS\",\n        \"loadWebpage\": \"Načíst webovou stránku\",\n        \"inputUrl\": \"Zadejte URL adresu\",\n        \"badIcon\": \"Nesprávná ikona\",\n        \"badUrl\": \"Nesprávná URL adresa\",\n        \"deleteWarning\": \"Zdroj a všechny uložené články budou odstraněny.\",\n        \"selected\": \"Vybraný zdroj\",\n        \"selectedMulti\": \"Vybrat více zdrojů\",\n        \"hidden\": \"Ukryto v \\\"all articles\\\"\"\n    },\n    \"groups\": {\n        \"exist\": \"Tato skupina již existuje\",\n        \"type\": \"Typ\",\n        \"group\": \"Skupina\",\n        \"source\": \"Zdroj\",\n        \"capacity\": \"Kapacita\",\n        \"exitGroup\": \"Zpět na skupiny\",\n        \"deleteSource\": \"Odstranit ze skupiny\",\n        \"sourceHint\": \"Přetažením zdrojů změníte jejich pořadí.\",\n        \"create\": \"Vytvořit skupinu\",\n        \"selectedGroup\": \"Vybraná skupina\",\n        \"selectedSource\": \"Vybraný zdroj\",\n        \"enterName\": \"Zadejte název\",\n        \"editName\": \"Editovat název\",\n        \"deleteGroup\": \"Odstranit skupinu\",\n        \"chooseGroup\": \"Vybrat skupinu\",\n        \"addToGroup\": \"Přidat do ...\",\n        \"groupHint\": \"Dvojklikem na skupinu upravíte zdroje. Přetažením změníte pořadí.\"\n    },\n    \"rules\": {\n        \"intro\": \"Automatické označování článků nebo odesílání oznámení pomocí regulárních výrazů.\",\n        \"help\": \"Zjistit více\",\n        \"source\": \"Zdroj\",\n        \"selectSource\": \"Vybrat zdroj\",\n        \"new\": \"Nové pravidlo\",\n        \"if\": \"Pokud\",\n        \"then\": \"Poté\",\n        \"title\": \"Titulek\",\n        \"content\": \"Obsah\",\n        \"fullSearch\": \"Titulek nebo obsah\",\n        \"creator\": \"Autor\",\n        \"match\": \"odpovídá\",\n        \"notMatch\": \"neodpovídá\",\n        \"regex\": \"Pravidelný výraz\",\n        \"badRegex\": \"Nesprávný pravidelný výraz.\",\n        \"action\": \"Akce\",\n        \"selectAction\": \"Vybrat akce\",\n        \"hint\": \"Pravidla se použijí v pořadí. Tažením myši můžete změnit pořadí.\",\n        \"test\": \"Testovací pravidla\"\n    },\n    \"service\": {\n        \"intro\": \"Synchronizace mezi zařízeními pomocí služeb RSS.\",\n        \"select\": \"Vyberte službu\",\n        \"suggest\": \"Navrhnout novou službu\",\n        \"overwriteWarning\": \"Místní zdroje budou odstraněny, pokud ve službě existují.\",\n        \"groupsWarning\": \"Skupiny nejsou automaticky synchronizovány se službou.\",\n        \"rateLimitWarning\": \"Abyste se vyhnuli omezování rychlosti, musíte si vytvořit vlastní klíč API.\",\n        \"removeAd\": \"Odstranit reklamu\",\n        \"endpoint\": \"Koncový bod\",\n        \"username\": \"Uživatelské jméno\",\n        \"password\": \"Heslo\",\n        \"unchanged\": \"Nezměněno\",\n        \"fetchLimit\": \"Limit synchronizace\",\n        \"fetchLimitNum\": \"{count} nejnovějších článků\",\n        \"importGroups\": \"Importovat skupiny\",\n        \"failure\": \"Nedaří se připojit ke službě\",\n        \"failureHint\": \"Zkontrolujte konfiguraci služby nebo stav sítě.\",\n        \"fetchUnlimited\": \"Neomezený (nedoporučuje se)\",\n        \"exportToLite\": \"Exportovat do Fluent reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Vyčistit\",\n        \"cache\": \"Vyčistit mezipaměť\",\n        \"cacheSize\": \"Velikost {size} dat v mezipaměti\",\n        \"deleteChoices\": \"Odstranit články před ... dny\",\n        \"confirmDelete\": \"Odstranit\",\n        \"daysAgo\": \"{days, plural, =1 {# day} other {# days}} ago\",\n        \"deleteAll\": \"Odstranit věechny články\",\n        \"calculatingSize\": \"Probíhá výpočet velikosti...\",\n        \"itemSize\": \"Přibližně {size} místního úložiště zabírají články\",\n        \"confirmImport\": \"Opravdu chcete importovat data ze záložního souboru? Všechna aktuální data budou vymazána.\",\n        \"data\": \"Data aplikace\",\n        \"backup\": \"Záloha\",\n        \"restore\": \"Obnovit\",\n        \"frData\": \"Data aplikace Fluent Reader\",\n        \"language\": \"Zobrazovaný jazyk\",\n        \"theme\": \"Motiv\",\n        \"lightTheme\": \"Světlý motiv\",\n        \"darkTheme\": \"Tmavý motiv\",\n        \"enableProxy\": \"Povolit Proxy\",\n        \"badUrl\": \"Nesprávná URL\",\n        \"pac\": \"PAC Adresa\",\n        \"setPac\": \"Nastavit PAC\",\n        \"pacHint\": \"U proxy serverů Socks se doporučuje, aby PAC vracel \\\"SOCKS5\\\" pro DNS na straně proxy serveru. Vypnutí proxy vyžaduje restart.\",\n        \"fetchInterval\": \"Automatický interval načítání\",\n        \"never\": \"Nikdy\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/de.json",
    "content": "{\n    \"allArticles\": \"Alle Artikel\",\n    \"add\": \"Hinzufügen\",\n    \"create\": \"Erstellen\",\n    \"icon\": \"Icon\",\n    \"name\": \"Name\",\n    \"openExternal\": \"Extern öffnen\",\n    \"emptyName\": \"Dieses Feld darf nicht leer sein.\",\n    \"emptyField\": \"Dieses Feld darf nicht leer sein.\",\n    \"edit\": \"Bearbeiten\",\n    \"delete\": \"Entfernen\",\n    \"followSystem\": \"Systemstandard verwenden\",\n    \"more\": \"Mehr\",\n    \"close\": \"Schließen\",\n    \"search\": \"Suchen\",\n    \"loadMore\": \"Mehr laden\",\n    \"dangerButton\": \"Wirklich {action}?\",\n    \"confirmMarkAll\": \"Möchtest du wirklich alle Artikel als gelesen markieren?\",\n    \"confirm\": \"Bestätigen\",\n    \"cancel\": \"Abbrechen\",\n    \"time\": {\n        \"now\": \"gerade eben\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minute} other {# minutes}}\",\n        \"hour\": \"{h, plural, =1 {# hour} other {# hours}}\",\n        \"day\": \"{d, plural, =1 {# day} other {# days}}\"\n    },\n    \"log\": {\n        \"empty\": \"Keine Benachrichtigungen\",\n        \"fetchFailure\": \"Fehler beim Laden von \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Erfolgreich {count, plural, =1 {# Artikel} other {# Artikel}} geladen.\",\n        \"networkError\": \"Netzwerk-Fehler aufgetreten.\",\n        \"parseError\": \"Fehler beim Lesen des XML-Feeds.\",\n        \"syncFailure\": \"Fehler beim Synchronisieren.\"\n    },\n    \"nav\": {\n        \"menu\": \"Menü\",\n        \"refresh\": \"Neu laden\",\n        \"markAllRead\": \"Alles als gelesen markieren\",\n        \"notifications\": \"Benachrichtigungen\",\n        \"view\": \"Ansicht\",\n        \"settings\": \"Einstellungen\",\n        \"minimize\": \"Minimieren\",\n        \"maximize\": \"Maximieren\"\n    },\n    \"menu\": {\n        \"close\": \"Menü schließen\",\n        \"subscriptions\": \"Abonnements\"\n    },\n    \"article\": {\n        \"error\": \"Fehler beim Laden des Artikels.\",\n        \"reload\": \"Neu laden?\",\n        \"empty\": \"Keine Artikel vorhanden\",\n        \"untitled\": \"(Unbenannt)\",\n        \"hide\": \"Artikel ausblenden\",\n        \"unhide\": \"Artikel wieder anzeigen\",\n        \"markRead\": \"Als gelesen markieren\",\n        \"markUnread\": \"Als ungelesen markieren\",\n        \"markAbove\": \"Darüber als gelesen markieren\",\n        \"markBelow\": \"Darunter als gelesen markieren\",\n        \"star\": \"Favorisieren\",\n        \"unstar\": \"Favorit entfernen\",\n        \"fontSize\": \"Schriftgröße\",\n        \"loadWebpage\": \"Internetseite laden\",\n        \"loadFull\": \"Kompletten Inhalt laden\",\n        \"notify\": \"Benachrichtigen, wenn im Hintergrund geladen\",\n        \"dontNotify\": \"Nicht benachrichtigen\"\n    },\n    \"context\": {\n        \"share\": \"Teilen\",\n        \"read\": \"Lesen\",\n        \"copyTitle\": \"Titel kopieren\",\n        \"copyURL\": \"Link kopieren\",\n        \"copy\": \"Kopieren\",\n        \"search\": \"\\\"{text}\\\" mit {engine} suchen\",\n        \"view\": \"Ansicht\",\n        \"cardView\": \"Karten\",\n        \"listView\": \"Liste\",\n        \"magazineView\": \"Magazin\",\n        \"compactView\": \"Kompakt\",\n        \"filter\": \"Filter\",\n        \"unreadOnly\": \"Nur ungelesene\",\n        \"starredOnly\": \"Nur Favoriten\",\n        \"fullSearch\": \"Suche im kompletten Text\",\n        \"showHidden\": \"Ausgeblendete Artikel anzeigen\",\n        \"manageSources\": \"Feeds verwalten\",\n        \"saveImageAs\": \"Bild speichern unter …\",\n        \"copyImage\": \"Bild kopieren\",\n        \"copyImageURL\": \"Bild-Link kopieren\",\n        \"caseSensitive\": \"Groß-/Kleinschreibung beachten\",\n        \"showCover\": \"Cover anzeigen\",\n        \"showSnippet\": \"Ausschnitt anzeigen\",\n        \"fadeRead\": \"Gelesene Artikel ausblenden\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Suchmaschine\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Fehler beim Schreiben der Datei.\",\n        \"name\": \"Einstellungen\",\n        \"fetching\": \"Aktualisiere Feeds, bitte warten …\",\n        \"exit\": \"Einstellungen schließen\",\n        \"sources\": \"Feeds\",\n        \"grouping\": \"Gruppen\",\n        \"rules\": \"Regeln\",\n        \"service\": \"Server\",\n        \"app\": \"Einstellungen\",\n        \"about\": \"Info\",\n        \"version\": \"Version\",\n        \"shortcuts\": \"Verknüpfungen\",\n        \"openSource\": \"Open Source\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Feeds, die hier importiert oder hinzugefügt werden, können nicht mit dem Server synchronisiert werden.\",\n        \"serviceManaged\": \"Dieser Feed wird vom Server verwaltet.\",\n        \"untitled\": \"Feed\",\n        \"errorAdd\": \"Beim Hinzufügen des Feeds ist ein Fehler aufgetreten.\",\n        \"errorParse\": \"Beim Lesen der OPML-Datei ist ein Fehler aufgetreten.\",\n        \"errorParseHint\": \"Bitte überprüfe, ob die Datei nicht beschädigt und mit UTF-8 formatiert ist.\",\n        \"errorImport\": \"Fehler beim Importieren von {count, plural, =1 {# Feed} other {# Feeds}}.\",\n        \"exist\": \"Dieser Feed existiert bereits.\",\n        \"opmlFile\": \"OPML-Datei\",\n        \"name\": \"Name des Feeds\",\n        \"editName\": \"Name bearbeiten\",\n        \"fetchFrequency\": \"Abrufhäufigkeit begrenzen\",\n        \"unlimited\": \"Unbegrenzt\",\n        \"openTarget\": \"Standard-Ziel für Artikel\",\n        \"delete\": \"Feed entfernen\",\n        \"add\": \"Feed hinzufügen\",\n        \"import\": \"Importieren\",\n        \"export\": \"Exportieren\",\n        \"rssText\": \"RSS-Volltext\",\n        \"loadWebpage\": \"Internetseite laden\",\n        \"inputUrl\": \"URL einfügen\",\n        \"badIcon\": \"Ungültiges Icon\",\n        \"badUrl\": \"Ungültige URL\",\n        \"deleteWarning\": \"Der Feed und alle gespeicherten Artikel werden entfernt.\",\n        \"selected\": \"Ausgewählter Feed\",\n        \"selectedMulti\": \"Ausgewählte Feeds\"\n    },\n    \"groups\": {\n        \"exist\": \"Diese Gruppe existiert bereits.\",\n        \"type\": \"Typ\",\n        \"group\": \"Gruppe\",\n        \"source\": \"Feed\",\n        \"capacity\": \"Größe\",\n        \"exitGroup\": \"Zurück zu Gruppen\",\n        \"deleteSource\": \"Aus Gruppe entfernen\",\n        \"sourceHint\": \"Gruppen mit Drag & Drop sortieren.\",\n        \"create\": \"Gruppe erstelllen\",\n        \"selectedGroup\": \"Ausgewählte Gruppe\",\n        \"selectedSource\": \"Ausgewählte Feeds\",\n        \"enterName\": \"Name eingeben\",\n        \"editName\": \"Name speichern\",\n        \"deleteGroup\": \"Gruppe löschen\",\n        \"chooseGroup\": \"Wähle ein Gruppe aus\",\n        \"addToGroup\": \"Zur Gruppe hinzufügen\",\n        \"groupHint\": \"Doppelklicke auf die Gruppe um die Feeds zu bearbeiten. Drag & Drop zum Sortieren.\"\n    },\n    \"rules\": {\n        \"intro\": \"Artikel automatisch markieren oder Benachrichtigungen senden mit Hilfe regulärer Ausdrücke.\",\n        \"help\": \"Mehr erfahren\",\n        \"source\": \"Feed\",\n        \"selectSource\": \"Wähle einen Feed aus\",\n        \"new\": \"Neue Regel\",\n        \"if\": \"Wenn\",\n        \"then\": \"Dann\",\n        \"title\": \"Titel\",\n        \"content\": \"Inhalt\",\n        \"fullSearch\": \"Titel oder Inhalt\",\n        \"creator\": \"Autor/-in\",\n        \"match\": \"enspricht\",\n        \"notMatch\": \"entspricht nicht\",\n        \"regex\": \"regulärer Ausdruck\",\n        \"badRegex\": \"Ungültiger regulärer Ausdruck.\",\n        \"action\": \"Aktionen\",\n        \"selectAction\": \"Aktionen wählen\",\n        \"hint\": \"Die Regeln werden in Reihenfolge verarbeitet. Drag & Drop zum Sortieren.\",\n        \"test\": \"Regeln testen\"\n    },\n    \"service\": {\n        \"intro\": \"Mit RSS-Server über mehrere Geräte hinweg synchronisieren.\",\n        \"select\": \"Wähle ein Anbieter aus\",\n        \"suggest\": \"Schlage einen anderen Anbieter vor\",\n        \"overwriteWarning\": \"Lokale Feeds werden gelöscht, wenn sie auf dem Server schon existieren.\",\n        \"groupsWarning\": \"Gruppen werden nicht automatisch mit dem Server synchronisiert.\",\n        \"rateLimitWarning\": \"Um Abruf-Begrenzungen zu vermeiden, musst du einen eigenen API-Schlüssel erstellen.\",\n        \"removeAd\": \"Werbung entfernen\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Nutzername\",\n        \"password\": \"Passwort\",\n        \"unchanged\": \"Unverändert\",\n        \"fetchLimit\": \"Synchronisations-Limit\",\n        \"fetchLimitNum\": \"{count} Artikel\",\n        \"importGroups\": \"Gruppen importieren\",\n        \"failure\": \"Fehler beim Verbinden zum Server\",\n        \"failureHint\": \"Bitte überprüfe die Server-Konfiguration oder deinen Netzwerk-Status.\",\n        \"fetchUnlimited\": \"Unbegrenzt (nicht empfohlen)\",\n        \"exportToLite\": \"Für Fluent Reader Lite exportieren\"\n    },\n    \"app\": {\n        \"cleanup\": \"Aufräumen\",\n        \"cache\": \"Cache leeren\",\n        \"cacheSize\": \"{size} Daten gecacht\",\n        \"deleteChoices\": \"Entferne Artikel älter als ... Tage\",\n        \"confirmDelete\": \"Löschen\",\n        \"daysAgo\": \"{days} Tage\",\n        \"deleteAll\": \"Alle Artikel entfernen\",\n        \"calculatingSize\": \"Berechne Größe...\",\n        \"itemSize\": \"Ungefähr {size} lokaler Speicher wird für Artikel genutzt.\",\n        \"confirmImport\": \"Möchtest du deine Daten wirklich neu importieren? Deine aktuellen Daten werden gelöscht.\",\n        \"data\": \"App-Daten\",\n        \"backup\": \"Sichern\",\n        \"restore\": \"Wiederherstellen\",\n        \"frData\": \"Fluent Reader - Daten\",\n        \"language\": \"Anzeigesprache\",\n        \"theme\": \"Darstellung\",\n        \"lightTheme\": \"Hell\",\n        \"darkTheme\": \"Dunkel\",\n        \"enableProxy\": \"Proxy aktivieren\",\n        \"badUrl\": \"Ungültige URL\",\n        \"pac\": \"PAC-Adresse\",\n        \"setPac\": \"PAC-Adresse festlegen\",\n        \"pacHint\": \"Für SOCKS-Proxies wird empfohlen, für proxy-seitiges DNS im PAC \\\"SOCKS5\\\" zurückzugeben. Das Deaktivieren des Proxies erfordert einen Neustart.\",\n        \"fetchInterval\": \"Automatisches Abrufintervall\",\n        \"never\": \"Nie\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/en-US.json",
    "content": "{\n    \"allArticles\": \"All articles\",\n    \"add\": \"Add\",\n    \"create\": \"Create\",\n    \"icon\": \"Icon\",\n    \"name\": \"Name\",\n    \"openExternal\": \"Open externally\",\n    \"emptyName\": \"This field cannot be empty.\",\n    \"emptyField\": \"This field cannot be empty.\",\n    \"edit\": \"Edit\",\n    \"delete\": \"Delete\",\n    \"followSystem\": \"Follow system\",\n    \"more\": \"More\",\n    \"close\": \"Close\",\n    \"search\": \"Search\",\n    \"loadMore\": \"Load more\",\n    \"dangerButton\": \"Confirm {action}?\",\n    \"confirmMarkAll\": \"Do you really want to mark all articles on this page as read?\",\n    \"confirm\": \"Confirm\",\n    \"cancel\": \"Cancel\",\n    \"default\": \"Default\",\n    \"time\": {\n        \"now\": \"now\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minute} other {# minutes}}\",\n        \"hour\": \"{h, plural, =1 {# hour} other {# hours}}\",\n        \"day\": \"{d, plural, =1 {# day} other {# days}}\"\n    },\n    \"log\": {\n        \"empty\": \"No notifications\",\n        \"fetchFailure\": \"Failed to load source \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Successfully fetched {count, plural, =1 {# article} other {# articles}}.\",\n        \"networkError\": \"A network error has occurred.\",\n        \"parseError\": \"An error has occurred when parsing the XML feed.\",\n        \"syncFailure\": \"Failed to sync with service\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Refresh\",\n        \"markAllRead\": \"Mark all as read\",\n        \"notifications\": \"Notifications\",\n        \"view\": \"View\",\n        \"settings\": \"Settings\",\n        \"minimize\": \"Minimize\",\n        \"maximize\": \"Maximize\"\n    },\n    \"menu\": {\n        \"close\": \"Close menu\",\n        \"subscriptions\": \"Subscriptions\"\n    },\n    \"article\": {\n        \"error\": \"Failed to load article.\",\n        \"reload\": \"Reload?\",\n        \"empty\": \"No articles\",\n        \"untitled\": \"(Untitled)\",\n        \"hide\": \"Hide article\",\n        \"unhide\": \"Unhide article\",\n        \"markRead\": \"Mark as read\",\n        \"markUnread\": \"Mark as unread\",\n        \"markAbove\": \"Mark above as read\",\n        \"markBelow\": \"Mark below as read\",\n        \"star\": \"Star\",\n        \"unstar\": \"Remove star\",\n        \"fontSize\": \"Font size\",\n        \"loadWebpage\": \"Load webpage\",\n        \"loadFull\": \"Load full content\",\n        \"notify\": \"Notify if fetched in background\",\n        \"dontNotify\": \"Don't notify\",\n        \"textDir\": \"Text direction\",\n        \"LTR\": \"Left-to-right\",\n        \"RTL\": \"Right-to-left\",\n        \"Vertical\": \"Vertical\",\n        \"font\": \"Font\"\n    },\n    \"context\": {\n        \"share\": \"Share\",\n        \"read\": \"Read\",\n        \"copyTitle\": \"Copy title\",\n        \"copyURL\": \"Copy link\",\n        \"copy\": \"Copy\",\n        \"search\": \"Search \\\"{text}\\\" on {engine}\",\n        \"view\": \"View\",\n        \"cardView\": \"Card view\",\n        \"listView\": \"List view\",\n        \"magazineView\": \"Magazine view\",\n        \"compactView\": \"Compact view\",\n        \"filter\": \"Filtering\",\n        \"unreadOnly\": \"Unread only\",\n        \"starredOnly\": \"Starred only\",\n        \"fullSearch\": \"Search in full text\",\n        \"showHidden\": \"Show hidden articles\",\n        \"manageSources\": \"Manage sources\",\n        \"saveImageAs\": \"Save image as …\",\n        \"copyImage\": \"Copy image\",\n        \"copyImageURL\": \"Copy image link\",\n        \"caseSensitive\": \"Case sensitive\",\n        \"showCover\": \"Show cover\",\n        \"showSnippet\": \"Show snippet\",\n        \"fadeRead\": \"Fade read articles\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Search engine\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"An error has occurred while writing the file.\",\n        \"name\": \"Settings\",\n        \"fetching\": \"Updating sources, please wait …\",\n        \"exit\": \"Exit settings\",\n        \"sources\": \"Sources\",\n        \"grouping\": \"Groups\",\n        \"rules\": \"Rules\",\n        \"service\": \"Service\",\n        \"app\": \"Preferences\",\n        \"about\": \"About\",\n        \"version\": \"Version\",\n        \"shortcuts\": \"Shortcuts\",\n        \"openSource\": \"Open source\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Sources imported or added here will not be synced with your service.\",\n        \"serviceManaged\": \"This source is managed by your service.\",\n        \"untitled\": \"Source\",\n        \"errorAdd\": \"An error has occured when adding the source.\",\n        \"errorParse\": \"An error has occurred when parsing the OPML file.\",\n        \"errorParseHint\": \"Please ensure that the file isn't corrupted and is encoded with UTF-8.\",\n        \"errorImport\": \"Error importing {count, plural, =1 {# source} other {# sources}}.\",\n        \"exist\": \"This source already exists.\",\n        \"opmlFile\": \"OPML File\",\n        \"name\": \"Source name\",\n        \"editName\": \"Edit name\",\n        \"fetchFrequency\": \"Fetch frequency limit\",\n        \"unlimited\": \"Unlimited\",\n        \"openTarget\": \"Default open target for articles\",\n        \"delete\": \"Delete source\",\n        \"add\": \"Add source\",\n        \"import\": \"Import\",\n        \"export\": \"Export\",\n        \"rssText\": \"RSS full text\",\n        \"loadWebpage\": \"Load webpage\",\n        \"inputUrl\": \"Enter URL\",\n        \"badIcon\": \"Invalid icon\",\n        \"badUrl\": \"Invalid URL\",\n        \"deleteWarning\": \"The source and all saved articles will be removed.\",\n        \"selected\": \"Selected source\",\n        \"selectedMulti\": \"Selected multiple sources\",\n        \"hidden\": \"Hide in \\\"all articles\\\"\"\n    },\n    \"groups\": {\n        \"exist\": \"This group already exists.\",\n        \"type\": \"Type\",\n        \"group\": \"Group\",\n        \"source\": \"Source\",\n        \"capacity\": \"Capacity\",\n        \"exitGroup\": \"Back to groups\",\n        \"deleteSource\": \"Delete from group\",\n        \"sourceHint\": \"Drag and drop sources to reorder.\",\n        \"create\": \"Create group\",\n        \"selectedGroup\": \"Selected group\",\n        \"selectedSource\": \"Selected source\",\n        \"enterName\": \"Enter name\",\n        \"editName\": \"Edit name\",\n        \"deleteGroup\": \"Delete group\",\n        \"chooseGroup\": \"Select a group\",\n        \"addToGroup\": \"Add to ...\",\n        \"groupHint\": \"Double click on group to edit sources. Drag and drop to reorder.\"\n    },\n    \"rules\": {\n        \"intro\": \"Automatically mark articles or send notifications with regular expressions.\",\n        \"help\": \"Learn more\",\n        \"source\": \"Source\",\n        \"selectSource\": \"Select a source\",\n        \"new\": \"New Rule\",\n        \"if\": \"If\",\n        \"then\": \"Then\",\n        \"title\": \"Title\",\n        \"content\": \"Content\",\n        \"fullSearch\": \"Title or content\",\n        \"creator\": \"Author\",\n        \"match\": \"matches\",\n        \"notMatch\": \"doesn't match\",\n        \"regex\": \"Regular expression\",\n        \"badRegex\": \"Invalid regular expression.\",\n        \"action\": \"Actions\",\n        \"selectAction\": \"Select actions\",\n        \"hint\": \"Rules will be applied in order. Drag and drop to reorder.\",\n        \"test\": \"Test rules\"\n    },\n    \"service\": {\n        \"intro\": \"Sync across devices with RSS services.\",\n        \"select\": \"Select a service\",\n        \"suggest\": \"Suggest a new service\",\n        \"overwriteWarning\": \"Local sources will be deleted if they exist in the service.\",\n        \"groupsWarning\": \"Groups aren't automatically synced with the service.\",\n        \"rateLimitWarning\": \"To avoid rate limiting, you need to create your own API Key.\",\n        \"removeAd\": \"Remove Ad\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Username\",\n        \"password\": \"Password\",\n        \"unchanged\": \"Unchanged\",\n        \"fetchLimit\": \"Sync limit\",\n        \"fetchLimitNum\": \"{count} latest articles\",\n        \"importGroups\": \"Import groups\",\n        \"failure\": \"Cannot connect to service\",\n        \"failureHint\": \"Please check the service configuration or network status.\",\n        \"fetchUnlimited\": \"Unlimited (not recommended)\",\n        \"exportToLite\": \"Export to Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Clean up\",\n        \"cache\": \"Clear cache\",\n        \"cacheSize\": \"Cached {size} of data\",\n        \"deleteChoices\": \"Delete articles from ... days ago\",\n        \"confirmDelete\": \"Delete\",\n        \"daysAgo\": \"{days, plural, =1 {# day} other {# days}} ago\",\n        \"deleteAll\": \"Delete all articles\",\n        \"calculatingSize\": \"Calculating size...\",\n        \"itemSize\": \"Around {size} of local storage is occupied by articles\",\n        \"confirmImport\": \"Do you really want to import data from the backup file? All current data will be wiped.\",\n        \"data\": \"Application Data\",\n        \"backup\": \"Backup\",\n        \"restore\": \"Restore\",\n        \"frData\": \"Fluent Reader Data\",\n        \"language\": \"Display language\",\n        \"theme\": \"Theme\",\n        \"lightTheme\": \"Light mode\",\n        \"darkTheme\": \"Dark mode\",\n        \"enableProxy\": \"Enable Proxy\",\n        \"badUrl\": \"Invalid URL\",\n        \"pac\": \"PAC Address\",\n        \"setPac\": \"Set PAC\",\n        \"pacHint\": \"For Socks proxies, it is recommended for PAC to return \\\"SOCKS5\\\" for proxy-side DNS. Turning off proxy requires restart.\",\n        \"fetchInterval\": \"Automatic fetch interval\",\n        \"never\": \"Never\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/es.json",
    "content": "{\n    \"allArticles\": \"Todos los artículos\",\n    \"add\": \"Agregar\",\n    \"create\": \"Crear\",\n    \"icon\": \"Icono\",\n    \"name\": \"Nombre\",\n    \"openExternal\": \"Abrir de modo externo\",\n    \"emptyName\": \"Este campo no puede estar vacío.\",\n    \"emptyField\": \"Este campo no puede estar vacío.\",\n    \"edit\": \"Modificar\",\n    \"delete\": \"Eliminar\",\n    \"followSystem\": \"Seguir sistema\",\n    \"more\": \"Más\",\n    \"close\": \"Cerrar\",\n    \"search\": \"Buscar\",\n    \"loadMore\": \"Cargar más\",\n    \"dangerButton\": \"Confirmar {action}?\",\n    \"confirmMarkAll\": \"¿Desea realmente marcar todos los artículos en esta página como leídos?\",\n    \"confirm\": \"Confirmar\",\n    \"cancel\": \"Cancelar\",\n    \"time\": {\n        \"now\": \"ahora\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minuto} other {# minutos}}\",\n        \"hour\": \"{h, plural, =1 {# hora} other {# horas}}\",\n        \"day\": \"{d, plural, =1 {# día} other {# días}}\"\n    },\n    \"log\": {\n        \"empty\": \"Sin notificaciones\",\n        \"fetchFailure\": \"Falló al cargar fuente \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Recuperado exitosamente {count, plural, =1 {# artículo} other {# artículos}}.\"\n    },\n    \"nav\": {\n        \"menu\": \"Menú\",\n        \"refresh\": \"Actualizar\",\n        \"markAllRead\": \"Marcar todo como leído\",\n        \"notifications\": \"Notificaciones\",\n        \"view\": \"Ver\",\n        \"settings\": \"Configuraciones\",\n        \"minimize\": \"Minimizar\",\n        \"maximize\": \"Maximizar\"\n    },\n    \"menu\": {\n        \"close\": \"Cerrar menú\",\n        \"subscriptions\": \"Suscripciones\"\n    },\n    \"article\": {\n        \"empty\": \"Sin artículos\",\n        \"untitled\": \"(sin título)\",\n        \"hide\": \"Ocultar artículo\",\n        \"unhide\": \"Mostar artículo\",\n        \"markRead\": \"Marcar como leído\",\n        \"markUnread\": \"Marcar como no leído\",\n        \"star\": \"Destacar\",\n        \"unstar\": \"Quitar destacado\",\n        \"fontSize\": \"Tamaño de la fuente\",\n        \"loadWebpage\": \"Cargar página web\"\n    },\n    \"context\": {\n        \"share\": \"Compartir\",\n        \"read\": \"Leer\",\n        \"copyTitle\": \"Copiar título\",\n        \"copyURL\": \"Copiar enlace\",\n        \"copy\": \"Copiar\",\n        \"search\": \"Buscar \\\"{text}\\\" en {engine}\",\n        \"view\": \"Ver\",\n        \"cardView\": \"Vista en modo tarjeta\",\n        \"listView\": \"Vista en modo listado\",\n        \"magazineView\": \"Vista en modo revista\",\n        \"compactView\": \"Vista en modo compacta\",\n        \"filter\": \"Filtrando\",\n        \"unreadOnly\": \"Solo no leídos\",\n        \"starredOnly\": \"Solo destacados\",\n        \"fullSearch\": \"Buscar en todo el texto\",\n        \"showHidden\": \"Mostrar artículos ocultos\",\n        \"manageSources\": \"Gestionar fuentes\"\n    },\n    \"settings\": {\n        \"writeError\": \"Se produjo un error al escribir el archivo.\",\n        \"name\": \"Configuraciones\",\n        \"fetching\": \"Actualizando fuentes, por favor espere …\",\n        \"exit\": \"Salir de Configuraciones\",\n        \"sources\": \"Fuentes\",\n        \"grouping\": \"Agrupamiento\",\n        \"rules\": \"Reglas\",\n        \"app\": \"Preferencias\",\n        \"about\": \"Acerca\",\n        \"version\": \"Versión\",\n        \"shortcuts\": \"Atajos\",\n        \"openSource\": \"Abrir fuente\",\n        \"feedback\": \"Reacciones\"\n    },\n    \"sources\": {\n        \"untitled\": \"Fuente\",\n        \"errorAdd\": \"Se ha producido un error al agregar la fuente.\",\n        \"errorParse\": \"Se produjo un error al analizar el archivo OPML.\",\n        \"errorParseHint\": \"Por favor asegúrese que el archivo no está corrupto y codificado en formato UTF-8.\",\n        \"errorImport\": \"Error en la importación {count, plural, =1 {# fuente} other {# fuentes}}.\",\n        \"opmlFile\": \"Archivo OPML\",\n        \"name\": \"Nombre de la fuente\",\n        \"editName\": \"Modificar nombre\",\n        \"fetchFrequency\": \"Límite en la frecuencia de recolección de las fuentes\",\n        \"unlimited\": \"Ilimitado\",\n        \"openTarget\": \"Lugar predeterminado de apertura de los artículos\",\n        \"delete\": \"Eliminar fuente\",\n        \"add\": \"Agregar fuente\",\n        \"import\": \"Importar\",\n        \"export\": \"Exportar\",\n        \"rssText\": \"RSS texto completo\",\n        \"loadWebpage\": \"Cargar página web\",\n        \"inputUrl\": \"Ingresar dirección URL\",\n        \"badUrl\": \"URL no válida\",\n        \"deleteWarning\": \"Se eliminarán la fuente y todos los artículos guardados..\",\n        \"selected\": \"Fuente seleccionada\",\n        \"selectedMulti\": \"Múltiples fuentes seleccionadas\"\n    },\n    \"groups\": {\n        \"type\": \"Tipo\",\n        \"group\": \"Grupo\",\n        \"source\": \"Fuente\",\n        \"capacity\": \"Capacidad\",\n        \"exitGroup\": \"Volver a los grupos\",\n        \"deleteSource\": \"Eliminar del grupo\",\n        \"sourceHint\": \"Arrastrar y soltar fuentes para reordenar.\",\n        \"create\": \"Crear grupo\",\n        \"selectedGroup\": \"Grupo seleccionado\",\n        \"selectedSource\": \"Fuente seleccionada\",\n        \"enterName\": \"Ingresar nombre\",\n        \"editName\": \"Modificar nombre\",\n        \"deleteGroup\": \"Eliminar grupo\",\n        \"chooseGroup\": \"Seleccionar un grupo\",\n        \"addToGroup\": \"Agregar a ...\",\n        \"groupHint\": \"Doble clic sobre un grupo para modificar las fuentes. Arrastrar y soltar para reordenar.\"\n    },\n    \"rules\": {\n        \"source\": \"Fuente\",\n        \"selectSource\": \"Seleccionar una fuente\",\n        \"new\": \"Nueva regla\",\n        \"if\": \"Si\",\n        \"then\": \"Luego\",\n        \"title\": \"Título\",\n        \"content\": \"Contenido\",\n        \"fullSearch\": \"Título o contenido\",\n        \"match\": \"coincidencias\",\n        \"notMatch\": \"no coincide\",\n        \"regex\": \"Expresión regular\",\n        \"badRegex\": \"Expresión regular no válida.\",\n        \"action\": \"Acciones\",\n        \"selectAction\": \"Seleccionar acciones\",\n        \"hint\": \"Las reglas se aplicarán en orden. Arrastrar y soltar para reordenar.\",\n        \"test\": \"Probar reglas\"\n    },\n    \"app\": {\n        \"cleanup\": \"Limpiar\",\n        \"cache\": \"Limpiar caché\",\n        \"cacheSize\": \"{size} caché de datos\",\n        \"deleteChoices\": \"Eliminar artículos de hace ... días atrás\",\n        \"confirmDelete\": \"Eliminar\",\n        \"daysAgo\": \"hace {days} atrás\",\n        \"deleteAll\": \"Eliminar todos los artículos\",\n        \"calculatingSize\": \"Calculando tamaño...\",\n        \"itemSize\": \"Alrededor de {size} del almacenamiento local está ocupado por artículos\",\n        \"confirmImport\": \"¿Realmente desea importar datos desde el archivo de resguardo? Todos los actuales datos serán eliminados.\",\n        \"data\": \"Datos de la aplicación\",\n        \"backup\": \"Resguardo\",\n        \"restore\": \"Restaurar\",\n        \"frData\": \"Lector de datos\",\n        \"language\": \"Mostrar idioma\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Modo claro\",\n        \"darkTheme\": \"Modo oscuro\",\n        \"enableProxy\": \"Habilitar proxy\",\n        \"badUrl\": \"URL no válida\",\n        \"pac\": \"Dirección PAC\",\n        \"setPac\": \"Establecer PAC\",\n        \"pacHint\": \"Para proxies de tipo Socks proxies, se recomienda que PAC devuelva \\\"SOCKS5\\\" respecto del DNS del proxy. Desactivar el proxy requiere reiniciar.\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/fi-FI.json",
    "content": "{\n    \"add\": \"Lisää\",\n    \"allArticles\": \"Kaikki artikkelit\",\n    \"app\": {\n        \"backup\": \"Varmuuskopiointi\",\n        \"badUrl\": \"Virheellinen URL\",\n        \"cache\": \"Tyhjennä välimuisti\",\n        \"cacheSize\": \"Välimuistissa on {size} dataa\",\n        \"calculatingSize\": \"Lasketaan kokoa...\",\n        \"cleanup\": \"Siivoa\",\n        \"confirmDelete\": \"Poista\",\n        \"confirmImport\": \"Haluatko tuoda tiedot varmuuskopiosta? Kaikki nykyinen data poistetaan.\",\n        \"darkTheme\": \"Tumma tila\",\n        \"data\": \"Sovelluksen Data\",\n        \"daysAgo\": \"{days, plural, =1 {# päivä} other {# päivää}} sitten\",\n        \"deleteAll\": \"Poista kaikki artikkelit\",\n        \"deleteChoices\": \"Poista ... päivää vanhemmat artikkelit\",\n        \"enableProxy\": \"Käytä välityspalvelinta\",\n        \"fetchInterval\": \"Automaattinen päivitys\",\n        \"frData\": \"Fluent Reader Data\",\n        \"itemSize\": \"Artikkelit käyttävät {size} paikallista tallennustilaa\",\n        \"language\": \"Näyttökieli\",\n        \"lightTheme\": \"Vaalea tila\",\n        \"never\": \"Ei koskaan\",\n        \"pac\": \"PAC Osoite\",\n        \"pacHint\": \"Socks -välityspalvelimille on suositeltavaa asettaa PAC palauttamaan \\\"SOCKS5\\\" välityspalvelminen DNS:tä. Välityspalvelimen laittaminen pois päältä vaatii uudelleenkäynnistyksen,\",\n        \"restore\": \"Palauta\",\n        \"setPac\": \"Aseta PAC\",\n        \"theme\": \"Teema\"\n    },\n    \"article\": {\n        \"dontNotify\": \"Älä ilmoita\",\n        \"empty\": \"Ei artikkeleita\",\n        \"error\": \"Artikkelin lataaminen epäonnistui.\",\n        \"fontSize\": \"Fonttikoko\",\n        \"hide\": \"Piilota artikkeli\",\n        \"loadFull\": \"Lataa koko sisältö\",\n        \"loadWebpage\": \"Lataa verkkosivu\",\n        \"markAbove\": \"Merkitse ylemmät luetuksi\",\n        \"markBelow\": \"Merkitse alemmat luetuksi\",\n        \"markRead\": \"Merkitse luetuksi\",\n        \"markUnread\": \"Merkitse lukemattomaksi\",\n        \"notify\": \"Ilmoita, jos haetaan taustalla\",\n        \"reload\": \"Ladataanko uudelleen?\",\n        \"star\": \"Tähti\",\n        \"unhide\": \"Näytä artikkeli\",\n        \"unstar\": \"Poista tähti\",\n        \"untitled\": \"(Nimetön)\"\n    },\n    \"cancel\": \"Peruuta\",\n    \"close\": \"Sulje\",\n    \"confirm\": \"Vahvista\",\n    \"confirmMarkAll\": \"Haluatko todella merkitä kaikki tämän sivun artikkelit luetuiksi?\",\n    \"context\": {\n        \"cardView\": \"Kortit\",\n        \"caseSensitive\": \"Vain sama merkkikoko\",\n        \"compactView\": \"Kompakti\",\n        \"copy\": \"Kopioi\",\n        \"copyImage\": \"Kopioi kuva\",\n        \"copyImageURL\": \"Kopioi kuvalinkki\",\n        \"copyTitle\": \"Kopioi otsikko\",\n        \"copyURL\": \"Kopioi linkki\",\n        \"fadeRead\": \"Häivytä luetut artikkelit\",\n        \"filter\": \"Suodatus\",\n        \"fullSearch\": \"Hae koko tekstistä\",\n        \"listView\": \"Lista\",\n        \"magazineView\": \"Lehti\",\n        \"manageSources\": \"Hallitse lähteitä\",\n        \"read\": \"Luettu\",\n        \"saveImageAs\": \"Tallenna kuva nimellä…\",\n        \"search\": \"Hae \\\"{text}\\\" {engine}lla\",\n        \"share\": \"Jaa\",\n        \"showCover\": \"Näytä artikkelin kuva\",\n        \"showHidden\": \"Näytä piilotetut artikkelit\",\n        \"showSnippet\": \"Näytä katkelma\",\n        \"starredOnly\": \"Vain tähdellä merkityt\",\n        \"unreadOnly\": \"Vain lukemattomat\",\n        \"view\": \"Näkymä\"\n    },\n    \"create\": \"Luo\",\n    \"dangerButton\": \"Vahvistetaanko {action}?\",\n    \"delete\": \"Poista\",\n    \"edit\": \"Muokkaa\",\n    \"emptyField\": \"Tämä kenttä ei voi olla tyhjä.\",\n    \"emptyName\": \"Tämä kenttä ei voi olla tyhjä.\",\n    \"followSystem\": \"Käytä järjestelmän teemaa\",\n    \"groups\": {\n        \"addToGroup\": \"Lisää ...\",\n        \"capacity\": \"Määrä\",\n        \"chooseGroup\": \"Valitse ryhmä\",\n        \"create\": \"Luo ryhmä\",\n        \"deleteGroup\": \"Poista ryhmä\",\n        \"deleteSource\": \"Poista ryhmästä\",\n        \"editName\": \"Muokkaa nimeä\",\n        \"enterName\": \"Anna nimi\",\n        \"exist\": \"Tämä ryhmä on jo olemassa.\",\n        \"exitGroup\": \"Takaisin ryhmiin\",\n        \"group\": \"Ryhmä\",\n        \"groupHint\": \"Kaksoisnapsauta ryhmää muokataksesi sen lähteitä. Järjestä uudelleen vetämällä ja pudottamalla.\",\n        \"selectedGroup\": \"Valittu ryhmä\",\n        \"selectedSource\": \"Valittu lähde\",\n        \"source\": \"Lähde\",\n        \"sourceHint\": \"Järjestä uudelleen vetämällä ja pudottamalla lähteitä.\",\n        \"type\": \"Tyyppi\"\n    },\n    \"icon\": \"Kuvake\",\n    \"loadMore\": \"Lataa lisää\",\n    \"log\": {\n        \"empty\": \"Ei ilmoituksia\",\n        \"fetchFailure\": \"Lähteen \\\"{name}\\\" lataaminen epäonnistui.\",\n        \"fetchSuccess\": \"Noudettiin onnistuneesti {count, plural, =1 {# artikkeli} other {# artikkelia}}.\",\n        \"networkError\": \"Tapahtui verkkovirhe.\",\n        \"parseError\": \"XML-syötteen jäsentämisessä tapahtui virhe.\",\n        \"syncFailure\": \"Palvelun kanssa synkronointi epäonnistui\"\n    },\n    \"menu\": {\n        \"close\": \"Sulje valikko\",\n        \"subscriptions\": \"Tilaukset\"\n    },\n    \"more\": \"Lisää\",\n    \"name\": \"Nimi\",\n    \"nav\": {\n        \"markAllRead\": \"Merkitse kaikki luetuksi\",\n        \"maximize\": \"Laajenna\",\n        \"menu\": \"Valikko\",\n        \"minimize\": \"Pienennä\",\n        \"notifications\": \"Ilmoitukset\",\n        \"refresh\": \"Päivitä\",\n        \"settings\": \"Asetukset\",\n        \"view\": \"Näkymä\"\n    },\n    \"openExternal\": \"Avaa selaimessa\",\n    \"rules\": {\n        \"action\": \"Toiminto\",\n        \"badRegex\": \"Virheellinen sääntö.\",\n        \"content\": \"Sisältö\",\n        \"creator\": \"Kirjoittaja\",\n        \"fullSearch\": \"Otsikko tai sisältö\",\n        \"help\": \"Lisätietoja\",\n        \"hint\": \"Sääntöjä sovelletaan järjestyksessä. Järjestä uudelleen vetämällä ja pudottamalla.\",\n        \"if\": \"Jos\",\n        \"intro\": \"Merkitse artikkelit automaattisesti tai lähetä ilmoituksia säännöllisin lausekkein.\",\n        \"match\": \"täsmää\",\n        \"new\": \"Uusi sääntö\",\n        \"notMatch\": \"ei täsmää\",\n        \"regex\": \"Säännöllinen lauseke\",\n        \"selectAction\": \"Valitse toiminnot\",\n        \"selectSource\": \"Valitse lähde\",\n        \"source\": \"Lähde\",\n        \"test\": \"Testaa sääntöä\",\n        \"then\": \"Sitten\",\n        \"title\": \"Otsikko\"\n    },\n    \"search\": \"Hae\",\n    \"searchEngine\": {\n        \"baidu\": \"Baidu\",\n        \"bing\": \"Bing\",\n        \"duckduckgo\": \"DuckDuckGo\",\n        \"google\": \"Google\",\n        \"name\": \"Hakukone\"\n    },\n    \"service\": {\n        \"endpoint\": \"Osoite\",\n        \"exportToLite\": \"Vie Fluent Reader Lite -ohjelmaan\",\n        \"failure\": \"Palveluun ei voi muodostaa yhteyttä\",\n        \"failureHint\": \"Tarkista palvelun asetukset tai verkkoyhteytesi.\",\n        \"fetchLimit\": \"Synkronointiraja\",\n        \"fetchLimitNum\": \"{count} viimeisintä artikkelia\",\n        \"fetchUnlimited\": \"Rajoittamaton (ei suositella)\",\n        \"groupsWarning\": \"Ryhmiä ei synkronoida automaattisesti palvelun kanssa.\",\n        \"importGroups\": \"Tuo ryhmät\",\n        \"intro\": \"Synkronoi laitteiden välillä RSS-palveluiden kanssa.\",\n        \"overwriteWarning\": \"Paikalliset lähteet poistetaan, jos niitä on palvelussa.\",\n        \"password\": \"Salasana\",\n        \"rateLimitWarning\": \"Rajapintakäytön rajoituksien välttämiseksi sinun on luotava oma API-avain.\",\n        \"removeAd\": \"Poista mainos\",\n        \"select\": \"Valitse palvelu\",\n        \"suggest\": \"Ehdota uutta palvelua\",\n        \"unchanged\": \"Ei muutoksia\",\n        \"username\": \"Käyttäjätunnus\"\n    },\n    \"settings\": {\n        \"about\": \"Tietoja\",\n        \"app\": \"Asetukset\",\n        \"exit\": \"Poistu asetuksista\",\n        \"feedback\": \"Palaute\",\n        \"fetching\": \"Päivitetään lähteitä, odota…\",\n        \"grouping\": \"Ryhmät\",\n        \"name\": \"Asetukset\",\n        \"openSource\": \"Avoin lähdekoodi\",\n        \"rules\": \"Säännöt\",\n        \"service\": \"Palvelu\",\n        \"shortcuts\": \"Pikakomennot\",\n        \"sources\": \"Lähteet\",\n        \"version\": \"Versio\",\n        \"writeError\": \"Tiedostoa kirjoitettaessa tapahtui virhe.\"\n    },\n    \"sources\": {\n        \"add\": \"Lisää lähde\",\n        \"badIcon\": \"Virheellinen kuvake\",\n        \"badUrl\": \"Virheellinen URL\",\n        \"delete\": \"Poista lähde\",\n        \"deleteWarning\": \"Lähde ja kaikki tallennetut artikkelit poistetaan.\",\n        \"editName\": \"Muokkaa nimeä\",\n        \"errorAdd\": \"Lähdettä lisättäessä tapahtui virhe.\",\n        \"errorImport\": \"Virhe tuotaessa {count, plural, =1 {# lähdettä} other {# lähteitä}}.\",\n        \"errorParse\": \"OPML -tiedoston jäsentämisessä tapahtui virhe.\",\n        \"errorParseHint\": \"Varmista, että tiedosto ei ole vioittunut ja että se on koodattu UTF-8: lla.\",\n        \"exist\": \"Tämä lähde on jo olemassa.\",\n        \"export\": \"Vie\",\n        \"fetchFrequency\": \"Tietojen hakemisen raja\",\n        \"import\": \"Tuo\",\n        \"inputUrl\": \"Syötä URL\",\n        \"loadWebpage\": \"Lataa verkkosivu\",\n        \"name\": \"Lähteen nimi\",\n        \"openTarget\": \"Avaa artikkelit oletuksena\",\n        \"opmlFile\": \"OPML -tiedosto\",\n        \"rssText\": \"RSS koko teksti\",\n        \"selected\": \"Valittu lähde\",\n        \"selectedMulti\": \"Valittu useita lähteitä\",\n        \"serviceManaged\": \"Palvelu hallinnoi tätä lähdettä.\",\n        \"serviceWarning\": \"Täältä tuotuja tai lisättyjä lähteitä ei synkronoida palvelusi kanssa.\",\n        \"unlimited\": \"Rajoittamaton\",\n        \"untitled\": \"Lähde\"\n    },\n    \"time\": {\n        \"d\": \"pv\",\n        \"day\": \"{d, plural, =1 {# päivä} other {# päivää}}\",\n        \"h\": \"h\",\n        \"hour\": \"{h, plural, =1 {# tunti} other {# tuntia}}\",\n        \"m\": \"min\",\n        \"minute\": \"{m, plural, =1 {# minutti} other {# minuttia}}\",\n        \"now\": \"nyt\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/fr-FR.json",
    "content": "{\n    \"allArticles\": \"Tous les articles\",\n    \"add\": \"Ajouter\",\n    \"create\": \"Créer\",\n    \"icon\": \"Icône\",\n    \"name\": \"Nom\",\n    \"openExternal\": \"Ouvrir dans le navigateur\",\n    \"emptyName\": \"Ce champ ne peut pas être vide.\",\n    \"emptyField\": \"Ce champ ne peut pas être vide.\",\n    \"edit\": \"Modifier\",\n    \"delete\": \"Supprimer\",\n    \"followSystem\": \"Suivre le système\",\n    \"more\": \"Plus\",\n    \"close\": \"Fermer\",\n    \"search\": \"Rechercher\",\n    \"loadMore\": \"Charger plus\",\n    \"dangerButton\": \"Confirmer {action} ?\",\n    \"confirmMarkAll\": \"Voulez-vous vraiment marquer tous les articles de cette page comme lus ?\",\n    \"confirm\": \"Confirmer\",\n    \"cancel\": \"Annuler\",\n    \"time\": {\n        \"now\": \"maintenant\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"j\",\n        \"minute\": \"{m, plural, =1 {# minute} other {# minutes}}\",\n        \"hour\": \"{h, plural, =1 {# heure} other {# heures}}\",\n        \"day\": \"{d, plural, =1 {# jour} other {# jours}}\"\n    },\n    \"log\": {\n        \"empty\": \"Aucune notification\",\n        \"fetchFailure\": \"Échec du chargement de la source \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Récupération réussi de {count, plural, =1 {# article} other {# articles}}.\",\n        \"networkError\": \"Une erreur de réseau s'est produite.\",\n        \"parseError\": \"Une erreur s'est produite lors de l'analyse du flux XML.\",\n        \"syncFailure\": \"Échec de synchronisation avec le service\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Actualiser\",\n        \"markAllRead\": \"Marquer tout comme lu\",\n        \"notifications\": \"Notifications\",\n        \"view\": \"Affichage\",\n        \"settings\": \"Paramètres\",\n        \"minimize\": \"Réduire\",\n        \"maximize\": \"Agrandir\"\n    },\n    \"menu\": {\n        \"close\": \"Fermer le menu\",\n        \"subscriptions\": \"Abonnements\"\n    },\n    \"article\": {\n        \"error\": \"Impossible de charger l'article.\",\n        \"reload\": \"Recharger ?\",\n        \"empty\": \"Pas d'articles\",\n        \"untitled\": \"(Sans titre)\",\n        \"hide\": \"Masquer l'article\",\n        \"unhide\": \"Afficher l'article\",\n        \"markRead\": \"Marquer comme lu\",\n        \"markUnread\": \"Marquer comme non lu\",\n        \"markAbove\": \"Marquer ci-dessus comme lu\",\n        \"markBelow\": \"Marquer ci-dessous comme lu\",\n        \"star\": \"Mettre en favori\",\n        \"unstar\": \"Supprimer le favori\",\n        \"fontSize\": \"Taille de la police\",\n        \"loadWebpage\": \"Charger la page web\",\n        \"loadFull\": \"Charger tout le contenu\",\n        \"notify\": \"Notifier le chargement en arrière-plan\",\n        \"dontNotify\": \"Ne pas notifier\"\n    },\n    \"context\": {\n        \"share\": \"Partager\",\n        \"read\": \"Lire\",\n        \"copyTitle\": \"Copier le titre\",\n        \"copyURL\": \"Copier le lien\",\n        \"copy\": \"Copier\",\n        \"search\": \"Rechercher \\\"{text}\\\" sur {engine}\",\n        \"view\": \"Affichage\",\n        \"cardView\": \"Vue par carte\",\n        \"listView\": \"Vue par liste\",\n        \"magazineView\": \"Vue par magazine\",\n        \"compactView\": \"Vue par compact\",\n        \"filter\": \"Filtrer\",\n        \"unreadOnly\": \"Non lu uniquement\",\n        \"starredOnly\": \"Favoris uniquement\",\n        \"fullSearch\": \"Recherche dans le texte complet\",\n        \"showHidden\": \"Afficher les articles cachés\",\n        \"manageSources\": \"Gérer les sources\",\n        \"saveImageAs\": \"Enregistrer l'image sous…\",\n        \"copyImage\": \"Copier l'image\",\n        \"copyImageURL\": \"Copier l'adresse de l'image\",\n        \"caseSensitive\": \"Sensible à la casse\",\n        \"showCover\": \"Afficher couverture\",\n        \"showSnippet\": \"Afficher extrait\",\n        \"fadeRead\": \"Atténuer les articles lus\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Moteur de recherche\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Une erreur s'est produite lors de l'écriture du fichier.\",\n        \"name\": \"Paramètres\",\n        \"fetching\": \"Mise à jour des sources, veuillez patienter…\",\n        \"exit\": \"Fermer les paramètres\",\n        \"sources\": \"Sources\",\n        \"grouping\": \"Groupes\",\n        \"rules\": \"Règles\",\n        \"service\": \"Service\",\n        \"app\": \"Préférences\",\n        \"about\": \"À propos\",\n        \"version\": \"Version\",\n        \"shortcuts\": \"Raccourcis\",\n        \"openSource\": \"Open source\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Les sources importées ou ajoutées ici ne seront pas synchronisées avec votre service.\",\n        \"serviceManaged\": \"Cette source est gérée par votre service.\",\n        \"untitled\": \"Source\",\n        \"errorAdd\": \"Une erreur s'est produite lors de l'ajout de la source.\",\n        \"errorParse\": \"Une erreur s'est produite lors de l'analyse du fichier OPML.\",\n        \"errorParseHint\": \"Veuillez vous assurer que le fichier n'est pas corrompu et qu'il est encodé en UTF-8.\",\n        \"errorImport\": \"Erreur d'importation pour {count, plural, =1 {# source} other {# sources}}.\",\n        \"exist\": \"Cette source existe déjà.\",\n        \"opmlFile\": \"Fichier OPML\",\n        \"name\": \"Nom de la source\",\n        \"editName\": \"Modifier le nom\",\n        \"fetchFrequency\": \"Limitation de la fréquence de collecte des données\",\n        \"unlimited\": \"Illimité\",\n        \"openTarget\": \"Mode d'ouverture par défaut des articles\",\n        \"delete\": \"Supprimer la source\",\n        \"add\": \"Ajouter la source\",\n        \"import\": \"Importer\",\n        \"export\": \"Exporter\",\n        \"rssText\": \"Texte complet RSS\",\n        \"loadWebpage\": \"Charger la page web\",\n        \"inputUrl\": \"Saisissez l'adresse URL\",\n        \"badIcon\": \"Icône invalide\",\n        \"badUrl\": \"Adresse URL invalide\",\n        \"deleteWarning\": \"La source et tous les articles sauvegardés seront supprimés.\",\n        \"selected\": \"Source sélectionnée\",\n        \"selectedMulti\": \"Sources multiples sélectionnées\"\n    },\n    \"groups\": {\n        \"exist\": \"Ce groupe existe déjà.\",\n        \"type\": \"Type\",\n        \"group\": \"Groupe\",\n        \"source\": \"Source\",\n        \"capacity\": \"Contenu\",\n        \"exitGroup\": \"Retour aux groupes\",\n        \"deleteSource\": \"Supprimer du groupe\",\n        \"sourceHint\": \"Glisser-déposer les sources pour les réorganiser.\",\n        \"create\": \"Créer un groupe\",\n        \"selectedGroup\": \"Groupe sélectionné\",\n        \"selectedSource\": \"Source sélectionnée\",\n        \"enterName\": \"Saisissez un nom\",\n        \"editName\": \"Modifier le nom\",\n        \"deleteGroup\": \"Supprimer le groupe\",\n        \"chooseGroup\": \"Selectionner un groupe\",\n        \"addToGroup\": \"Ajouter à ...\",\n        \"groupHint\": \"Double-cliquez sur le groupe pour modifier ses sources. Faites un glisser-déposer pour réorganiser les sources.\"\n    },\n    \"rules\": {\n        \"intro\": \"Marquez automatiquement les articles ou envoyez des notifications avec des expressions régulières.\",\n        \"help\": \"En savoir plus\",\n        \"source\": \"Source\",\n        \"selectSource\": \"Sélectionner une source\",\n        \"new\": \"Nouvelle règle\",\n        \"if\": \"Si\",\n        \"then\": \"Alors\",\n        \"title\": \"Titre\",\n        \"content\": \"Contenu\",\n        \"fullSearch\": \"Titre ou contenu\",\n        \"creator\": \"Auteur\",\n        \"match\": \"correspond à\",\n        \"notMatch\": \"ne correspond pas à\",\n        \"regex\": \"Expression régulière\",\n        \"badRegex\": \"Expression régulière invalide.\",\n        \"action\": \"Actions\",\n        \"selectAction\": \"Sélectionner action\",\n        \"hint\": \"Les règles seront appliquées dans l'ordre. Glisser-déposer pour réorganiser.\",\n        \"test\": \"Tester les règles\"\n    },\n    \"service\": {\n        \"intro\": \"Synchronisation entre les appareils avec des services RSS.\",\n        \"select\": \"Sélectionner un service\",\n        \"suggest\": \"Proposer un nouveau service\",\n        \"overwriteWarning\": \"Les sources locales seront supprimées si elles existent dans le service.\",\n        \"groupsWarning\": \"Les groupes ne sont pas automatiquement synchronisés avec le service.\",\n        \"endpoint\": \"Adresse\",\n        \"username\": \"Pseudo\",\n        \"password\": \"Mot de passe\",\n        \"unchanged\": \"Inchangé\",\n        \"fetchLimit\": \"Limite de synchronisation\",\n        \"fetchLimitNum\": \"{count} articles récents\",\n        \"importGroups\": \"Importer des groupes\",\n        \"failure\": \"Impossible de se connecter au service\",\n        \"failureHint\": \"Veuillez vérifier la configuration du service ou l'état du réseau.\",\n        \"fetchUnlimited\": \"Illimité (non recommandé)\"\n    },\n    \"app\": {\n        \"cleanup\": \"Nettoyage\",\n        \"cache\": \"Supprimer le cache\",\n        \"cacheSize\": \"{size} de données mises en cache\",\n        \"deleteChoices\": \"Supprimer les articles antérieurs à ... jours\",\n        \"confirmDelete\": \"Supprimer\",\n        \"daysAgo\": \"{days, plural, =1 {# jour} other {# jours}}\",\n        \"deleteAll\": \"Supprimer tous les articles\",\n        \"calculatingSize\": \"Calcul de la taille...\",\n        \"itemSize\": \"Environ {size} du stockage local est occupé par des articles\",\n        \"confirmImport\": \"Voulez-vous vraiment importer des données du fichier de sauvegarde ? Toutes les données actuelles seront effacées.\",\n        \"data\": \"Données de l'appplication\",\n        \"backup\": \"Sauvegarder\",\n        \"restore\": \"Restorer\",\n        \"frData\": \"Données de Fluent Reader\",\n        \"language\": \"Langue d'affichage\",\n        \"theme\": \"Thème\",\n        \"lightTheme\": \"Mode jour\",\n        \"darkTheme\": \"Mode nuit\",\n        \"enableProxy\": \"Activer le Proxy\",\n        \"badUrl\": \"Adresse URL invalide\",\n        \"pac\": \"Adresse PAC\",\n        \"setPac\": \"Définir PAC\",\n        \"pacHint\": \"Pour les proxies Sockets, il est recommandé que le PAC retourne \\\"SOCKS5\\\" pour le DNS côté proxies. La désactivation du proxy nécessite un redémarrage.\",\n        \"fetchInterval\": \"Intervalle de récupération automatique\",\n        \"never\": \"Jamais\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/it.json",
    "content": "{\n    \"allArticles\": \"Tutti gli articoli\",\n    \"add\": \"Aggiungi\",\n    \"create\": \"Crea\",\n    \"icon\": \"Icona\",\n    \"name\": \"Nome\",\n    \"openExternal\": \"Apri Esternamente\",\n    \"emptyName\": \"Questo campo non puo essere vuoto\",\n    \"emptyField\": \"Questo campo non puo essere vuoto\",\n    \"edit\": \"Modifica\",\n    \"delete\": \"Elimina\",\n    \"followSystem\": \"segui impostazioni di sistema\",\n    \"more\": \"di più\",\n    \"close\": \"Chiudi\",\n    \"search\": \"Cerca\",\n    \"loadMore\": \"Carica piu feed\",\n    \"dangerButton\": \"Confermi di {action}?\",\n    \"confirmMarkAll\": \"Vuoi veramente segnare tutti i feed di questa pagina come letti?\",\n    \"confirm\": \"Confema\",\n    \"cancel\": \"Anulla\",\n    \"time\": {\n        \"now\": \"ora\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"g\",\n        \"minute\": \"{m, plural, =1 {# minuto} other {# minuti}}\",\n        \"hour\": \"{h, plural, =1 {# ora} other {# ore}}\",\n        \"day\": \"{d, plural, =1 {# giorno} other {# giorni}}\"\n    },\n    \"log\": {\n        \"empty\": \"Non ci sono notifiche\",\n        \"fetchFailure\": \"Errore nel caricare la fonte \\\"{name}\\\".\",\n        \"fetchSuccess\": \"{count, plural, =1 {# articolo} other {# articoli}} caricato con successo\",\n        \"networkError\": \"è occorso un errore di rete\",\n        \"parseError\": \"è occorso un errore nel anallizzare il feed rss\",\n        \"syncFailure\": \"Errore nel sicronizzarsi con il servizio\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Aggiorna\",\n        \"markAllRead\": \"Segna tutti come letti\",\n        \"notifications\": \"Notifiche\",\n        \"view\": \"View\",\n        \"settings\": \"Impostazioni\",\n        \"minimize\": \"Riduci a Icona\",\n        \"maximize\": \"Ingrandisci\"\n    },\n    \"menu\": {\n        \"close\": \"Chiudi menu\",\n        \"subscriptions\": \"Iscrizioni\"\n    },\n    \"article\": {\n        \"error\": \"Errore nel caricare articolo\",\n        \"reload\": \"Aggiorna?\",\n        \"empty\": \"Non ci sono articoli\",\n        \"untitled\": \"(Senza titolo)\",\n        \"hide\": \"Nascondi articolo\",\n        \"unhide\": \"Mostra articolo\",\n        \"markRead\": \"Segna come letto\",\n        \"markUnread\": \"Segna come non letto\",\n        \"markAbove\": \"Segna precedenti come letti\",\n        \"markBelow\": \"Segna successivi come letti\",\n        \"star\": \"salva\",\n        \"unstar\": \"rimuovi dai salvati\",\n        \"fontSize\": \"Dimensione testo\",\n        \"loadWebpage\": \"Carica pagina\",\n        \"loadFull\": \"Carica tutto il contenuto\",\n        \"notify\": \"Notifica se caricato in background\",\n        \"dontNotify\": \"Non notificare\"\n    },\n    \"context\": {\n        \"share\": \"Convidi\",\n        \"read\": \"Leggi\",\n        \"copyTitle\": \"Copia titolo\",\n        \"copyURL\": \"Copia link\",\n        \"copy\": \"Copia\",\n        \"search\": \"Cerca \\\"{text}\\\" on {engine}\",\n        \"view\": \"Visualizza\",\n        \"cardView\": \"Card view\",\n        \"listView\": \"List view\",\n        \"magazineView\": \"Magazine view\",\n        \"compactView\": \"Compact view\",\n        \"filter\": \"Filtra\",\n        \"unreadOnly\": \"Solo non letti\",\n        \"starredOnly\": \"Solo Salvati\",\n        \"fullSearch\": \"Cerca in tutto il lesto\",\n        \"showHidden\": \"Visualizza articoli nascosti\",\n        \"manageSources\": \"Gestisci fonti\",\n        \"saveImageAs\": \"Salva immagine come  …\",\n        \"copyImage\": \"Copia immagine\",\n        \"copyImageURL\": \"Copia immagine link\",\n        \"caseSensitive\": \"Case sensitive\",\n        \"showCover\": \"Mostra copertina\",\n        \"showSnippet\": \"Show snippet\",\n        \"fadeRead\": \"Scolorisci articoli letti\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Motore di ricerca\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"è occorso un errore nello scrivere il file\",\n        \"name\": \"Impostazioni\",\n        \"fetching\": \"Aggiornamento delle fonti..Attendi\",\n        \"exit\": \"Esci dalle Impostazioni\",\n        \"sources\": \"Fonti\",\n        \"grouping\": \"Gruppi\",\n        \"rules\": \"Regole\",\n        \"service\": \"Servizio\",\n        \"app\": \"Preferenze\",\n        \"about\": \"Informazioni\",\n        \"version\": \"Versione\",\n        \"shortcuts\": \"Shortcuts\",\n        \"openSource\": \"Open source\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"le fonti importate o aggiunte qui non saranno sincronizzate con il tuo servizio\",\n        \"serviceManaged\": \"la fonte è gesita dal tuo servizio\",\n        \"untitled\": \"Fonte\",\n        \"errorAdd\": \"Un errore è occorso nel caricare la fonte\",\n        \"errorParse\": \"Un errore è occorso nell analizzare il file OPML\",\n        \"errorParseInt\": \"Assicurati che il file non sia corrotto è sia in formato utf-8\",\n        \"errorImport\": \"Errore nel importare {count, plural, =1 {# fonte} other {# fonti}}.\",\n        \"exist\": \"Questa fonte è gia stata aggiunta\",\n        \"opmlFile\": \"OPML File\",\n        \"name\": \"Nome fonte\",\n        \"editName\": \"Modifica Nome\",\n        \"fetchFrequency\": \"Limite frecquenza di aggiornamento\",\n        \"unlimited\": \"Senza limite\",\n        \"openTarget\": \"Luogo predefinito di apertura degli articoli\",\n        \"delete\": \"Elimina fonte\",\n        \"add\": \"Aggiungi fonte\",\n        \"import\": \"Importa\",\n        \"export\": \"Esporta\",\n        \"rssText\": \"RSS visualizza tutto il testo\",\n        \"loadWebpage\": \"Carica pagina\",\n        \"inputUrl\": \"Inserisci URL\",\n        \"badIcon\": \"Icona non valida\",\n        \"badUrl\": \"URL non valido\",\n        \"deleteWarning\": \"La fonte è tutti i relativi articoli salvati verranno eliminati\",\n        \"selected\": \"Seleziona fonte\",\n        \"selectedMulti\": \"Seleziona più fonti\"\n    },\n    \"groups\": {\n        \"exist\": \"Questo gruppo già esiste\",\n        \"type\": \"Tipo\",\n        \"group\": \"Gruppo\",\n        \"source\": \"Fonte\",\n        \"capacity\": \"Capacita\",\n        \"exitGroup\": \"Ritorna ai gruppi\",\n        \"deleteSource\": \"Rimuovi dal gruppo\",\n        \"sourceHint\": \"Clicca e trascina le fonti per ordinarle\",\n        \"create\": \"Crea gruppo\",\n        \"selectedGroup\": \"Seleziona gruppo\",\n        \"selectedSource\": \"Seleziona fonte\",\n        \"enterName\": \"Inserisci nome\",\n        \"editName\": \"Modificaname\",\n        \"deleteGroup\": \"Elimina Gruppo\",\n        \"chooseGroup\": \"Seleziona un gruppo\",\n        \"addToGroup\": \"Aggiungi a ...\",\n        \"groupHint\": \"Doppio-Click sul gruppo per modificare le fonti. Clicca e trascina le fonti per ordinarle\"\n    },\n    \"rules\": {\n        \"intro\": \"automaticamentente seleziona articoli o manda notifiche tramite Regex\",\n        \"help\": \"Per saperne di più\",\n        \"source\": \"Fonte\",\n        \"selectSource\": \"Seleziona una fonte\",\n        \"new\": \"Nuova Regola\",\n        \"if\": \"Se\",\n        \"then\": \"Allora\",\n        \"title\": \"Titolo\",\n        \"content\": \"Contenuto\",\n        \"fullSearch\": \"Titolo o Contenuto\",\n        \"creator\": \"Autore\",\n        \"match\": \"Risultati\",\n        \"notMatch\": \"Non ci sono risultati\",\n        \"regex\": \"Espressione Regolare\",\n        \"badRegex\": \"Espressione Regolare Invalida\",\n        \"action\": \"Azioni\",\n        \"selectAction\": \"Seleziona azioni\",\n        \"hint\": \"Le regole verranno applicate sequenzialmente, Clicca e trascina per riordinare\",\n        \"test\": \"Prova le regole\"\n    },\n    \"service\": {\n        \"intro\": \"Sincronizza attraverso i dispositivi i servizi RSS\",\n        \"select\": \"Seleziona un servizio\",\n        \"suggest\": \"Suggerisci un nuovo servizio\",\n        \"overwriteWarning\": \"Le fonti locali verranno eliminate se sono gia presenti nel servizio \",\n        \"groupsWarning\": \"I gruppi non sono automaticamente sincronizzati con il servizio\",\n        \"rateLimitWarning\": \"Per evitare un limite nella frecquenza di aggiornamento dei avere una API key personalizzata\",\n        \"removeAd\": \"Rimuovi Annuncio\",\n        \"endpoint\": \"Indirizzo\",\n        \"username\": \"Username\",\n        \"password\": \"Password\",\n        \"unchanged\": \"Non modificato\",\n        \"fetchLimit\": \"Limite di Sincronizzazione\",\n        \"fetchLimitNum\": \"{count} articoli recenti\",\n        \"importGroups\": \"Importa gruppi\",\n        \"failure\": \"Impossibile connettersi al servizio\",\n        \"failureHint\": \"Controlla le impostazioni del servizio o se ci sono problemi di connessione\",\n        \"fetchUnlimited\": \"Illimitato (non Raccomandaot)\",\n        \"exportToLite\": \"Esporta a Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Pulisci\",\n        \"cache\": \"Elimina cache\",\n        \"cacheSize\": \"Dimensione Cache {size}\",\n        \"deleteChoices\": \"Rimuovi articoli di ... giorni fà\",\n        \"confirmDelete\": \"Rimuovi\",\n        \"daysAgo\": \"{days, plural, =1 {# giorno} other {# giorni}} fà\",\n        \"deleteAll\": \"Rimuovi tutti gli articoli\",\n        \"calculatingSize\": \"Calcolo dimensione...\",\n        \"itemSize\": \"Gli articoli occupano {size} \",\n        \"confirmImport\": \"Vuoi veramente importare i dati dal file di backup? I dati correnti verranno eliminati\",\n        \"data\": \"Memoria Applicazione\",\n        \"backup\": \"Backup\",\n        \"restore\": \"Ripristina\",\n        \"frData\": \"Fluent Reader Data\",\n        \"language\": \"Lingua Display\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Tema chiaro\",\n        \"darkTheme\": \"Tema scuro\",\n        \"enableProxy\": \"Abilita Proxy\",\n        \"badUrl\": \"URL Invalido\",\n        \"pac\": \"Indirizzo PAC\",\n        \"setPac\": \" Imposta PAC\",\n        \"pacHint\": \"Per proxies Socks, è raccomandato per i PAC di ritornare \\\"SOCKS5\\\" per proxy-side DNS. Disabilitare i proxy neccessita il riavvio dell'applicazione\",\n        \"fetchInterval\": \"Ricarica intervallo Automaticamente\",\n        \"never\": \"Mai\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/ja.json",
    "content": "{\n    \"allArticles\": \"全ての記事\",\n    \"add\": \"追加\",\n    \"create\": \"新規\",\n    \"icon\": \"アイコン\",\n    \"name\": \"名称\",\n    \"openExternal\": \"ブラウザで開く\",\n    \"emptyName\": \"名称を入力してください。\",\n    \"emptyField\": \"このフィールドは空にできません。\",\n    \"edit\": \"編集\",\n    \"delete\": \"削除\",\n    \"followSystem\": \"システム設定に従う\",\n    \"more\": \"さらに詳しく\",\n    \"close\": \"閉じる\",\n    \"search\": \"検索\",\n    \"loadMore\": \"もっと読み込む\",\n    \"dangerButton\": \"{action}を確認しますか？\",\n    \"confirmMarkAll\": \"全ての記事を開封済みにしますか？\",\n    \"confirm\": \"確認\",\n    \"cancel\": \"キャンセル\",\n    \"time\": {\n        \"now\": \"now\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m}分\",\n        \"hour\": \"{h}時間\",\n        \"day\": \"{d}日\"\n    },\n    \"log\": {\n        \"empty\": \"通知なし\",\n        \"fetchFailure\": \"フィード“{name}”の読み込みに失敗しました。\",\n        \"fetchSuccess\": \"{count} 件の記事をロードしました。\",\n        \"networkError\": \"フィードの接続にエラーが発生しました。\",\n        \"parseError\": \"XMLストリームの解析にエラーが発生しました。\",\n        \"syncFailure\": \"サービスの同期に失敗しました。\"\n    },\n    \"nav\": {\n        \"menu\": \"メニュー\",\n        \"refresh\": \"更新\",\n        \"markAllRead\": \"一括で開封済み\",\n        \"notifications\": \"通知\",\n        \"view\": \"ビュー\",\n        \"settings\": \"設定\",\n        \"minimize\": \"最小化\",\n        \"maximize\": \"最大化\"\n    },\n    \"menu\": {\n        \"close\": \"メニューを閉じる\",\n        \"subscriptions\": \"購読\"\n    },\n    \"article\": {\n        \"error\": \"記事の読み込みに失敗しました。\",\n        \"reload\": \"リロード\",\n        \"empty\": \"記事なし\",\n        \"untitled\": \"（無題）\",\n        \"hide\": \"記事を非表示\",\n        \"unhide\": \"記事を再表示\",\n        \"markRead\": \"開封済みにする\",\n        \"markUnread\": \"未開封にする\",\n        \"markAbove\": \"上記の記事を開封済みに\",\n        \"markBelow\": \"下記の記事を開封済みに\",\n        \"star\": \"星マーク\",\n        \"unstar\": \"星マークを外す\",\n        \"fontSize\": \"フォントサイズ\",\n        \"loadWebpage\": \"ウェブページを読み込む\",\n        \"loadFull\": \"全体を読み込む\",\n        \"notify\": \"バックグラウンドで取得された場合に通知する\",\n        \"dontNotify\": \"通知しない\"\n    },\n    \"context\": {\n        \"share\": \"共有\",\n        \"read\": \"読む\",\n        \"copyTitle\": \"タイトルをコピー\",\n        \"copyURL\": \"URLをコピー\",\n        \"copy\": \"コピー\",\n        \"search\": \"{engine} を使って“{text}”を検索する\",\n        \"view\": \"ビュー\",\n        \"cardView\": \"カードビュー\",\n        \"listView\": \"リストビュー\",\n        \"magazineView\": \"雑誌ビュー\",\n        \"compactView\": \"コンパクトビュー\",\n        \"filter\": \"フィルター\",\n        \"unreadOnly\": \"未開封のみ\",\n        \"starredOnly\": \"星付けのみ\",\n        \"fullSearch\": \"全文検索\",\n        \"showHidden\": \"非表示記事を表示\",\n        \"manageSources\": \"フィードを管理\",\n        \"saveImageAs\": \"イメージを保存\",\n        \"copyImage\": \"イメージをコピー\",\n        \"copyImageURL\": \"イメージリンクをコピー\",\n        \"caseSensitive\": \"大文字と小文字を区別\",\n        \"showCover\": \"表紙を表示\",\n        \"showSnippet\": \"スニペットを表示\",\n        \"fadeRead\": \"開封済みをフェード表示\"\n    },\n    \"searchEngine\": {\n        \"name\": \"検索エンジン\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"ファイルの書き込みにエラーが発生しました。\",\n        \"name\": \"オプション\",\n        \"fetching\": \"フィードを更新中、しばらくお待ちください…\",\n        \"exit\": \"終了\",\n        \"sources\": \"フィード\",\n        \"grouping\": \"グルーピング\",\n        \"rules\": \"ルール\",\n        \"service\": \"サービス\",\n        \"app\": \"環境設定\",\n        \"about\": \"本アプリについて\",\n        \"version\": \"バージョン\",\n        \"shortcuts\": \"ショートカット\",\n        \"openSource\": \"オープンソース\",\n        \"feedback\": \"フィードバック\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"ここでインポートか追加されるフィードはサーバ側と同期しません。\",\n        \"serviceManaged\": \"このフィードはサーバ側で管理されます。\",\n        \"untitled\": \"フィード\",\n        \"errorAdd\": \"フィードの追加にエラーが発生しました。\",\n        \"errorParse\": \"OPMLファイルの解析にエラーが発生しました。\",\n        \"errorParseHint\": \"OPMLファイルが破損しておらず、UTF-8 でエンコードされていることを確認してください。\",\n        \"errorImport\": \"{count}件のフィードのインポート中にエラーが発生しました。\",\n        \"exist\": \"このフィードは既に存在します。\",\n        \"opmlFile\": \"OPMLファイル\",\n        \"name\": \"フィード名\",\n        \"editName\": \"名称変更\",\n        \"fetchFrequency\": \"取得頻度制限\",\n        \"unlimited\": \"無制限\",\n        \"openTarget\": \"フィード記事を開く方法\",\n        \"delete\": \"フィードを削除\",\n        \"add\": \"フィードを追加\",\n        \"import\": \"インポート\",\n        \"export\": \"エクスポート\",\n        \"rssText\": \"RSSテキスト\",\n        \"loadWebpage\": \"ウェブページを読み込む\",\n        \"inputUrl\": \"URLを入力\",\n        \"badIcon\": \"無効なアイコン\",\n        \"badUrl\": \"無効なURL\",\n        \"deleteWarning\": \"フィード及び保管している記事を削除することになります。\",\n        \"selected\": \"選択されたフィード\",\n        \"selectedMulti\": \"選択されたフィード(複数)\"\n    },\n    \"groups\": {\n        \"exist\": \"このグループは既に存在します。\",\n        \"type\": \"区分\",\n        \"group\": \"グループ\",\n        \"source\": \"フィード\",\n        \"capacity\": \"容量\",\n        \"exitGroup\": \"グループ一覧に戻る\",\n        \"deleteSource\": \"グループからフィードを削除\",\n        \"sourceHint\": \"フィードをドラッグ アンド ドロップして並べ替えます。\",\n        \"create\": \"新規グループ\",\n        \"selectedGroup\": \"選択されたグループ\",\n        \"selectedSource\": \"選択されたフィード\",\n        \"enterName\": \"名称を入力ください\",\n        \"editName\": \"名称を編集ください\",\n        \"deleteGroup\": \"グループを削除\",\n        \"chooseGroup\": \"グループを選択\",\n        \"addToGroup\": \"グループに追加\",\n        \"groupHint\": \"グループをダブルクリックしてフィードを編集します。フィードをドラッグ アンド ドロップして並べ替えます。\"\n    },\n    \"rules\": {\n        \"intro\": \"正規表現で記事を自動的にマークするか、通知を送信します\",\n        \"help\": \"さらに詳しく\",\n        \"source\": \"フィード\",\n        \"selectSource\": \"フィードを選ぶ\",\n        \"new\": \"新規ルール\",\n        \"if\": \"もし\",\n        \"then\": \"なら\",\n        \"title\": \"タイトル\",\n        \"content\": \"コンテンツ\",\n        \"fullSearch\": \"タイトルかコンテンツ\",\n        \"creator\": \"著者\",\n        \"match\": \"一致する\",\n        \"notMatch\": \"一致しない\",\n        \"regex\": \"正規表現\",\n        \"badRegex\": \"無効な正規表現\",\n        \"action\": \"アクション\",\n        \"selectAction\": \"アクションを選択\",\n        \"hint\": \"ルールは順番に適用されます。ドラッグ アンド ドロップして並べ替えます。\",\n        \"test\": \"テスト用ルール\"\n    },\n    \"service\": {\n        \"intro\": \"RSSサービスを使用してディバイス間で同期します\",\n        \"select\": \"サービスを選択\",\n        \"suggest\": \"新たなサービスを推薦\",\n        \"overwriteWarning\": \"ローカルフィードがサーバ側に既存する場合に無視されます。\",\n        \"groupsWarning\": \"グループはサーバ側と自動的に同期されません。\",\n        \"rateLimitWarning\": \"レート制限を回避するには、独自のAPI キーを作成する必要があります。\",\n        \"removeAd\": \"広告を削除\",\n        \"endpoint\": \"エンドポイント\",\n        \"username\": \"ユーザー名\",\n        \"password\": \"パスワード\",\n        \"unchanged\": \"変更なし\",\n        \"fetchLimit\": \"同期数制限\",\n        \"fetchLimitNum\": \"{count} 件の最新記事\",\n        \"importGroups\": \"グループをエクスポート\",\n        \"failure\": \"サーバ接続中にエラーが発生しました。\",\n        \"failureHint\": \"サーバ設定とネットワーク接続を確認ください\",\n        \"fetchUnlimited\": \"無制限（非推奨）\",\n        \"exportToLite\": \"Fluent Reader Liteにエクスポート\"\n    },\n    \"app\": {\n        \"cleanup\": \"一括削除\",\n        \"cache\": \"キャッシュを削除\",\n        \"cacheSize\": \"{size}のデータをキャッシュしている\",\n        \"deleteChoices\": \"… 日前の記事を削除\",\n        \"confirmDelete\": \"記事を削除\",\n        \"daysAgo\": \"{days} 日前\",\n        \"deleteAll\": \"全ての記事を削除\",\n        \"calculatingSize\": \"占めるスペースを計算中…\",\n        \"itemSize\": \"ローカル記事は{size}のスペースを占める\",\n        \"confirmImport\": \"バックアップファイルからデータを導入しますか？全ての既存データを削除することになります。\",\n        \"data\": \"アプリデータ\",\n        \"backup\": \"バックアップ\",\n        \"restore\": \"リストア\",\n        \"frData\": \"Fluent Readerデータ\",\n        \"language\": \"表示言語\",\n        \"theme\": \"アプリテーマ\",\n        \"lightTheme\": \"明るいテーマ\",\n        \"darkTheme\": \"暗いテーマ\",\n        \"enableProxy\": \"プロキシを使う\",\n        \"badUrl\": \"正しいURLを入力ください\",\n        \"pac\": \"PACアドレス\",\n        \"setPac\": \"PACを設定\",\n        \"pacHint\": \"Sockプロキシの場合にPACが“SOCKS5”を返すことをお勧めします。プロキシを停止してから再起動する必要があります。\",\n        \"fetchInterval\": \"フェッチ間隔\",\n        \"never\": \"しない\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/ko.json",
    "content": "{\n    \"allArticles\": \"모든 글\",\n    \"add\": \"추가\",\n    \"create\": \"생성\",\n    \"icon\": \"아이콘\",\n    \"name\": \"이름\",\n    \"openExternal\": \"브라우저를 통해 열기\",\n    \"emptyName\": \"이 칸은 비어있을 수 없습니다.\",\n    \"emptyField\": \"이 칸은 비어있을 수 없습니다.\",\n    \"edit\": \"수정\",\n    \"delete\": \"삭제\",\n    \"followSystem\": \"시스템 설정에 따름\",\n    \"more\": \"더 보기\",\n    \"close\": \"닫기\",\n    \"search\": \"검색\",\n    \"loadMore\": \"더 불러오기\",\n    \"dangerButton\": \"{action}하시겠습니까?\",\n    \"confirmMarkAll\": \"이 페이지에 있는 모든 글을 읽은 것으로 처리하시겠습니까?\",\n    \"confirm\": \"확인\",\n    \"cancel\": \"취소\",\n    \"time\": {\n        \"now\": \"방금\",\n        \"m\": \"분 전\",\n        \"h\": \"시간 전\",\n        \"d\": \"일 전\",\n        \"minute\": \"{m}분\",\n        \"hour\": \"{h}시간\",\n        \"day\": \"{d}일\"\n    },\n    \"log\": {\n        \"empty\": \"알림 없음\",\n        \"fetchFailure\": \"피드 \\\"{name}\\\"의 글을 불러오는 데에 실패했습니다.\",\n        \"fetchSuccess\": \"{count}개의 글을 불러오는 데에 성공했습니다.\",\n        \"networkError\": \"네트워크 오류가 발생했습니다.\",\n        \"parseError\": \"XML 피드를 파싱하는 도중 오류가 발생했습니다.\",\n        \"syncFailure\": \"서비스와 동기화에 실패했습니다.\"\n    },\n    \"nav\": {\n        \"menu\": \"메뉴\",\n        \"refresh\": \"새로고침\",\n        \"markAllRead\": \"모두 읽은 것으로 처리\",\n        \"notifications\": \"알림\",\n        \"view\": \"보기\",\n        \"settings\": \"설정\",\n        \"minimize\": \"최소화\",\n        \"maximize\": \"최대화\"\n    },\n    \"menu\": {\n        \"close\": \"메뉴 닫기\",\n        \"subscriptions\": \"구독\"\n    },\n    \"article\": {\n        \"error\": \"글을 불러오지 못했습니다.\",\n        \"reload\": \"다시 불러오시겠습니까?\",\n        \"empty\": \"글 없음\",\n        \"untitled\": \"(제목 없음)\",\n        \"hide\": \"글 숨기기\",\n        \"unhide\": \"글 숨기기 취소\",\n        \"markRead\": \"읽은 것으로 표시\",\n        \"markUnread\": \"읽지 않은 것으로 표시\",\n        \"markAbove\": \"위에 있는 글을 모두 읽은 것으로 표시\",\n        \"markBelow\": \"아래에 있는 글을 모두 읽은 것으로 표시\",\n        \"star\": \"강조\",\n        \"unstar\": \"강조 제거\",\n        \"fontSize\": \"글꼴 크기\",\n        \"loadWebpage\": \"웹페이지 불러오기\",\n        \"loadFull\": \"모든 컨텐츠 불러오기\",\n        \"notify\": \"백그라운드 동작 중 글을 불러오면 알림\",\n        \"dontNotify\": \"알리지 않음\"\n    },\n    \"context\": {\n        \"share\": \"공유하기\",\n        \"read\": \"읽기\",\n        \"copyTitle\": \"제목 복사하기\",\n        \"copyURL\": \"주소 복사하기\",\n        \"copy\": \"복사\",\n        \"search\": \"{engine}에서 \\\"{text}\\\" 검색\",\n        \"view\": \"보기\",\n        \"cardView\": \"카드\",\n        \"listView\": \"리스트\",\n        \"magazineView\": \"매거진\",\n        \"compactView\": \"컴팩트\",\n        \"filter\": \"필터\",\n        \"unreadOnly\": \"읽지 않은 글만\",\n        \"starredOnly\": \"강조 표시한 글만\",\n        \"fullSearch\": \"본문에서도 검색\",\n        \"showHidden\": \"숨겨진 글 표시\",\n        \"manageSources\": \"피드 관리\",\n        \"saveImageAs\": \"이미지 저장하기\",\n        \"copyImage\": \"이미지 복사하기\",\n        \"copyImageURL\": \"이미지 주소 복사하기\",\n        \"caseSensitive\": \"대소문자 구분\",\n        \"showCover\": \"커버 이미지 표시\",\n        \"showSnippet\": \"스니펫 표시\",\n        \"fadeRead\": \"읽은 글을 희미하게 표시\"\n    },\n    \"searchEngine\": {\n        \"name\": \"검색 엔진\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"파일을 작성하는 도중 오류가 발생했습니다.\",\n        \"name\": \"설정\",\n        \"fetching\": \"소스를 업데이트하는 중입니다. 잠시만 기다려주세요…\",\n        \"exit\": \"종료\",\n        \"sources\": \"피드\",\n        \"grouping\": \"그룹\",\n        \"rules\": \"규칙\",\n        \"service\": \"서비스\",\n        \"app\": \"환경설정\",\n        \"about\": \"이 앱에 관하여\",\n        \"version\": \"버전\",\n        \"shortcuts\": \"단축키\",\n        \"openSource\": \"오픈 피드\",\n        \"feedback\": \"피드백 제출\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"여기서 불러오거나 추가한 피드는 연결한 서비스와 동기화되지 않습니다.\",\n        \"serviceManaged\": \"이 피드는 연결한 서비스에 의해 관리되고 있습니다.\",\n        \"untitled\": \"피드\",\n        \"errorAdd\": \"피드를 추가하는 도중 오류가 발생했습니다.\",\n        \"errorParse\": \"OPML 파일을 파싱할 수 없습니다.\",\n        \"errorParseHint\": \"파일이 손상되지 않았고 UTF-8로 인코딩 되었는지 확인해주세요.\",\n        \"errorImport\": \"{count}개의 피드를 불러오는 도중 오류가 발생했습니다.\",\n        \"exist\": \"이미 존재하는 피드입니다.\",\n        \"opmlFile\": \"OPML 파일\",\n        \"name\": \"피드 이름\",\n        \"editName\": \"이름 수정\",\n        \"fetchFrequency\": \"피드 새로고침에 걸리는 시간\",\n        \"unlimited\": \"무제한\",\n        \"openTarget\": \"글 불러오는 방법\",\n        \"delete\": \"피드 삭제\",\n        \"add\": \"피드 추가\",\n        \"import\": \"불러오기\",\n        \"export\": \"내보내기\",\n        \"rssText\": \"RSS 전문\",\n        \"loadWebpage\": \"웹페이지 불러고이\",\n        \"inputUrl\": \"URL 입력\",\n        \"badIcon\": \"유효하지 않은 아이콘\",\n        \"badUrl\": \"유효하지 않은 URL\",\n        \"deleteWarning\": \"피드와 저장된 글들이 모두 삭제됩니다.\",\n        \"selected\": \"선택된 피드\",\n        \"selectedMulti\": \"선택된 여러 개의 피드\"\n    },\n    \"groups\": {\n        \"exist\": \"이미 존재하는 그룹입니다.\",\n        \"type\": \"유형\",\n        \"group\": \"그룹\",\n        \"source\": \"피드\",\n        \"capacity\": \"용량\",\n        \"exitGroup\": \"그룹으로 돌아가기\",\n        \"deleteSource\": \"그룹에서 삭제\",\n        \"sourceHint\": \"피드를 끌어서 재정렬할 수 있습니다.\",\n        \"create\": \"그룹 생성\",\n        \"selectedGroup\": \"선택된 그룹\",\n        \"selectedSource\": \"선택된 피드\",\n        \"enterName\": \"이름 입력\",\n        \"editName\": \"이름 수정\",\n        \"deleteGroup\": \"그룹 삭제\",\n        \"chooseGroup\": \"그룹 선택\",\n        \"addToGroup\": \"그룹에 추가\",\n        \"groupHint\": \"피드를 수정하려면 그룹을 더블 클릭하세요. 끌어서 재정렬할 수 있습니다.\"\n    },\n    \"rules\": {\n        \"intro\": \"정규 표현식으로 글을 마크하거나 알림을 보냅니다.\",\n        \"help\": \"더 알아보기\",\n        \"source\": \"피드\",\n        \"selectSource\": \"피드 선택\",\n        \"new\": \"새로운 규칙\",\n        \"if\": \"만약\",\n        \"then\": \"이라면\",\n        \"title\": \"제목\",\n        \"content\": \"내용\",\n        \"fullSearch\": \"제목 또는 내용\",\n        \"creator\": \"작성자\",\n        \"match\": \"일치\",\n        \"notMatch\": \"일치하지 않음\",\n        \"regex\": \"정규 표현식\",\n        \"badRegex\": \"유효하지 않은 정규 표현식입니다.\",\n        \"action\": \"행동\",\n        \"selectAction\": \"행동 선택\",\n        \"hint\": \"규칙은 순서대로 적용됩니다. 끌어서 재정렬할 수 있습니다.\",\n        \"test\": \"규칙 테스트\"\n    },\n    \"service\": {\n        \"intro\": \"RSS 서비스를 이용하여 기기간 동기화합니다.\",\n        \"select\": \"서비스 선택\",\n        \"suggest\": \"새로운 서비스 제안\",\n        \"overwriteWarning\": \"서비스에 포함된 이미 존재하는 로컬 피드는 삭제됩니다.\",\n        \"groupsWarning\": \"그룹들은 서비스를 통해 동기화할 수 없습니다.\",\n        \"rateLimitWarning\": \"제한을 피하려면 자신만의 API 키를 만들어야 합니다.\",\n        \"removeAd\": \"광고 제거\",\n        \"endpoint\": \"종단\",\n        \"username\": \"사용자 이름\",\n        \"password\": \"비밀번호\",\n        \"unchanged\": \"변경점 없음\",\n        \"fetchLimit\": \"동기화 제한\",\n        \"fetchLimitNum\": \"최근 {count}개의 글\",\n        \"importGroups\": \"그룹 불러오기\",\n        \"failure\": \"서비스에 연결할 수 없음\",\n        \"failureHint\": \"서비스 설정이나 네트워크 상태를 확인해보세요.\",\n        \"fetchUnlimited\": \"제한 없음 (추천하지 않음)\",\n        \"exportToLite\": \"Fluent Reader Lite에 내보내기\"\n    },\n    \"app\": {\n        \"cleanup\": \"일괄 삭제\",\n        \"cache\": \"캐시 지우기\",\n        \"cacheSize\": \"{size}의 캐시가 저장되어 있습니다.\",\n        \"deleteChoices\": \"... 일 전에 작성된 글을 삭제\",\n        \"confirmDelete\": \"삭제\",\n        \"daysAgo\": \"{days}일 전\",\n        \"deleteAll\": \"모든 글을 삭제\",\n        \"calculatingSize\": \"크기를 계산하는 중입니다...\",\n        \"itemSize\": \"대략 {size}의 로컬 저장소가 불러온 글에 의해 점유되고 있습니다.\",\n        \"confirmImport\": \"백업 파일을 통해서 데이터를 불러오시겠습니까? 현재 저장된 데이터가 대체됩니다.\",\n        \"data\": \"앱 데이터\",\n        \"backup\": \"백업\",\n        \"restore\": \"복원\",\n        \"frData\": \"Fluent Reader 데이터\",\n        \"language\": \"언어\",\n        \"theme\": \"테마\",\n        \"lightTheme\": \"라이트 모드\",\n        \"darkTheme\": \"다크 모드\",\n        \"enableProxy\": \"프록시 활성화\",\n        \"badUrl\": \"유효하지 않은 URL\",\n        \"pac\": \"PAC 주소\",\n        \"setPac\": \"PAC 설정\",\n        \"pacHint\": \"Socks 프록시의 경우에는 PAC이 프록시측 DNS에 \\\"SOCKS5\\\"를 리턴하는 것을 권장합니다.. 재시작하려면 프록시를 종료해야 합니다.\",\n        \"fetchInterval\": \"피드를 불러오는 간격\",\n        \"never\": \"하지 않음\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/nl.json",
    "content": "{\n    \"allArticles\": \"Alle artikelen\",\n    \"add\": \"Toevoegen\",\n    \"create\": \"Maken\",\n    \"icon\": \"Pictogram\",\n    \"name\": \"Naam\",\n    \"openExternal\": \"Openen in webbrowser\",\n    \"emptyName\": \"Dit veld mag niet blanco zijn.\",\n    \"emptyField\": \"Dit veld mag niet blanco zijn.\",\n    \"edit\": \"Bewerken\",\n    \"delete\": \"Verwijderen\",\n    \"followSystem\": \"Systeeminstellingen gebruiken\",\n    \"more\": \"Meer\",\n    \"close\": \"Sluiten\",\n    \"search\": \"Zoeken\",\n    \"loadMore\": \"Meer laden\",\n    \"dangerButton\": \"{action} bevestigen\",\n    \"confirmMarkAll\": \"Weet je zeker dat je alle artikelen op deze pagina als gelezen wilt markeren?\",\n    \"confirm\": \"Ja\",\n    \"cancel\": \"Annuleren\",\n    \"time\": {\n        \"now\": \"nu\",\n        \"m\": \"m\",\n        \"h\": \"u\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minuut} other {# minuten}}\",\n        \"hour\": \"{h, plural, =1 {# uur} other {# uur}}\",\n        \"day\": \"{d, plural, =1 {# dag} other {# dagen}}\"\n    },\n    \"log\": {\n        \"empty\": \"Geen meldingen\",\n        \"fetchFailure\": \"De bron, {name}, kan niet worden geladen.\",\n        \"fetchSuccess\": \"Artikelen opgehaald: {count, plural, =1 {# article} other {# articles}}.\",\n        \"networkError\": \"Er is een netwerkfout opgetreden.\",\n        \"parseError\": \"Er is een fout opgetreden tijdens het verwerken van de xml-feed.\",\n        \"syncFailure\": \"Het synchroniseren met de dienst is mislukt\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Verversen\",\n        \"markAllRead\": \"Alles markeren als gelezen\",\n        \"notifications\": \"Meldingen\",\n        \"view\": \"Weergave\",\n        \"settings\": \"Instellingen\",\n        \"minimize\": \"Minimaliseren\",\n        \"maximize\": \"Maximaliseren\"\n    },\n    \"menu\": {\n        \"close\": \"Menu sluiten\",\n        \"subscriptions\": \"Abonnementen\"\n    },\n    \"article\": {\n        \"error\": \"Het artikel kan niet worden geladen.\",\n        \"reload\": \"Herladen?\",\n        \"empty\": \"Geen artikelen\",\n        \"untitled\": \"(naamloos)\",\n        \"hide\": \"Artikel verbergen\",\n        \"unhide\": \"Artikel tonen\",\n        \"markRead\": \"Markeren als gelezen\",\n        \"markUnread\": \"Markeren als ongelezen\",\n        \"markAbove\": \"Artikelen hierboven markeren als gelezen\",\n        \"markBelow\": \"Artikelen hieronder markeren als gelezen\",\n        \"star\": \"Toevoegen aan favorieten\",\n        \"unstar\": \"Verwijderen uit favorieten\",\n        \"fontSize\": \"Tekstgrootte\",\n        \"loadWebpage\": \"Webpagina laden\",\n        \"loadFull\": \"Volledige inhoud laden\",\n        \"notify\": \"Melding tonen na ophalen op achtergrond\",\n        \"dontNotify\": \"Geen melding tonen\"\n    },\n    \"context\": {\n        \"share\": \"Delen\",\n        \"read\": \"Gelezen\",\n        \"copyTitle\": \"Titel kopiëren\",\n        \"copyURL\": \"Link kopiëren\",\n        \"copy\": \"Kopiëren\",\n        \"search\": \"Naar ‘{text}’ zoeken op {engine}\",\n        \"view\": \"Weergave\",\n        \"cardView\": \"Kaartweergave\",\n        \"listView\": \"Lijstweergave\",\n        \"magazineView\": \"Tijdschriftweergave\",\n        \"compactView\": \"Compacte weergave\",\n        \"filter\": \"Filteren\",\n        \"unreadOnly\": \"Alleen ongelezen\",\n        \"starredOnly\": \"Alleen favorieten\",\n        \"fullSearch\": \"Volledige tekst doorzoeken\",\n        \"showHidden\": \"Verborgen artikelen tonen\",\n        \"manageSources\": \"Bronnen beheren\",\n        \"saveImageAs\": \"Afbeelding opslaan als…\",\n        \"copyImage\": \"Afbeelding kopiëren\",\n        \"copyImageURL\": \"Afbeeldingsadres kopiëren\",\n        \"caseSensitive\": \"Hoofdlettergevoelig\",\n        \"showCover\": \"Omslag tonen\",\n        \"showSnippet\": \"Knipsel tonen\",\n        \"fadeRead\": \"Gelezen artikelen dimmen\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Zoekmachine\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Er is een fout opgetreden tijdens het wegschrijven van het bestand.\",\n        \"name\": \"Instellingen\",\n        \"fetching\": \"Bezig met bijwerken van bronnen…\",\n        \"exit\": \"Instellingen afsluiten\",\n        \"sources\": \"Bronnen\",\n        \"grouping\": \"Groepen\",\n        \"rules\": \"Regels\",\n        \"service\": \"Dienst\",\n        \"app\": \"Instellingen\",\n        \"about\": \"Over\",\n        \"version\": \"Versie\",\n        \"shortcuts\": \"Sneltoetsen\",\n        \"openSource\": \"Open source\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Hier toegevoegde of geïmporteerde bronnen worden niet gesynchroniseerd met je dienst.\",\n        \"serviceManaged\": \"Deze bron wordt beheerd door je dienst.\",\n        \"untitled\": \"Bron\",\n        \"errorAdd\": \"Er is een fout opgetreden tijdens het toevoegen.\",\n        \"errorParse\": \"Er is een fout opgetreden tijdens het verwerken van het opml-bestand.\",\n        \"errorParseHint\": \"Controleer of het bestand niet beschadigd is en opgemaakt is met utf-8.\",\n        \"errorImport\": \"Importeren mislukt: {count, plural, =1 {# source} other {# sources}}.\",\n        \"exist\": \"Deze bron is al toegevoegd.\",\n        \"opmlFile\": \"OPML-bestand\",\n        \"name\": \"Bronnaam\",\n        \"editName\": \"Naam bewerken\",\n        \"fetchFrequency\": \"Ophaalfrequentie aanpassen\",\n        \"unlimited\": \"Onbeperkt\",\n        \"openTarget\": \"Standaarddoel bij artikelen\",\n        \"delete\": \"Bron verwijderen\",\n        \"add\": \"Bron toevoegen\",\n        \"import\": \"Importeren\",\n        \"export\": \"Exporteren\",\n        \"rssText\": \"RSS met volledige tekst\",\n        \"loadWebpage\": \"Webpagina laden\",\n        \"inputUrl\": \"Voer een url in\",\n        \"badIcon\": \"Ongeldig pictogram\",\n        \"badUrl\": \"Ongeldige url\",\n        \"deleteWarning\": \"De bron en alle opgeslagen artikelen worden verwijderd.\",\n        \"selected\": \"Gekozen bron\",\n        \"selectedMulti\": \"Meerdere bronnen gekozen\"\n    },\n    \"groups\": {\n        \"exist\": \"Deze groep bestaat al.\",\n        \"type\": \"Soort\",\n        \"group\": \"Groep\",\n        \"source\": \"Bron\",\n        \"capacity\": \"Capaciteit\",\n        \"exitGroup\": \"Terug naar groepen\",\n        \"deleteSource\": \"Verwijderen uit groep\",\n        \"sourceHint\": \"Versleep bronnen om ze anders te rangschikken.\",\n        \"create\": \"Groep aanmaken\",\n        \"selectedGroup\": \"Gekozen groep\",\n        \"selectedSource\": \"Gekozen bron\",\n        \"enterName\": \"Voer een naam in\",\n        \"editName\": \"Naam aanpassen\",\n        \"deleteGroup\": \"Groep verwijderen\",\n        \"chooseGroup\": \"Kies een groep\",\n        \"addToGroup\": \"Toevoegen aan…\",\n        \"groupHint\": \"Dubbelklik op een groep om de bronnen ervan aan te passen - versleep om anders te rangschikken.\"\n    },\n    \"rules\": {\n        \"intro\": \"Markeer artikelen automatisch of verstuur meldingen met reguliere uitdrukkingen.\",\n        \"help\": \"Meer informatie\",\n        \"source\": \"Bron\",\n        \"selectSource\": \"Kies een bron\",\n        \"new\": \"Nieuwe regel\",\n        \"if\": \"Als\",\n        \"then\": \"Dan\",\n        \"title\": \"Titel\",\n        \"content\": \"Inhoud\",\n        \"fullSearch\": \"Titel of inhoud\",\n        \"creator\": \"Auteur\",\n        \"match\": \"overeenkomsten\",\n        \"notMatch\": \"komt niet overeen\",\n        \"regex\": \"Reguliere uitdrukking\",\n        \"badRegex\": \"Ongeldige reguliere uitdrukking.\",\n        \"action\": \"Acties\",\n        \"selectAction\": \"Kies acties\",\n        \"hint\": \"Regels worden op volgorde toegepast. Versleep om anders te rangschikken.\",\n        \"test\": \"Regels testen\"\n    },\n    \"service\": {\n        \"intro\": \"Synchroniseer tussen apparaten middels rss-diensten.\",\n        \"select\": \"Kies een dienst\",\n        \"suggest\": \"Nieuwe dienst aandragen\",\n        \"overwriteWarning\": \"Lokale bronnen worden verwijderd als de dienst ze al kent.\",\n        \"groupsWarning\": \"Groepen worden niet automatisch gesynchroniseerd met de dienst.\",\n        \"rateLimitWarning\": \"Geef je eigen api-sleutel op om beperkingen te voorkomen.\",\n        \"removeAd\": \"Reclame verwijderen\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Gebruikersnaam\",\n        \"password\": \"Wachtwoord\",\n        \"unchanged\": \"Ongewijzigd\",\n        \"fetchLimit\": \"Synchronisatielimiet\",\n        \"fetchLimitNum\": \"{count} recentste artikelen\",\n        \"importGroups\": \"Groepen importeren\",\n        \"failure\": \"Er kan geen verbinding worden gemaakt met de dienst\",\n        \"failureHint\": \"Controleer de dienstinstellingen of netwerkstatus.\",\n        \"fetchUnlimited\": \"Onbeperkt (niet aanbevolen)\",\n        \"exportToLite\": \"Exporteren naar Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Opruimen\",\n        \"cache\": \"Cache legen\",\n        \"cacheSize\": \"In cache: {size} aan gegevens\",\n        \"deleteChoices\": \"Artikelen verwijderen die ouder zijn dan … dagen\",\n        \"confirmDelete\": \"Verwijderen\",\n        \"daysAgo\": \"{days, plural, =1 {# dag} other {# dagen}} geleden\",\n        \"deleteAll\": \"Alle artikelen verwijderen\",\n        \"calculatingSize\": \"Bezig met grootteberekening…\",\n        \"itemSize\": \"De artikelen nemen ongeveer {size} aan lokale opslag in beslag\",\n        \"confirmImport\": \"Weet je zeker dat je artikelen wilt importeren uit een back-upbestand? Alle huidige gegevens worden verwijderd.\",\n        \"data\": \"Programmagegevens\",\n        \"backup\": \"Back-uppen\",\n        \"restore\": \"Herstellen\",\n        \"frData\": \"Fluent Reader-gegevens\",\n        \"language\": \"Weergavetaal\",\n        \"theme\": \"Thema\",\n        \"lightTheme\": \"Licht\",\n        \"darkTheme\": \"Donker\",\n        \"enableProxy\": \"Proxy gebruiken\",\n        \"badUrl\": \"Ongeldige url\",\n        \"pac\": \"PAC-adres\",\n        \"setPac\": \"PAC instellen\",\n        \"pacHint\": \"Bij Socks-proxies is het aanbevolen om PAC ‘SOCKS5’ te laten ophalen aan de dns-kant. Herstart om de proxy uit te schakelen.\",\n        \"fetchInterval\": \"Automatisch ophalen\",\n        \"never\": \"Nooit\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/pt-BR.json",
    "content": "{\n    \"allArticles\": \"Todos os artigos\",\n    \"add\": \"Adicionar\",\n    \"create\": \"Criar\",\n    \"icon\": \"Ícone\",\n    \"name\": \"Nome\",\n    \"openExternal\": \"Abrir externamente\",\n    \"emptyName\": \"Este campo não pode ficar vazio.\",\n    \"emptyField\": \"Este campo não pode ficar vazio.\",\n    \"edit\": \"Editar\",\n    \"delete\": \"Deletar\",\n    \"followSystem\": \"Seguir o sistema\",\n    \"more\": \"Mais\",\n    \"close\": \"Fechar\",\n    \"search\": \"Pesquisar\",\n    \"loadMore\": \"Carregar mais\",\n    \"dangerButton\": \"Confirmar {action}?\",\n    \"confirmMarkAll\": \"Você realmente deseja marcar todos os artigos dessa página como lidos?\",\n    \"confirm\": \"Confirmar\",\n    \"cancel\": \"Cancelar\",\n    \"time\": {\n        \"now\": \"agora\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minuto} other {# minutos}}\",\n        \"hour\": \"{h, plural, =1 {# hora} other {# horas}}\",\n        \"day\": \"{d, plural, =1 {# dia} other {# dias}}\"\n    },\n    \"log\": {\n        \"empty\": \"Nenhuma notificação\",\n        \"fetchFailure\": \"Falha ao carregar a fonte \\\"{name}\\\".\",\n        \"fetchSuccess\": \"{count, plural, =1 {# Artigo} other {# Artigos}} foram atualizados com sucesso.\",\n        \"networkError\": \"Ocorreu um erro na rede.\",\n        \"parseError\": \"Ocorreu um erro ao analisar o feed XML.\",\n        \"syncFailure\": \"Falha ao sincronizar com o serviço\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Atualizar\",\n        \"markAllRead\": \"Marcar todos como lidos\",\n        \"notifications\": \"Notificações\",\n        \"view\": \"Visualização\",\n        \"settings\": \"Configurações\",\n        \"minimize\": \"Minimizar\",\n        \"maximize\": \"Maximizar\"\n    },\n    \"menu\": {\n        \"close\": \"Fechar menu\",\n        \"subscriptions\": \"Inscrições\"\n    },\n    \"article\": {\n        \"error\": \"Falha ao carregar o artigo.\",\n        \"reload\": \"Recarregar?\",\n        \"empty\": \"Nenhum artigo\",\n        \"untitled\": \"(Sem título)\",\n        \"hide\": \"Ocultar artigo\",\n        \"unhide\": \"Exibir artigo\",\n        \"markRead\": \"Marcar como lido\",\n        \"markUnread\": \"Marcar como não lido\",\n        \"markAbove\": \"Marcar artigo(s) abaixo como lido(s)\",\n        \"markBelow\": \"Marcar artigo(s) abaixo como não lido(s)\",\n        \"star\": \"Marcar como favorito\",\n        \"unstar\": \"Remover marcação\",\n        \"fontSize\": \"Tamanho da fonte\",\n        \"loadWebpage\": \"Carregar página web\",\n        \"loadFull\": \"Carregar todo o conteúdo\",\n        \"notify\": \"Notificar se atualizado em segundo plano\",\n        \"dontNotify\": \"Não notificar\"\n    },\n    \"context\": {\n        \"share\": \"Compartilhar\",\n        \"read\": \"Ler\",\n        \"copyTitle\": \"Copiar título\",\n        \"copyURL\": \"Copiar link\",\n        \"copy\": \"Copiar\",\n        \"search\": \"Pesquisar \\\"{text}\\\" no {engine}\",\n        \"view\": \"Visualização\",\n        \"cardView\": \"Como cartões\",\n        \"listView\": \"Em lista\",\n        \"magazineView\": \"Como revista\",\n        \"compactView\": \"Compacto\",\n        \"filter\": \"Filtrar\",\n        \"unreadOnly\": \"Somente não lidos\",\n        \"starredOnly\": \"Somente favoritos\",\n        \"fullSearch\": \"Pesquisar em todo o texto\",\n        \"showHidden\": \"Exibir artigos ocultos\",\n        \"manageSources\": \"Gerenciar fontes\",\n        \"saveImageAs\": \"Salvar imagem como …\",\n        \"copyImage\": \"Copiar imagem\",\n        \"copyImageURL\": \"Copiar link da imagem\",\n        \"caseSensitive\": \"Diferenciar maiúsculas e minúsculas\",\n        \"showCover\": \"Exibir capa\",\n        \"showSnippet\": \"Mostrar trecho\",\n        \"fadeRead\": \"Esmaecer artigos lidos\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Motor de pesquisa\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Ocorreu um erro ao gravar o arquivo.\",\n        \"name\": \"Configurações\",\n        \"fetching\": \"Atualizando fontes, por favor aguarde …\",\n        \"exit\": \"Sair das Configurações\",\n        \"sources\": \"Fontes\",\n        \"grouping\": \"Grupos\",\n        \"rules\": \"Regras\",\n        \"service\": \"Serviço\",\n        \"app\": \"Preferências\",\n        \"about\": \"Sobre\",\n        \"version\": \"Versão\",\n        \"shortcuts\": \"Atalhos\",\n        \"openSource\": \"Código aberto\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Fontes importadas ou adicionadas aqui não serão sincronizadas com o seu serviço.\",\n        \"serviceManaged\": \"Essa fonte é gerenciada pelo seu serviço.\",\n        \"untitled\": \"Fonte\",\n        \"errorAdd\": \"Ocorreu um erro ao adicionar a fonte.\",\n        \"errorParse\": \"Ocorreu um erro ao analisar o arquivo OPML.\",\n        \"errorParseHint\": \"Certifique-se de que o arquivo não esteja corrompido e que esteja codificado com UTF-8.\",\n        \"errorImport\": \"Erro ao importar {count, plural, =1 {# fonte} other {# fontes}}.\",\n        \"exist\": \"Esta fonte já existe.\",\n        \"opmlFile\": \"Arquivo OPML\",\n        \"name\": \"Nome da fonte\",\n        \"editName\": \"Editar nome\",\n        \"fetchFrequency\": \"Limite da frequência de atualização\",\n        \"unlimited\": \"Ilimitado\",\n        \"openTarget\": \"Método padrão de carregamento dos artigos\",\n        \"delete\": \"Deletar fonte\",\n        \"add\": \"Adicionar fonte\",\n        \"import\": \"Importar\",\n        \"export\": \"Exportar\",\n        \"rssText\": \"Texto completo do RSS\",\n        \"loadWebpage\": \"Carregar página web\",\n        \"inputUrl\": \"Insira a URL\",\n        \"badIcon\": \"Ícone inválido\",\n        \"badUrl\": \"URL inválida\",\n        \"deleteWarning\": \"A fonte e todos os artigos salvos serão removidos.\",\n        \"selected\": \"Fonte selecionada\",\n        \"selectedMulti\": \"Múltiplas fontes selecionadas\"\n    },\n    \"groups\": {\n        \"exist\": \"Este grupo já existe.\",\n        \"type\": \"Tipo\",\n        \"group\": \"Grupo\",\n        \"source\": \"Fonte\",\n        \"capacity\": \"Capacidade\",\n        \"exitGroup\": \"Voltar para os grupos\",\n        \"deleteSource\": \"Deletar deste grupo\",\n        \"sourceHint\": \"Arraste e solte as fontes para reorganizá-las.\",\n        \"create\": \"Criar grupo\",\n        \"selectedGroup\": \"Grupo selecionado\",\n        \"selectedSource\": \"Fonte selecionada\",\n        \"enterName\": \"Insira o nome\",\n        \"editName\": \"Editar o nome\",\n        \"deleteGroup\": \"Deletar grupo\",\n        \"chooseGroup\": \"Selecione um grupo\",\n        \"addToGroup\": \"Adicionar para ...\",\n        \"groupHint\": \"Clique duplo nos grupos para editar as fontes; Arraste e solte para reorganizá-los.\"\n    },\n    \"rules\": {\n        \"intro\": \"Marcar artigos automaticamente ou enviar notificações com base em regras de expressões regulares.\",\n        \"help\": \"Saiba mais\",\n        \"source\": \"Fonte\",\n        \"selectSource\": \"Selecionar uma fonte\",\n        \"new\": \"Nova regra\",\n        \"if\": \"Se\",\n        \"then\": \"Então\",\n        \"title\": \"Título\",\n        \"content\": \"Conteúdo\",\n        \"fullSearch\": \"Título ou conteúdo\",\n        \"creator\": \"Autor\",\n        \"match\": \"corresponde\",\n        \"notMatch\": \"não corresponde\",\n        \"regex\": \"Expressão regular\",\n        \"badRegex\": \"Expressão regular inválida.\",\n        \"action\": \"Ações\",\n        \"selectAction\": \"Selecionar ações\",\n        \"hint\": \"As regras serão aplicadas em ordem. Arraste e solte para reorganizar.\",\n        \"test\": \"Testar regras\"\n    },\n    \"service\": {\n        \"intro\": \"Sincronização entre dispositivos com serviços RSS.\",\n        \"select\": \"Selecione um serviço\",\n        \"suggest\": \"Sugerir um novo serviço\",\n        \"overwriteWarning\": \"Fontes locais serão deletas se elas existirem no serviço.\",\n        \"groupsWarning\": \"Grupos não são automaticamente sincronizados com o serviço.\",\n        \"rateLimitWarning\": \"Para evitar limitações do serviço, você precisa criar sua própria chave de API.\",\n        \"removeAd\": \"Remover Ad\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Usuário\",\n        \"password\": \"Senha\",\n        \"unchanged\": \"Inalterado\",\n        \"fetchLimit\": \"Limite de sincronização\",\n        \"fetchLimitNum\": \"{count} últimos artigos\",\n        \"importGroups\": \"Importar grupos\",\n        \"failure\": \"Não foi possível conectar ao serviço\",\n        \"failureHint\": \"Por favor verifique a configuração do serviço ou o status da rede.\",\n        \"fetchUnlimited\": \"Ilimitado (não recomendado)\",\n        \"exportToLite\": \"Exportar para o Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Limpeza\",\n        \"cache\": \"Limpar cache\",\n        \"cacheSize\": \"{size} de dados em cache\",\n        \"deleteChoices\": \"Deletar artigos de ... dias atrás\",\n        \"confirmDelete\": \"Deletar\",\n        \"daysAgo\": \"{days, plural, =1 {# dia} other {# dias}} atrás\",\n        \"deleteAll\": \"Deletar todos os artigos\",\n        \"calculatingSize\": \"Calculando tamanho...\",\n        \"itemSize\": \"Cerca de {size} do armazenamento local é ocupado por artigos\",\n        \"confirmImport\": \"Você realmente deseja importar os dados do arquivo de backup? Todos os dados atuais serão apagados.\",\n        \"data\": \"Dados da aplicação\",\n        \"backup\": \"Backup\",\n        \"restore\": \"Restaurar\",\n        \"frData\": \"Dados do Fluent Reader\",\n        \"language\": \"Idioma\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Modo claro\",\n        \"darkTheme\": \"Modo escuro\",\n        \"enableProxy\": \"Ativar proxy\",\n        \"badUrl\": \"URL inválida\",\n        \"pac\": \"Endereço PAC\",\n        \"setPac\": \"Definir PAC\",\n        \"pacHint\": \"For Socks proxies, it is recommended for PAC to return \\\"SOCKS5\\\" for proxy-side DNS. Turning off proxy requires restart.\",\n        \"fetchInterval\": \"Intervalo de atualização automática\",\n        \"never\": \"Nunca\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/pt-PT.json",
    "content": "{\n    \"allArticles\": \"Todos os artigos\",\n    \"add\": \"Adicionar\",\n    \"create\": \"Criar\",\n    \"icon\": \"Ícone\",\n    \"name\": \"Nome\",\n    \"openExternal\": \"Abrir externamente\",\n    \"emptyName\": \"Este campo não pode ficar vazio.\",\n    \"emptyField\": \"Este campo não pode ficar vazio.\",\n    \"edit\": \"Editar\",\n    \"delete\": \"Eliminar\",\n    \"followSystem\": \"Seguir o sistema\",\n    \"more\": \"Mais\",\n    \"close\": \"Fechar\",\n    \"search\": \"Pesquisar\",\n    \"loadMore\": \"Carregar mais\",\n    \"dangerButton\": \"Confirmar {action}?\",\n    \"confirmMarkAll\": \"Deseja mesmo marcar todos os artigos desta página como lidos?\",\n    \"confirm\": \"Confirmar\",\n    \"cancel\": \"Cancelar\",\n    \"default\": \"Padrão\",\n    \"time\": {\n        \"now\": \"agora\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minuto} other {# minutos}}\",\n        \"hour\": \"{h, plural, =1 {# hora} other {# horas}}\",\n        \"day\": \"{d, plural, =1 {# dia} other {# dias}}\"\n    },\n    \"log\": {\n        \"empty\": \"Nenhuma notificação\",\n        \"fetchFailure\": \"Falha ao carregar a fonte \\\"{name}\\\".\",\n        \"fetchSuccess\": \"{count, plural, =1 {# Artigo} other {# Artigos}} foram atualizados com sucesso.\",\n        \"networkError\": \"Ocorreu um erro na rede.\",\n        \"parseError\": \"Ocorreu um erro ao analisar o feed XML.\",\n        \"syncFailure\": \"Falha ao sincronizar com o serviço\"\n    },\n    \"nav\": {\n        \"menu\": \"Menu\",\n        \"refresh\": \"Atualizar\",\n        \"markAllRead\": \"Marcar todos como lidos\",\n        \"notifications\": \"Notificações\",\n        \"view\": \"Visualização\",\n        \"settings\": \"Definições\",\n        \"minimize\": \"Minimizar\",\n        \"maximize\": \"Maximizar\"\n    },\n    \"menu\": {\n        \"close\": \"Fechar menu\",\n        \"subscriptions\": \"Subscrições\"\n    },\n    \"article\": {\n        \"error\": \"Falha ao carregar o artigo.\",\n        \"reload\": \"Recarregar?\",\n        \"empty\": \"Nenhum artigo\",\n        \"untitled\": \"(Sem título)\",\n        \"hide\": \"Ocultar artigo\",\n        \"unhide\": \"Exibir artigo\",\n        \"markRead\": \"Marcar como lido\",\n        \"markUnread\": \"Marcar como não lido\",\n        \"markAbove\": \"Marcar artigo(s) acima como lido(s)\",\n        \"markBelow\": \"Marcar artigo(s) abaixo como não lido(s)\",\n        \"star\": \"Marcar como favorito\",\n        \"unstar\": \"Remover marcação\",\n        \"fontSize\": \"Tamanho da fonte\",\n        \"loadWebpage\": \"Carregar página web\",\n        \"loadFull\": \"Carregar todo o conteúdo\",\n        \"notify\": \"Notificar se atualizado em segundo plano\",\n        \"dontNotify\": \"Não notificar\",\n        \"textDir\": \"Direção do texto\",\n        \"LTR\": \"Esquerda-para-direita\",\n        \"RTL\": \"Direita-para-esquerda\",\n        \"Vertical\": \"Vertical\",\n        \"font\": \"Fonte\"\n    },\n    \"context\": {\n        \"share\": \"Partilhar\",\n        \"read\": \"Ler\",\n        \"copyTitle\": \"Copiar título\",\n        \"copyURL\": \"Copiar link\",\n        \"copy\": \"Copiar\",\n        \"search\": \"Pesquisar \\\"{text}\\\" no {engine}\",\n        \"view\": \"Visualizar\",\n        \"cardView\": \"Como cartões\",\n        \"listView\": \"Em lista\",\n        \"magazineView\": \"Como revista\",\n        \"compactView\": \"Compacto\",\n        \"filter\": \"Filtrar\",\n        \"unreadOnly\": \"Apenas não lidos\",\n        \"starredOnly\": \"Apenas favoritos\",\n        \"fullSearch\": \"Pesquisar em todo o texto\",\n        \"showHidden\": \"Exibir artigos ocultos\",\n        \"manageSources\": \"Gerir fontes\",\n        \"saveImageAs\": \"Guardar imagem como …\",\n        \"copyImage\": \"Copiar imagem\",\n        \"copyImageURL\": \"Copiar link da imagem\",\n        \"caseSensitive\": \"Diferenciar maiúsculas e minúsculas\",\n        \"showCover\": \"Mostrar capa\",\n        \"showSnippet\": \"Mostrar trecho\",\n        \"fadeRead\": \"Desaparecer artigos lidos\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Motor de pesquisa\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Ocorreu um erro ao gravar o ficheiro.\",\n        \"name\": \"Definições\",\n        \"fetching\": \"Atualizando fontes, aguarde por favor …\",\n        \"exit\": \"Sair das definições\",\n        \"sources\": \"Fontes\",\n        \"grouping\": \"Grupos\",\n        \"rules\": \"Regras\",\n        \"service\": \"Serviço\",\n        \"app\": \"Preferências\",\n        \"about\": \"Sobre\",\n        \"version\": \"Versão\",\n        \"shortcuts\": \"Atalhos\",\n        \"openSource\": \"Código aberto\",\n        \"feedback\": \"Feedback\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Fontes importadas ou adicionadas aqui não serão sincronizadas com o seu serviço.\",\n        \"serviceManaged\": \"Esta fonte é gerenciada pelo seu serviço.\",\n        \"untitled\": \"Fonte\",\n        \"errorAdd\": \"Ocorreu um erro ao adicionar a fonte.\",\n        \"errorParse\": \"Ocorreu um erro ao analisar o arquivo OPML.\",\n        \"errorParseHint\": \"Certifique-se de que o arquivo não esteja corrompido e que esteja codificado com UTF-8.\",\n        \"errorImport\": \"Erro ao importar {count, plural, =1 {# fonte} other {# fontes}}.\",\n        \"exist\": \"Esta fonte já existe.\",\n        \"opmlFile\": \"Ficheiro OPML\",\n        \"name\": \"Nome da fonte\",\n        \"editName\": \"Editar nome\",\n        \"fetchFrequency\": \"Limite da frequência de atualização\",\n        \"unlimited\": \"Ilimitado\",\n        \"openTarget\": \"Método padrão de carregamento dos artigos\",\n        \"delete\": \"Eliminar fonte\",\n        \"add\": \"Adicionar fonte\",\n        \"import\": \"Importar\",\n        \"export\": \"Exportar\",\n        \"rssText\": \"Texto completo do RSS\",\n        \"loadWebpage\": \"Carregar página web\",\n        \"inputUrl\": \"Insira a URL\",\n        \"badIcon\": \"Ícone inválido\",\n        \"badUrl\": \"URL inválida\",\n        \"deleteWarning\": \"A fonte e todos os artigos guardados serão removidos.\",\n        \"selected\": \"Fonte selecionada\",\n        \"selectedMulti\": \"Múltiplas fontes selecionadas\"\n    },\n    \"groups\": {\n        \"exist\": \"Este grupo já existe.\",\n        \"type\": \"Tipo\",\n        \"group\": \"Grupo\",\n        \"source\": \"Fonte\",\n        \"capacity\": \"Capacidade\",\n        \"exitGroup\": \"Voltar para os grupos\",\n        \"deleteSource\": \"Eliminar do grupo\",\n        \"sourceHint\": \"Arraste e solte as fontes para reorganizá-las.\",\n        \"create\": \"Criar grupo\",\n        \"selectedGroup\": \"Grupo selecionado\",\n        \"selectedSource\": \"Fonte selecionada\",\n        \"enterName\": \"Insira o nome\",\n        \"editName\": \"Editar nome\",\n        \"deleteGroup\": \"Eliminar grupo\",\n        \"chooseGroup\": \"Selecione um grupo\",\n        \"addToGroup\": \"Adicionar a ...\",\n        \"groupHint\": \"Clique duplo no grupo para editar as fontes. Arraste e solte para reorganizá-los.\"\n    },\n    \"rules\": {\n        \"intro\": \"Marcar artigos automaticamente ou enviar notificações com expressões regulares.\",\n        \"help\": \"Saber mais\",\n        \"source\": \"Fonte\",\n        \"selectSource\": \"Selecionar uma fonte\",\n        \"new\": \"Nova regra\",\n        \"if\": \"Se\",\n        \"then\": \"Então\",\n        \"title\": \"Título\",\n        \"content\": \"Conteúdo\",\n        \"fullSearch\": \"Título ou conteúdo\",\n        \"creator\": \"Autor\",\n        \"match\": \"corresponde\",\n        \"notMatch\": \"não corresponde\",\n        \"regex\": \"Expressão regular\",\n        \"badRegex\": \"Expressão regular inválida.\",\n        \"action\": \"Ações\",\n        \"selectAction\": \"Selecionar ações\",\n        \"hint\": \"As regras serão aplicadas em ordem. Arraste e solte para reorganizar.\",\n        \"test\": \"Testar regras\"\n    },\n    \"service\": {\n        \"intro\": \"Sincronização entre dispositivos com serviços RSS.\",\n        \"select\": \"Selecione um serviço\",\n        \"suggest\": \"Sugerir um novo serviço\",\n        \"overwriteWarning\": \"Fontes locais serão eliminadas se elas existirem no serviço.\",\n        \"groupsWarning\": \"Grupos não são automaticamente sincronizados com o serviço.\",\n        \"rateLimitWarning\": \"Para evitar limitações do serviço, você precisa criar sua própria chave de API.\",\n        \"removeAd\": \"Remover Anuncio\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Utilizador\",\n        \"password\": \"Password\",\n        \"unchanged\": \"Inalterado\",\n        \"fetchLimit\": \"Limite de sincronização\",\n        \"fetchLimitNum\": \"{count} últimos artigos\",\n        \"importGroups\": \"Importar grupos\",\n        \"failure\": \"Não foi possível conectar ao serviço\",\n        \"failureHint\": \"Por favor verifique a configuração do serviço ou o estado da rede.\",\n        \"fetchUnlimited\": \"Ilimitado (não recomendado)\",\n        \"exportToLite\": \"Exportar para o Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Limpar\",\n        \"cache\": \"Limpar cache\",\n        \"cacheSize\": \"{size} de dados em cache\",\n        \"deleteChoices\": \"Eliminar artigos de ... dias atrás\",\n        \"confirmDelete\": \"Eliminar\",\n        \"daysAgo\": \"{days, plural, =1 {# dia} other {# dias}} atrás\",\n        \"deleteAll\": \"Eliminar todos os artigos\",\n        \"calculatingSize\": \"Calculando tamanho...\",\n        \"itemSize\": \"Cerca de {size} do armazenamento local é ocupado por artigos\",\n        \"confirmImport\": \"Do you really want to import data from the backup file? All current data will be wiped.\",\n        \"data\": \"Dados da aplicação\",\n        \"backup\": \"Backup\",\n        \"restore\": \"Restorar\",\n        \"frData\": \"Dados do Fluent Reader\",\n        \"language\": \"Idioma\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Modo claro\",\n        \"darkTheme\": \"Modo escuro\",\n        \"enableProxy\": \"Ativar proxy\",\n        \"badUrl\": \"URL inválida\",\n        \"pac\": \"Endereço PAC\",\n        \"setPac\": \"Definir PAC\",\n        \"pacHint\": \"Para proxies Socks, é recomendado para o PAC retornar \\\"SOCKS5\\\" para o proxy-side DNS. Desligar o proxy requer um reinicio.\",\n        \"fetchInterval\": \"Intervalo de atualização automática\",\n        \"never\": \"Nunca\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/ru.json",
    "content": "{\n    \"allArticles\": \"Все статьи\",\n    \"add\": \"Добавить\",\n    \"create\": \"Создать\",\n    \"icon\": \"Иконка\",\n    \"name\": \"Название\",\n    \"openExternal\": \"Открыть внешней программой\",\n    \"emptyName\": \"Это поле не может быть пустым.\",\n    \"emptyField\": \"Это поле не может быть пустым.\",\n    \"edit\": \"Редактировать\",\n    \"delete\": \"Удалить\",\n    \"followSystem\": \"Как в системе\",\n    \"more\": \"Ещё\",\n    \"close\": \"Закрыть\",\n    \"search\": \"Поиск\",\n    \"loadMore\": \"Загрузить ещё\",\n    \"dangerButton\": \"Подтвердить {action}?\",\n    \"confirmMarkAll\": \"Вы действительно хотите отметить все статьи на этой странице прочитанными?\",\n    \"confirm\": \"Подтвердить\",\n    \"cancel\": \"Отмена\",\n    \"default\": \"По умолчанию\",\n    \"time\": {\n        \"now\": \"сейчас\",\n        \"m\": \"м\",\n        \"h\": \"ч\",\n        \"d\": \"д\",\n        \"minute\": \"{m, plural, =1 {# минута} other {# минут}}\",\n        \"hour\": \"{h, plural, =1 {# час} other {# часов}}\",\n        \"day\": \"{d, plural, =1 {# день} other {# дней}}\"\n    },\n    \"log\": {\n        \"empty\": \"Нет уведомлений\",\n        \"fetchFailure\": \"Не удалось загрузить из источника \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Успешно {count, plural, =1 {получена # статья} other {получены # статей}}.\",\n        \"networkError\": \"Ошибка сети.\",\n        \"parseError\": \"Возникла ошибка при разборе XML.\",\n        \"syncFailure\": \"Не удалось синхронизировать с сервисом\"\n    },\n    \"nav\": {\n        \"menu\": \"Меню\",\n        \"refresh\": \"Обновить\",\n        \"markAllRead\": \"Отметить всё прочитанным\",\n        \"notifications\": \"Уведомления\",\n        \"view\": \"Вид\",\n        \"settings\": \"Настройки\",\n        \"minimize\": \"Свернуть\",\n        \"maximize\": \"Развернуть\"\n    },\n    \"menu\": {\n        \"close\": \"Закрыть меню\",\n        \"subscriptions\": \"Подписки\"\n    },\n    \"article\": {\n        \"error\": \"Не удалось загрузить статью.\",\n        \"reload\": \"Перезагрузить?\",\n        \"empty\": \"Нет статей\",\n        \"untitled\": \"(Без названия)\",\n        \"hide\": \"Спрятать статью\",\n        \"unhide\": \"Показать статью\",\n        \"markRead\": \"Отметить как прочитанное\",\n        \"markUnread\": \"Отметить как непрочитанное\",\n        \"markAbove\": \"Отметить выше как прочитанное\",\n        \"markBelow\": \"Отметить ниже как прочитанное\",\n        \"star\": \"В избранное\",\n        \"unstar\": \"Убрать из избранного\",\n        \"fontSize\": \"Размер шрифта\",\n        \"loadWebpage\": \"Загрузить веб-страницу\",\n        \"loadFull\": \"Загрузить полное содержимое\",\n        \"notify\": \"Уведомить, если получено в фоновом режиме\",\n        \"dontNotify\": \"Не уведомлять\",\n        \"textDir\": \"Направление текста\",\n        \"LTR\": \"Слева направо\",\n        \"RTL\": \"Справа налево\",\n        \"Vertical\": \"Вертикально\",\n        \"font\": \"Шрифт\"\n    },\n    \"context\": {\n        \"share\": \"Поделиться\",\n        \"read\": \"Читать\",\n        \"copyTitle\": \"Копировать заголовок\",\n        \"copyURL\": \"Копировать ссылку\",\n        \"copy\": \"Копировать\",\n        \"search\": \"Искать \\\"{text}\\\" в {engine}\",\n        \"view\": \"Вид\",\n        \"cardView\": \"Карточки\",\n        \"listView\": \"Список\",\n        \"magazineView\": \"Журнал\",\n        \"compactView\": \"Компактный\",\n        \"filter\": \"Фильтры\",\n        \"unreadOnly\": \"Только непрочитанные\",\n        \"starredOnly\": \"Только избранные\",\n        \"fullSearch\": \"Поиск по всему тексту\",\n        \"showHidden\": \"Показывать скрытые\",\n        \"manageSources\": \"Управление источниками\",\n        \"saveImageAs\": \"Сохранить изображение как …\",\n        \"copyImage\": \"Копировать изображение\",\n        \"copyImageURL\": \"Копировать ссылку на изображение\",\n        \"caseSensitive\": \"С учётом регистра\",\n        \"showCover\": \"Показать обложку\",\n        \"showSnippet\": \"Показать отрывок\",\n        \"fadeRead\": \"Высветлять прочитанные статьи\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Поисковая система\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Произошла ошибка при записи файла.\",\n        \"name\": \"Настройки\",\n        \"fetching\": \"Обновление источников. Пожалуйста, подождите.\",\n        \"exit\": \"Выйти из настроек\",\n        \"sources\": \"Источники\",\n        \"grouping\": \"Группы\",\n        \"rules\": \"Правила\",\n        \"service\": \"Сервисы\",\n        \"app\": \"Предпочтения\",\n        \"about\": \"О программе\",\n        \"version\": \"Версия\",\n        \"shortcuts\": \"Сочетания клавиш\",\n        \"openSource\": \"Открытый исходный код\",\n        \"feedback\": \"Обратная связь\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Импортированные или добавленные здесь источники не будут синхронизированы с Вашим сервисом.\",\n        \"serviceManaged\": \"Этот источник управляется Вашим сервисом.\",\n        \"untitled\": \"Источник\",\n        \"errorAdd\": \"Возникла ошибка при добавлении источника.\",\n        \"errorParse\": \"Возникла ошибка при разборе OPML файла.\",\n        \"errorParseHint\": \"Пожалуйста, удостоверьтесь что файл не повреждён и использует кодировку UTF-8.\",\n        \"errorImport\": \"Ошибка импорта {count, plural, =1 {# источника} other {# источников}}.\",\n        \"exist\": \"Этот источник уже существует.\",\n        \"opmlFile\": \"OPML файл\",\n        \"name\": \"Название источника\",\n        \"editName\": \"Изменить название\",\n        \"fetchFrequency\": \"Ограничение частоты обновлений\",\n        \"unlimited\": \"Без ограничений\",\n        \"openTarget\": \"Метод открытия статей по умолчанию\",\n        \"delete\": \"Удалить источник\",\n        \"add\": \"Добавить источник\",\n        \"import\": \"Импорт\",\n        \"export\": \"Экспорт\",\n        \"rssText\": \"Полный текст RSS\",\n        \"loadWebpage\": \"Загрузить веб-страницу\",\n        \"inputUrl\": \"Введите URL\",\n        \"badIcon\": \"Недопустимая иконка\",\n        \"badUrl\": \"Недопустимый URL\",\n        \"deleteWarning\": \"Источник и все сохранённые статьи будут удалены.\",\n        \"selected\": \"Выберите источник\",\n        \"selectedMulti\": \"Выберите несколько источников\"\n    },\n    \"groups\": {\n        \"exist\": \"Эта группа уже существует.\",\n        \"type\": \"Тип\",\n        \"group\": \"Группа\",\n        \"source\": \"Источник\",\n        \"capacity\": \"Ёмкость\",\n        \"exitGroup\": \"Назад к группам\",\n        \"deleteSource\": \"Удалить из группы\",\n        \"sourceHint\": \"Перетаскивайте источники для изменения порядка.\",\n        \"create\": \"Создать группу\",\n        \"selectedGroup\": \"Выбранная группа\",\n        \"selectedSource\": \"Выбранный источник\",\n        \"enterName\": \"Введите название\",\n        \"editName\": \"Изменить название\",\n        \"deleteGroup\": \"Удалить группу\",\n        \"chooseGroup\": \"Выбрать группу\",\n        \"addToGroup\": \"Добавить в …\",\n        \"groupHint\": \"Сделайте двойной щелчок по группе для редактирования источников. Перетаскивайте для изменения порядка.\"\n    },\n    \"rules\": {\n        \"intro\": \"Автоматически отмечать статьи или отправлять уведомления с помощью регулярных выражений.\",\n        \"help\": \"Узнать больше\",\n        \"source\": \"Источник\",\n        \"selectSource\": \"Выбрать источник\",\n        \"new\": \"Новое правило\",\n        \"if\": \"Если\",\n        \"then\": \"То\",\n        \"title\": \"Название\",\n        \"content\": \"Содержимое\",\n        \"fullSearch\": \"Название или содержимое\",\n        \"creator\": \"Автор\",\n        \"match\": \"совпадает\",\n        \"notMatch\": \"не совпадает\",\n        \"regex\": \"Регулярное выражение\",\n        \"badRegex\": \"Недопустимое регулярное выражение.\",\n        \"action\": \"Действия\",\n        \"selectAction\": \"Выберите действия\",\n        \"hint\": \"Правила применяются по порядку. Перетащите для изменения порядка.\",\n        \"test\": \"Проверить правила\"\n    },\n    \"service\": {\n        \"intro\": \"Синхронизация между устройствами с помощью RSS сервисов.\",\n        \"select\": \"Выберите сервис\",\n        \"suggest\": \"Предложить новый сервис\",\n        \"overwriteWarning\": \"Локальные источники будут удалены если они существуют в сервисе.\",\n        \"groupsWarning\": \"Группы не синхронизируются автоматически через сервис.\",\n        \"rateLimitWarning\": \"Чтобы избежать ограничения частоты запросов, Вам нужно создать свой ключ API.\",\n        \"removeAd\": \"Убрать рекламу\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Имя пользователя\",\n        \"password\": \"Пароль\",\n        \"unchanged\": \"Без изменений\",\n        \"fetchLimit\": \"Ограничение синхронизации\",\n        \"fetchLimitNum\": \"{count, plural, =1 {# последняя статья} other {# последних статей}}\",\n        \"importGroups\": \"Импортировать группы\",\n        \"failure\": \"Нет подключения к сервису\",\n        \"failureHint\": \"Please check the service configuration or network status.\",\n        \"fetchUnlimited\": \"Без ограничений (не рекомендуется)\",\n        \"exportToLite\": \"Экспорт в Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Очистка\",\n        \"cache\": \"Очистить кэш\",\n        \"cacheSize\": \"Закэшировано {size} данных\",\n        \"deleteChoices\": \"Удалить статьи старше … дней\",\n        \"confirmDelete\": \"Удалить\",\n        \"daysAgo\": \"{days, plural, =1 {# дня} other {# дней}} назад\",\n        \"deleteAll\": \"Удалить все статьи\",\n        \"calculatingSize\": \"Вычисление размера…\",\n        \"itemSize\": \"Статьями занято примерно {size} пространства локального хранилища\",\n        \"confirmImport\": \"Вы действительно хотите импортировать данные из файла резервной копии? Все текущие данные будут удалены.\",\n        \"data\": \"Данные приложения\",\n        \"backup\": \"Резервная копия\",\n        \"restore\": \"Восстановление\",\n        \"frData\": \"Данные Fluent Reader\",\n        \"language\": \"Язык интерфейса\",\n        \"theme\": \"Тема\",\n        \"lightTheme\": \"Светлая\",\n        \"darkTheme\": \"Тёмная\",\n        \"enableProxy\": \"Включить прокси\",\n        \"badUrl\": \"Недопустимый URL\",\n        \"pac\": \"PAC Адрес\",\n        \"setPac\": \"Установить PAC\",\n        \"pacHint\": \"Для Socks прокси рекомендуется, чтобы PAC возвращал \\\"SOCKS5\\\" для DNS на стороне прокси. Выключение прокси требует перезапуска.\",\n        \"fetchInterval\": \"Интервал автоматического обновления\",\n        \"never\": \"Никогда\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/sv.json",
    "content": "{\n    \"allArticles\": \"Alla artiklar\",\n    \"add\": \"Lägg till\",\n    \"create\": \"Skapa\",\n    \"icon\": \"Ikon\",\n    \"name\": \"Namn\",\n    \"openExternal\": \"Öppna externt\",\n    \"emptyName\": \"Detta fält kan inte vara tomt.\",\n    \"emptyField\": \"Detta fält kan inte vara tomt.\",\n    \"edit\": \"Redigera\",\n    \"delete\": \"Ta bort\",\n    \"followSystem\": \"Följ systemet\",\n    \"more\": \"Mer\",\n    \"close\": \"Stäng\",\n    \"search\": \"Sök\",\n    \"loadMore\": \"Läs in mer\",\n    \"dangerButton\": \"Bekräfta {action}?\",\n    \"confirmMarkAll\": \"Vill du verkligen markera alla artiklar på denna sida som lästa?\",\n    \"confirm\": \"Bekräfta\",\n    \"cancel\": \"Avbryt\",\n    \"time\": {\n        \"now\": \"nu\",\n        \"m\": \"m\",\n        \"h\": \"t\",\n        \"d\": \"d\",\n        \"minute\": \"{m, plural, =1 {# minut} other {# minuter}}\",\n        \"hour\": \"{h, plural, =1 {# timma} other {# timmar}}\",\n        \"day\": \"{d, plural, =1 {# dag} other {# dagar}}\"\n    },\n    \"log\": {\n        \"empty\": \"Ingen avisering\",\n        \"fetchFailure\": \"Kunde inte läsa in källan \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Lyckades hämta {count, plural, =1 {# artikel} other {# artiklar}}.\",\n        \"networkError\": \"Ett nätverksfel uppstod.\",\n        \"parseError\": \"Ett fel uppstod vid tolkning av XML-flödet.\",\n        \"syncFailure\": \"Kunde inte synkronisera med tjänsten\"\n    },\n    \"nav\": {\n        \"menu\": \"Meny\",\n        \"refresh\": \"Uppdatera\",\n        \"markAllRead\": \"Markera alla som lästa\",\n        \"notifications\": \"Aviseringar\",\n        \"view\": \"Visa\",\n        \"settings\": \"Inställningar\",\n        \"minimize\": \"Minimera\",\n        \"maximize\": \"Maximera\"\n    },\n    \"menu\": {\n        \"close\": \"Stäng menyn\",\n        \"subscriptions\": \"Prenumerationer\"\n    },\n    \"article\": {\n        \"error\": \"Kunde inte läsa in artikeln.\",\n        \"reload\": \"Vill du läsa in igen?\",\n        \"empty\": \"Inga artiklar\",\n        \"untitled\": \"(Namnlös)\",\n        \"hide\": \"Dölj artikel\",\n        \"unhide\": \"Visa artikel\",\n        \"markRead\": \"Markera som läst\",\n        \"markUnread\": \"Markera som oläst\",\n        \"markAbove\": \"Markera ovanstående som läst\",\n        \"markBelow\": \"Markera nedanstående som läst\",\n        \"star\": \"Stjärna\",\n        \"unstar\": \"Ta bort stjärna\",\n        \"fontSize\": \"Teckenstorlek\",\n        \"loadWebpage\": \"Läs in webbsidan\",\n        \"loadFull\": \"Läs in fullständigt innehåll\",\n        \"notify\": \"Avisera om hämtat i bakgrunden\",\n        \"dontNotify\": \"Avisera inte\"\n    },\n    \"context\": {\n        \"share\": \"Dela\",\n        \"read\": \"Läs\",\n        \"copyTitle\": \"Kopiera titel\",\n        \"copyURL\": \"Kopiera länk\",\n        \"copy\": \"Kopiera\",\n        \"search\": \"Sök \\\"{text}\\\" på {engine}\",\n        \"view\": \"Visa\",\n        \"cardView\": \"Kortvy\",\n        \"listView\": \"Listvy\",\n        \"magazineView\": \"Tidningsvy\",\n        \"compactView\": \"Kompakt vy\",\n        \"filter\": \"Filtrering\",\n        \"unreadOnly\": \"Endast oläst\",\n        \"starredOnly\": \"Endast stjärnmärkt\",\n        \"fullSearch\": \"Sök i hela texten\",\n        \"showHidden\": \"Visa dolda artiklar\",\n        \"manageSources\": \"Hantera källor\",\n        \"saveImageAs\": \"Spara bild som …\",\n        \"copyImage\": \"Kopiera bild\",\n        \"copyImageURL\": \"Kopiera bildlänk\",\n        \"caseSensitive\": \"Skiftlägeskänslig\",\n        \"showCover\": \"Visa omslag\",\n        \"showSnippet\": \"Visa utdrag\",\n        \"fadeRead\": \"Tona lästa artiklar\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Sökmotor\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Ett fel uppstod vid skrivning av filen.\",\n        \"name\": \"Inställningar\",\n        \"fetching\": \"Uppdaterar källor, vänta …\",\n        \"exit\": \"Stäng inställningar\",\n        \"sources\": \"Källor\",\n        \"grouping\": \"Grupper\",\n        \"rules\": \"Regler\",\n        \"service\": \"Tjänst\",\n        \"app\": \"Inställningar\",\n        \"about\": \"Om\",\n        \"version\": \"Version\",\n        \"shortcuts\": \"Genvägar\",\n        \"openSource\": \"Open source\",\n        \"feedback\": \"Återkoppling\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Källor tillagda eller importerade här, kommer inte att synkroniseras med din tjänst.\",\n        \"serviceManaged\": \"Denna källa hanteras av din tjänst.\",\n        \"untitled\": \"Källa\",\n        \"errorAdd\": \"Ett fel uppstod då källan lades till.\",\n        \"errorParse\": \"Ett fel uppstod vid tolkning av OPML-filen.\",\n        \"errorParseHint\": \"Tillse att filen inte är skadad och är kodad med UTF-8.\",\n        \"errorImport\": \"Fel vid import av {count, plural, =1 {# källa} other {# källor}}.\",\n        \"exist\": \"Denna källa finns redan.\",\n        \"opmlFile\": \"OPML-fil\",\n        \"name\": \"Källnamn\",\n        \"editName\": \"Redigera namn\",\n        \"fetchFrequency\": \"Hämta frekvensbegränsning\",\n        \"unlimited\": \"Obegränsad\",\n        \"openTarget\": \"Standard öppet mål för artiklar\",\n        \"delete\": \"Ta bort källa\",\n        \"add\": \"Lägg till källa\",\n        \"import\": \"Importera\",\n        \"export\": \"Exportera\",\n        \"rssText\": \"RSS fulltext\",\n        \"loadWebpage\": \"Läs in webbsidaq\",\n        \"inputUrl\": \"Ange URL\",\n        \"badIcon\": \"Ogiltig ikon\",\n        \"badUrl\": \"Ogiltig URL\",\n        \"deleteWarning\": \"Källan och alla sparade artiklar kommer att tas bort.\",\n        \"selected\": \"Valde källa\",\n        \"selectedMulti\": \"Valde flera källor\"\n    },\n    \"groups\": {\n        \"exist\": \"Denna grupp finns redan.\",\n        \"type\": \"Typ\",\n        \"group\": \"Grupp\",\n        \"source\": \"Källa\",\n        \"capacity\": \"Kapacitet\",\n        \"exitGroup\": \"Tillbaka till grupper\",\n        \"deleteSource\": \"Ta bort från gruppen\",\n        \"sourceHint\": \"Dra och släpp källor för att sortera.\",\n        \"create\": \"Skapa grupp\",\n        \"selectedGroup\": \"Valde grupp\",\n        \"selectedSource\": \"Valde källa\",\n        \"enterName\": \"Ange namn\",\n        \"editName\": \"Redigera namn\",\n        \"deleteGroup\": \"Ta bort grupp\",\n        \"chooseGroup\": \"Välj en grupp\",\n        \"addToGroup\": \"Lägg till i ...\",\n        \"groupHint\": \"Dubbelklicka på en grupp för att redigera källor. Dra och släpp för att sortera.\"\n    },\n    \"rules\": {\n        \"intro\": \"Markera artiklar automatiskt eller avisera med regular expressions.\",\n        \"help\": \"Läs mer\",\n        \"source\": \"Källa\",\n        \"selectSource\": \"Välj en källa\",\n        \"new\": \"Ny regel\",\n        \"if\": \"Om\",\n        \"then\": \"Då\",\n        \"title\": \"Titel\",\n        \"content\": \"Innehåll\",\n        \"fullSearch\": \"Titel eller innehåll\",\n        \"creator\": \"Författare\",\n        \"match\": \"matchar\",\n        \"notMatch\": \"matchar inte\",\n        \"regex\": \"Regular expression\",\n        \"badRegex\": \"Ogiltigt regular expression.\",\n        \"action\": \"Åtgärder\",\n        \"selectAction\": \"Välj åtgärder\",\n        \"hint\": \"Regler kommer att tillämpas i ordning. Dra och släpp för att ändra ordningen.\",\n        \"test\": \"Testa regler\"\n    },\n    \"service\": {\n        \"intro\": \"Synkronisera mellan enheter med RSS-tjänster.\",\n        \"select\": \"Välj en tjänst\",\n        \"suggest\": \"Föreslå en ny tjänst\",\n        \"overwriteWarning\": \"Lokala källor tas bort, om de finns i tjänsten.\",\n        \"groupsWarning\": \"Grupper synkroniseras inte automatiskt med tjänsten.\",\n        \"rateLimitWarning\": \"För att undvika frekvensbegränsning måste du skapa din egen API-nyckel.\",\n        \"removeAd\": \"Ta bort annons\",\n        \"endpoint\": \"Slutpunkt\",\n        \"username\": \"Användarnamn\",\n        \"password\": \"Lösenord\",\n        \"unchanged\": \"Oförändrad\",\n        \"fetchLimit\": \"Synkroniseringsgräns\",\n        \"fetchLimitNum\": \"{count} senaste artiklar\",\n        \"importGroups\": \"Importera grupper\",\n        \"failure\": \"Kan inte ansluta till tjänsten\",\n        \"failureHint\": \"Kontrollera tjänstkonfigurationen eller nätverksstatus.\",\n        \"fetchUnlimited\": \"Obegränsat (rekommenderas ej)\",\n        \"exportToLite\": \"Exportera till Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Rensa\",\n        \"cache\": \"Rensa cache\",\n        \"cacheSize\": \"Cache-lagra {size} data\",\n        \"deleteChoices\": \"Ta bort artiklar från ... dagar sedan\",\n        \"confirmDelete\": \"Ta bort\",\n        \"daysAgo\": \"{days, plural, =1 {# dag} other {# dagar}} sedan\",\n        \"deleteAll\": \"Ta bort alla artiklar\",\n        \"calculatingSize\": \"Beräknar storlek...\",\n        \"itemSize\": \"Omkring {size} lokal datalagring upptas av artiklar\",\n        \"confirmImport\": \"Vill du verkligen importera data från säkerhetskopian? All aktuell data kommer att raderas.\",\n        \"data\": \"Applikationsdata\",\n        \"backup\": \"Säkerhetskopier\",\n        \"restore\": \"Återställ\",\n        \"frData\": \"Fluent Reader Data\",\n        \"language\": \"Skärmspråk\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Ljust läge\",\n        \"darkTheme\": \"Mörkt läge\",\n        \"enableProxy\": \"Aktivera proxy\",\n        \"badUrl\": \"Ogiltig URL\",\n        \"pac\": \"PAC-adress\",\n        \"setPac\": \"Ange PAC\",\n        \"pacHint\": \"För Socks-proxyservrar rekommenderas att PAC returnerar \\\"SOCKS5\\\" för DNS på proxysidan. Om du stänger av proxyn krävs omstart.\",\n        \"fetchInterval\": \"Automatiskt hämtningsintervall\",\n        \"never\": \"Aldrig\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/tr.json",
    "content": "{\n    \"allArticles\": \"Tüm Yazılar\",\n    \"add\": \"Ekle\",\n    \"create\": \"Ekle\",\n    \"icon\": \"Simge\",\n    \"name\": \"Ad\",\n    \"openExternal\": \"Yeni pencerede aç\",\n    \"emptyName\": \"Bu alan boş olamaz.\",\n    \"emptyField\": \"Bu alan boş olamaz.\",\n    \"edit\": \"Düzenle\",\n    \"delete\": \"Sil\",\n    \"followSystem\": \"Sistem ayarlarını kullan\",\n    \"more\": \"Daha fazla\",\n    \"close\": \"Kapat\",\n    \"search\": \"Ara\",\n    \"loadMore\": \"Daha fazla\",\n    \"dangerButton\": \"İşleme devam et ({action})\",\n    \"confirmMarkAll\": \"Bu sayfadaki tüm yazıları gerçekten okundu olarak işaretlemek istiyor musunuz?\",\n    \"confirm\": \"Tamam\",\n    \"cancel\": \"İptal Et\",\n    \"time\": {\n        \"now\": \"şu an\",\n        \"m\": \"d\",\n        \"h\": \"s\",\n        \"d\": \"g\",\n        \"minute\": \"{m, plural, =1 {# dakika} other {# dakika}}\",\n        \"hour\": \"{h, plural, =1 {# saat} other {# saat}}\",\n        \"day\": \"{d, plural, =1 {# gün} other {# gün}}\"\n    },\n    \"log\": {\n        \"empty\": \"Bildirim yok\",\n        \"fetchFailure\": \"\\\"{name}\\\" kaynağı yüklenemedi.\",\n        \"fetchSuccess\": \"{count, plural, =1 {# yazı} other {# yazı}} başarıyla güncellendi.\",\n        \"networkError\": \"Ağ hatası oluştu.\",\n        \"parseError\": \"XML beslemesi ayrıştırılırken bir hata oluştu..\",\n        \"syncFailure\": \"Hizmet ile senkronize edilemedi\"\n    },\n    \"nav\": {\n        \"menu\": \"Menü\",\n        \"refresh\": \"Yenile\",\n        \"markAllRead\": \"Tümünü okundu olarak işaretle\",\n        \"notifications\": \"Bildirimler\",\n        \"view\": \"Görünüm\",\n        \"settings\": \"Ayarlar\",\n        \"minimize\": \"Simge durumuna küçült\",\n        \"maximize\": \"Ekranı kapla\"\n    },\n    \"menu\": {\n        \"close\": \"Kapat\",\n        \"subscriptions\": \"Abonelikler\"\n    },\n    \"article\": {\n        \"error\": \"Yazı yüklenemedi.\",\n        \"reload\": \"Tekrar yükle?\",\n        \"empty\": \"Yazı yok\",\n        \"untitled\": \"(Başlıksız)\",\n        \"hide\": \"Yazıyı gizle\",\n        \"unhide\": \"Yazıyı göster\",\n        \"markRead\": \"Okundu olarak işaretle\",\n        \"markUnread\": \"Okunmamış olarak işaretle\",\n        \"markAbove\": \"Yukarıdakileri okundu olarak işaretle\",\n        \"markBelow\": \"Aşağıdakileri okundu olarak işaretle\",\n        \"star\": \"Yıldız ekle\",\n        \"unstar\": \"Yıldızı kaldır\",\n        \"fontSize\": \"Yazı boyutu\",\n        \"loadWebpage\": \"Web sayfasını yükle\",\n        \"loadFull\": \"Tam içeriği yükle\",\n        \"notify\": \"Arka planda getirilirse bildir\",\n        \"dontNotify\": \"Bildirme\"\n    },\n    \"context\": {\n        \"share\": \"Paylaş\",\n        \"read\": \"Oku\",\n        \"copyTitle\": \"Başlığı kopyala\",\n        \"copyURL\": \"Bağlantıyı kopyala\",\n        \"copy\": \"Kopyala\",\n        \"search\": \"{engine}'da \\\"{text}\\\" ara\",\n        \"view\": \"Görünüm\",\n        \"cardView\": \"Kart görünümü\",\n        \"listView\": \"Liste görünümü\",\n        \"magazineView\": \"Dergi görünümü\",\n        \"compactView\": \"Kompakt görünüm\",\n        \"filter\": \"Filtreleme\",\n        \"unreadOnly\": \"Okunmamışlar\",\n        \"starredOnly\": \"Yıldızlılar\",\n        \"fullSearch\": \"Tam metinde ara\",\n        \"showHidden\": \"Gizli yazıları göster\",\n        \"manageSources\": \"Kaynakları yönet\",\n        \"saveImageAs\": \"Resmi farklı kaydet …\",\n        \"copyImage\": \"Resmi kopyala\",\n        \"copyImageURL\": \"Resim bağlantısını kopyala\",\n        \"caseSensitive\": \"Harfe duyarlı\",\n        \"showCover\": \"Resmi göster\",\n        \"showSnippet\": \"Açıklama göster\",\n        \"fadeRead\": \"Okunanları karart\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Arama motoru\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Dosyayı yazarken bir hata oluştu.\",\n        \"name\": \"Ayarlar\",\n        \"fetching\": \"Kaynaklar güncelleniyor, lütfen bekleyin…\",\n        \"exit\": \"Çıkış\",\n        \"sources\": \"Kaynaklar\",\n        \"grouping\": \"Gruplar\",\n        \"rules\": \"Kurallar\",\n        \"service\": \"Hizmetler\",\n        \"app\": \"Tercihler\",\n        \"about\": \"Hakkında\",\n        \"version\": \"Sürüm\",\n        \"shortcuts\": \"Kısayollar\",\n        \"openSource\": \"Açık Kaynak\",\n        \"feedback\": \"Geri Bildirim\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Sources imported or added here will not be synced with your service.\",\n        \"serviceManaged\": \"Bu kaynak, hizmetiniz tarafından yönetilmektedir.\",\n        \"untitled\": \"Kaynak\",\n        \"errorAdd\": \"Kaynak eklenirken bir hata oluştu.\",\n        \"errorParse\": \"OPML dosyası ayrıştırılırken bir hata oluştu.\",\n        \"errorParseHint\": \"Lütfen dosyanın bozuk olmadığından ve UTF-8 formatında olduğundan emin olun.\",\n        \"errorImport\": \"İçe aktarma hatası {count, plural, =1 {# kaynak} other {# kaynak}}.\",\n        \"exist\": \"Bu kaynak zaten var.\",\n        \"opmlFile\": \"OPML Dosyası\",\n        \"name\": \"Kaynak adı\",\n        \"editName\": \"Güncelle\",\n        \"fetchFrequency\": \"Yenileme sıklığı\",\n        \"unlimited\": \"Sınırsız\",\n        \"openTarget\": \"Yazılar için varsayılan işlem\",\n        \"delete\": \"Sil\",\n        \"add\": \"Kaynak ekle\",\n        \"import\": \"İçe Aktar\",\n        \"export\": \"Dışa Aktar\",\n        \"rssText\": \"RSS tam metni\",\n        \"loadWebpage\": \"Web sayfasını yükle\",\n        \"inputUrl\": \"URL girin\",\n        \"badIcon\": \"Geçersiz simge\",\n        \"badUrl\": \"Geçersiz URL\",\n        \"deleteWarning\": \"Kaynak ve kaydedilen tüm yazılar kaldırılacaktır.\",\n        \"selected\": \"Seçilen kaynak\",\n        \"selectedMulti\": \"Birden çok kaynak seçildi\"\n    },\n    \"groups\": {\n        \"exist\": \"Bu grup zaten var.\",\n        \"type\": \"Tip\",\n        \"group\": \"Grup\",\n        \"source\": \"Kaynak\",\n        \"capacity\": \"Kapasite\",\n        \"exitGroup\": \"Geri\",\n        \"deleteSource\": \"Sil\",\n        \"sourceHint\": \"Yeniden sıralamak için kaynakları sürükleyip bırakın.\",\n        \"create\": \"Grup oluştur\",\n        \"selectedGroup\": \"Grup\",\n        \"selectedSource\": \"Kaynağı seç\",\n        \"enterName\": \"Ad girin\",\n        \"editName\": \"Güncelle\",\n        \"deleteGroup\": \"Sil\",\n        \"chooseGroup\": \"Grup seç\",\n        \"addToGroup\": \"Ekle\",\n        \"groupHint\": \"Kaynakları düzenlemek için gruba çift tıklayın. Yeniden sıralamak için sürükleyip bırakın.\"\n    },\n    \"rules\": {\n        \"intro\": \"Yazıları otomatik olarak işaretle yada düzenli ifadeler (regex) ile bildirimler gönder.\",\n        \"help\": \"Daha fazla bilgi edin\",\n        \"source\": \"Kaynak\",\n        \"selectSource\": \"Kaynak Seçin\",\n        \"new\": \"Yeni kural\",\n        \"if\": \"Eğer\",\n        \"then\": \"Sonra\",\n        \"title\": \"Başlık\",\n        \"content\": \"İçerik\",\n        \"fullSearch\": \"Başlık veya İçerik\",\n        \"creator\": \"Yazar\",\n        \"match\": \"eşleşiyorsa\",\n        \"notMatch\": \"eşleşmiyorsa\",\n        \"regex\": \"Düzenli ifade (Regex)\",\n        \"badRegex\": \"Geçersiz düzenli ifade (Regex).\",\n        \"action\": \"Eylemler\",\n        \"selectAction\": \"Eylemleri Seçin\",\n        \"hint\": \"Kurallar sırayla uygulanacaktır. Yeniden sıralamak için sürükleyip bırakın.\",\n        \"test\": \"Test Et\"\n    },\n    \"service\": {\n        \"intro\": \"RSS hizmetleriyle cihazlar arasında senkronize edin.\",\n        \"select\": \"Hizmet seçin\",\n        \"suggest\": \"Yeni hizmet öner\",\n        \"overwriteWarning\": \"Kaynak hizmet içerisinde varsa, yerel kaynaklar silinecek..\",\n        \"groupsWarning\": \"Gruplar hizmetle otomatik olarak senkronize edilmez.\",\n        \"endpoint\": \"Endpoint\",\n        \"username\": \"Kullanıcı Adı\",\n        \"password\": \"Parola\",\n        \"unchanged\": \"Değişmedi\",\n        \"fetchLimit\": \"Senkronizasyon sınırı\",\n        \"fetchLimitNum\": \"Son {count} yazı\",\n        \"importGroups\": \"Grupları içe aktar\",\n        \"failure\": \"Hizmete bağlanılamıyor\",\n        \"failureHint\": \"Lütfen servis ayarlarını veya internet bağlantınızı kontrol edin.\",\n        \"fetchUnlimited\": \"Sınırsız (tavsiye edilmez)\"\n    },\n    \"app\": {\n        \"cleanup\": \"Temizle\",\n        \"cache\": \"Önbelleği temizle\",\n        \"cacheSize\": \"{size} veri önbelleğe alındı\",\n        \"deleteChoices\": \"... gün öncesine ait yazıları sil\",\n        \"confirmDelete\": \"Sil\",\n        \"daysAgo\": \"{days} gün önce\",\n        \"deleteAll\": \"Tüm yazıları sil\",\n        \"calculatingSize\": \"Boyut hesaplanıyor...\",\n        \"itemSize\": \"Kullanılan depolama alanınızın yaklaşık {size}\",\n        \"confirmImport\": \"İşleme devam etmek istediğinize emin misiniz? Mevcut tüm veriler silinecek.\",\n        \"data\": \"Uygulama Verileri\",\n        \"backup\": \"Yedekle\",\n        \"restore\": \"Geri Yükle\",\n        \"frData\": \"Fluent Reader Verileri\",\n        \"language\": \"Görüntüleme dili\",\n        \"theme\": \"Tema\",\n        \"lightTheme\": \"Aydınlık\",\n        \"darkTheme\": \"Karanlık\",\n        \"enableProxy\": \"Proxy'yi Etkinleştir\",\n        \"badUrl\": \"Geçersiz URL\",\n        \"pac\": \"PAC Adresi\",\n        \"setPac\": \"PAC ayarla\",\n        \"pacHint\": \"Socks proxy'leri için, PAC'ın proxy tarafı DNS için \\\"SOCKS5\\\" döndürmesi önerilir. Proxy'yi kapatmak, yeniden başlatmayı gerektirir.\",\n        \"fetchInterval\": \"Otomatik getirme aralığı\",\n        \"never\": \"Asla\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/uk.json",
    "content": "{\n    \"allArticles\": \"Всі статті\",\n    \"add\": \"Додати\",\n    \"create\": \"Створити\",\n    \"icon\": \"Іконка\",\n    \"name\": \"Ім'я\",\n    \"openExternal\": \"Відкрити зовні\",\n    \"emptyName\": \"Це поле не може бути порожнім.\",\n    \"emptyField\": \"Це поле не може бути порожнім.\",\n    \"edit\": \"Редагувати\",\n    \"delete\": \"Видалити\",\n    \"followSystem\": \"Як у системі\",\n    \"more\": \"Більше\",\n    \"close\": \"Закрити\",\n    \"search\": \"Шукати\",\n    \"loadMore\": \"Завантажити більше\",\n    \"dangerButton\": \"Справді {action}?\",\n    \"confirmMarkAll\": \"Ви дійсно хочете позначити всі статті на цій сторінці як прочитані?\",\n    \"confirm\": \"Підтвердити\",\n    \"cancel\": \"Назад\",\n    \"time\": {\n        \"now\": \"щойно\",\n        \"m\": \"х\",\n        \"h\": \"г\",\n        \"d\": \"д\",\n        \"minute\": \"{m, plural, =1 {# хвилина} other {# хвилин}}\",\n        \"hour\": \"{h, plural, =1 {# година} other {# годин}}\",\n        \"day\": \"{d, plural, =1 {# день} other {# днів}}\"\n    },\n    \"log\": {\n        \"empty\": \"Немає сповіщень\",\n        \"fetchFailure\": \"Не вдалося завантажити джерело \\\"{name}\\\".\",\n        \"fetchSuccess\": \"Успішно завантажено {count, plural, =1 {# стаття} other {# статів}}.\",\n        \"networkError\": \"Сталася помилка мережі.\",\n        \"parseError\": \"Під час аналізу стрічки XML сталася помилка.\",\n        \"syncFailure\": \"Не вдалося синхронізувати зі службою\"\n    },\n    \"nav\": {\n        \"menu\": \"Меню\",\n        \"refresh\": \"Оновити\",\n        \"markAllRead\": \"Позначити всі як прочитані\",\n        \"notifications\": \"Сповіщення\",\n        \"view\": \"Вигляд\",\n        \"settings\": \"Налаштування\",\n        \"minimize\": \"Мінімізувати\",\n        \"maximize\": \"Максимізувати\"\n    },\n    \"menu\": {\n        \"close\": \"Закрити меню\",\n        \"subscriptions\": \"Підписки\"\n    },\n    \"article\": {\n        \"error\": \"Не вдалося завантажити статтю.\",\n        \"reload\": \"Перезавантажити?\",\n        \"empty\": \"Статей немає\",\n        \"untitled\": \"(Без назви)\",\n        \"hide\": \"Сховати статтю\",\n        \"unhide\": \"Показати статтю\",\n        \"markRead\": \"Позначити як прочитане\",\n        \"markUnread\": \"Позначити як непрочитане\",\n        \"markAbove\": \"Позначити вище як прочитане\",\n        \"markBelow\": \"Позначити нижче як прочитане\",\n        \"star\": \"Зберегти\",\n        \"unstar\": \"Прибрати з збереженого\",\n        \"fontSize\": \"Розмір шрифту\",\n        \"loadWebpage\": \"Завантажити веб-сторінку\",\n        \"loadFull\": \"Завантажте повний вміст\",\n        \"notify\": \"Сповісти, якщо отримано у фоновому режимі\",\n        \"dontNotify\": \"Не сповіщати\"\n    },\n    \"context\": {\n        \"share\": \"Поділитися\",\n        \"read\": \"Читати\",\n        \"copyTitle\": \"Копіювати заголовок\",\n        \"copyURL\": \"Копіювати посилання\",\n        \"copy\": \"Копіювати\",\n        \"search\": \"Шукати \\\"{text}\\\" в {engine}\",\n        \"view\": \"Вигляд\",\n        \"cardView\": \"Карточний\",\n        \"listView\": \"Списком\",\n        \"magazineView\": \"Журнальний\",\n        \"compactView\": \"Компактний\",\n        \"filter\": \"Фільтр\",\n        \"unreadOnly\": \"Лише непрочитане\",\n        \"starredOnly\": \"Лише збережені\",\n        \"fullSearch\": \"Шукати в повному тексті\",\n        \"showHidden\": \"Показати приховані статті\",\n        \"manageSources\": \"Керувати джерелами\",\n        \"saveImageAs\": \"Зберегти зображення як …\",\n        \"copyImage\": \"Копіювати зображення\",\n        \"copyImageURL\": \"Копіювати адресу зображення\",\n        \"caseSensitive\": \"З урахуванням регістру\",\n        \"showCover\": \"Показати обкладинку\",\n        \"showSnippet\": \"Показати фрагмент\",\n        \"fadeRead\": \"Fade читати статті\"\n    },\n    \"searchEngine\": {\n        \"name\": \"Пошукова система\",\n        \"google\": \"Google\",\n        \"bing\": \"Bing\",\n        \"baidu\": \"Baidu\",\n        \"duckduckgo\": \"DuckDuckGo\"\n    },\n    \"settings\": {\n        \"writeError\": \"Під час запису файлу сталася помилка.\",\n        \"name\": \"Налаштування\",\n        \"fetching\": \"Оновлення джерел, зачекайте …\",\n        \"exit\": \"Вийти з налаштувань\",\n        \"sources\": \"Джерела\",\n        \"grouping\": \"Групи\",\n        \"rules\": \"Правила\",\n        \"service\": \"Сервіси\",\n        \"app\": \"Вподобання\",\n        \"about\": \"Відомості\",\n        \"version\": \"Версія\",\n        \"shortcuts\": \"Комбінації клавіш\",\n        \"openSource\": \"Відкрити джерело\",\n        \"feedback\": \"Зворотній зв'язок\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"Джерела, імпортовані або додані сюди, не будуть синхронізовані з вашою службою.\",\n        \"serviceManaged\": \"Цим джерелом керує ваша служба.\",\n        \"untitled\": \"Джерело\",\n        \"errorAdd\": \"Під час додавання джерела сталася помилка.\",\n        \"errorParse\": \"Під час аналізу файлу OPML сталася помилка.\",\n        \"errorParseHint\": \"Переконайтеся, що файл не пошкоджений і має кодування UTF-8.\",\n        \"errorImport\": \"Помилка імпорту {count, plural, =1 {# джерела} other {# джерел}}.\",\n        \"exist\": \"Це джерело вже існує.\",\n        \"opmlFile\": \"OPML Файл\",\n        \"name\": \"Назва джерела\",\n        \"editName\": \"Редагувати назву\",\n        \"fetchFrequency\": \"Вибір обмеження частоти\",\n        \"unlimited\": \"Необмежений\",\n        \"openTarget\": \"Відкрита ціль за замовчуванням для статей\",\n        \"delete\": \"Видалити джерело\",\n        \"add\": \"Додати джерело\",\n        \"import\": \"Імпорт\",\n        \"export\": \"Експорт\",\n        \"rssText\": \"Повний текст RSS\",\n        \"loadWebpage\": \"Завантажити веб-сторінку\",\n        \"inputUrl\": \"Введіть URL-адресу\",\n        \"badIcon\": \"Недійсна іконка\",\n        \"badUrl\": \"Недійсна URL-адреса\",\n        \"deleteWarning\": \"Джерело та всі збережені статті будуть видалені.\",\n        \"selected\": \"Вибране джерело\",\n        \"selectedMulti\": \"Вибрано кілька джерел\"\n    },\n    \"groups\": {\n        \"exist\": \"Ця група вже існує.\",\n        \"type\": \"Тип\",\n        \"group\": \"Група\",\n        \"source\": \"Джерело\",\n        \"capacity\": \"Місткість\",\n        \"exitGroup\": \"Повернутися до груп\",\n        \"deleteSource\": \"Видалити з групи\",\n        \"sourceHint\": \"Перетягніть джерела, щоб змінити порядок.\",\n        \"create\": \"Створити групу\",\n        \"selectedGroup\": \"Вибрана група\",\n        \"selectedSource\": \"Вибране джерело\",\n        \"enterName\": \"Введіть назву\",\n        \"editName\": \"Редагувати назву\",\n        \"deleteGroup\": \"Видалити групу\",\n        \"chooseGroup\": \"Вибрати групу\",\n        \"addToGroup\": \"Додати до ...\",\n        \"groupHint\": \"Двічі клацніть на групі, щоб редагувати джерела. Перетягніть, щоб змінити порядок.\"\n    },\n    \"rules\": {\n        \"intro\": \"Автоматично позначайте статті або надсилайте сповіщення регулярними виразами.\",\n        \"help\": \"Дізнатися більше\",\n        \"source\": \"Джерело\",\n        \"selectSource\": \"Виберіть джерело\",\n        \"new\": \"Нове правило\",\n        \"if\": \"Якщо\",\n        \"then\": \"Тоді\",\n        \"title\": \"Заголовок\",\n        \"content\": \"Вміст\",\n        \"fullSearch\": \"Заголовок та вміст\",\n        \"creator\": \"Автор\",\n        \"match\": \"якщо збігається\",\n        \"notMatch\": \"не збігається\",\n        \"regex\": \"Регулярний вираз (Regex)\",\n        \"badRegex\": \"Недійсний регулярний вираз. (Regex)\",\n        \"action\": \"Дії\",\n        \"selectAction\": \"Вибрати дії\",\n        \"hint\": \"Правила застосовуватимуться по порядку. Перетягніть, щоб змінити порядок.\",\n        \"test\": \"Тест правил\"\n    },\n    \"service\": {\n        \"intro\": \"Синхронізація між пристроями за допомогою служб RSS.\",\n        \"select\": \"Вибрати службу\",\n        \"suggest\": \"Запропонуйте нову службу\",\n        \"overwriteWarning\": \"Локальні джерела будуть видалені, якщо вони існують в службі.\",\n        \"groupsWarning\": \"Групи не синхронізуються автоматично зі службою.\",\n        \"rateLimitWarning\": \"Щоб уникнути обмеження швидкості, вам потрібно створити власний ключ API.\",\n        \"removeAd\": \"Видалити рекламу\",\n        \"endpoint\": \"Кінцева точка\",\n        \"username\": \"Ім'я користувача\",\n        \"password\": \"Пароль\",\n        \"unchanged\": \"Без змін\",\n        \"fetchLimit\": \"Обмеження синхронізації\",\n        \"fetchLimitNum\": \"{count} останніх статей\",\n        \"importGroups\": \"Імпортувати групи\",\n        \"failure\": \"Не вдається підключитися до служби\",\n        \"failureHint\": \"Будь ласка, перевірте конфігурацію служби або стан мережі.\",\n        \"fetchUnlimited\": \"Необмежений (не рекомендується)\",\n        \"exportToLite\": \"Експорт у програму Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"Прибирати\",\n        \"cache\": \"Очистити кеш\",\n        \"cacheSize\": \"Кешовано {size} даних\",\n        \"deleteChoices\": \"Видалити статті з ... днів тому\",\n        \"confirmDelete\": \"Видалити\",\n        \"daysAgo\": \"{days, plural, =1 {# день} other {# днів}} тому\",\n        \"deleteAll\": \"Видалити всі статті\",\n        \"calculatingSize\": \"Розрахунок розміру ...\",\n        \"itemSize\": \"Близько {size} локальної пам'яті займають статті\",\n        \"confirmImport\": \"Ви дійсно хочете імпортувати дані з файлу резервної копії? Усі поточні дані будуть знищені.\",\n        \"data\": \"Дані програми\",\n        \"backup\": \"Резервне копіювання\",\n        \"restore\": \"Відновити\",\n        \"frData\": \"Дані Fluent Reader\",\n        \"language\": \"Мова\",\n        \"theme\": \"Тема\",\n        \"lightTheme\": \"Світлий режим\",\n        \"darkTheme\": \"Темний режим\",\n        \"enableProxy\": \"Увімкнути Proxy\",\n        \"badUrl\": \"Недійсна URL-адреса\",\n        \"pac\": \"Адреса PAC\",\n        \"setPac\": \"Встановити PAC\",\n        \"pacHint\": \"Для проксі Socks рекомендується, щоб PAC повертав \\\"SOCKS5\\\" для DNS на стороні проксі. Для відключення проксі потрібне перезавантаження.\",\n        \"fetchInterval\": \"Інтервал автоматичної вибірки\",\n        \"never\": \"Ніколи\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/zh-CN.json",
    "content": "{\n    \"allArticles\": \"全部文章\",\n    \"add\": \"添加\",\n    \"create\": \"新建\",\n    \"icon\": \"图标\",\n    \"name\": \"名称\",\n    \"openExternal\": \"在浏览器中打开\",\n    \"emptyName\": \"名称不得为空\",\n    \"emptyField\": \"此项不得为空\",\n    \"edit\": \"编辑\",\n    \"delete\": \"删除\",\n    \"followSystem\": \"跟随系统\",\n    \"more\": \"更多\",\n    \"close\": \"关闭\",\n    \"search\": \"搜索\",\n    \"loadMore\": \"加载更多\",\n    \"dangerButton\": \"确认{action}？\",\n    \"confirmMarkAll\": \"确认将本页所有文章标为已读？\",\n    \"confirm\": \"确认\",\n    \"cancel\": \"取消\",\n    \"default\": \"默认\",\n    \"time\": {\n        \"now\": \"now\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m}分钟\",\n        \"hour\": \"{h}小时\",\n        \"day\": \"{d}天\"\n    },\n    \"log\": {\n        \"empty\": \"无消息\",\n        \"fetchFailure\": \"无法加载订阅源“{name}”\",\n        \"fetchSuccess\": \"成功加载 {count} 篇文章\",\n        \"networkError\": \"连接订阅源时出错\",\n        \"parseError\": \"解析XML信息流时出错\",\n        \"syncFailure\": \"无法与服务同步\"\n    },\n    \"nav\": {\n        \"menu\": \"菜单\",\n        \"refresh\": \"刷新\",\n        \"markAllRead\": \"全部标为已读\",\n        \"notifications\": \"消息\",\n        \"view\": \"视图\",\n        \"settings\": \"选项\",\n        \"minimize\": \"最小化\",\n        \"maximize\": \"最大化\"\n    },\n    \"menu\": {\n        \"close\": \"关闭菜单\",\n        \"subscriptions\": \"订阅源\"\n    },\n    \"article\": {\n        \"error\": \"文章加载失败\",\n        \"reload\": \"重新加载\",\n        \"empty\": \"无文章\",\n        \"untitled\": \"（无标题）\",\n        \"hide\": \"隐藏文章\",\n        \"unhide\": \"取消隐藏\",\n        \"markRead\": \"标为已读\",\n        \"markUnread\": \"标为未读\",\n        \"markAbove\": \"将以上标为已读\",\n        \"markBelow\": \"将以下标为已读\",\n        \"star\": \"标为星标\",\n        \"unstar\": \"取消星标\",\n        \"fontSize\": \"字体大小\",\n        \"loadWebpage\": \"加载网页\",\n        \"loadFull\": \"抓取全文\",\n        \"notify\": \"后台抓取时发送通知\",\n        \"dontNotify\": \"不发送通知\",\n        \"textDir\": \"文本方向\",\n        \"LTR\": \"从左到右\",\n        \"RTL\": \"从右到左\",\n        \"Vertical\": \"纵书\",\n        \"font\": \"字体\"\n    },\n    \"context\": {\n        \"share\": \"分享\",\n        \"read\": \"阅读\",\n        \"copyTitle\": \"复制标题\",\n        \"copyURL\": \"复制链接\",\n        \"copy\": \"复制\",\n        \"search\": \"使用 {engine} 搜索“{text}”\",\n        \"view\": \"视图\",\n        \"cardView\": \"卡片视图\",\n        \"listView\": \"列表视图\",\n        \"magazineView\": \"杂志视图\",\n        \"compactView\": \"紧凑视图\",\n        \"filter\": \"筛选\",\n        \"unreadOnly\": \"仅未读文章\",\n        \"starredOnly\": \"仅星标文章\",\n        \"fullSearch\": \"在正文中搜索\",\n        \"showHidden\": \"显示隐藏文章\",\n        \"manageSources\": \"管理订阅源\",\n        \"saveImageAs\": \"将图像另存为\",\n        \"copyImage\": \"复制图像\",\n        \"copyImageURL\": \"复制图像链接\",\n        \"caseSensitive\": \"区分大小写\",\n        \"showCover\": \"显示封面\",\n        \"showSnippet\": \"显示摘要\",\n        \"fadeRead\": \"淡化已读文章\"\n    },\n    \"searchEngine\": {\n        \"name\": \"搜索引擎\",\n        \"bing\": \"必应\",\n        \"baidu\": \"百度\"\n    },\n    \"settings\": {\n        \"writeError\": \"写入文件时发生错误\",\n        \"name\": \"选项\",\n        \"fetching\": \"正在更新订阅源，请稍候…\",\n        \"exit\": \"退出选项\",\n        \"sources\": \"订阅源\",\n        \"grouping\": \"分组与排序\",\n        \"rules\": \"规则\",\n        \"service\": \"服务\",\n        \"app\": \"应用偏好\",\n        \"about\": \"关于\",\n        \"version\": \"版本\",\n        \"shortcuts\": \"快捷键\",\n        \"openSource\": \"开源项目\",\n        \"feedback\": \"反馈\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"此处导入或添加的订阅源将不会与服务端同步\",\n        \"serviceManaged\": \"该订阅源由服务端管理\",\n        \"untitled\": \"订阅源\",\n        \"errorAdd\": \"添加订阅源时出错\",\n        \"errorParse\": \"解析OPML文件时出错\",\n        \"errorParseHint\": \"请确保OPML文件完整且使用UTF-8编码。\",\n        \"errorImport\": \"导入{count}项订阅源时出错\",\n        \"exist\": \"该订阅源已存在\",\n        \"opmlFile\": \"OPML文件\",\n        \"name\": \"订阅源名称\",\n        \"editName\": \"修改名称\",\n        \"fetchFrequency\": \"抓取频率限制\",\n        \"unlimited\": \"无限制\",\n        \"openTarget\": \"订阅源文章打开方式\",\n        \"delete\": \"删除订阅源\",\n        \"add\": \"添加订阅源\",\n        \"import\": \"导入文件\",\n        \"export\": \"导出文件\",\n        \"rssText\": \"RSS正文\",\n        \"loadWebpage\": \"加载网页\",\n        \"inputUrl\": \"输入URL\",\n        \"badIcon\": \"图标不存在或非图片\",\n        \"badUrl\": \"请正确输入URL\",\n        \"deleteWarning\": \"这将移除订阅源与所有已保存的文章\",\n        \"selected\": \"选中订阅源\",\n        \"selectedMulti\": \"选中多个订阅源\",\n        \"hidden\": \"从“全部文章”中隐藏\"\n    },\n    \"groups\": {\n        \"exist\": \"该分组已存在\",\n        \"type\": \"类型\",\n        \"group\": \"分组\",\n        \"source\": \"订阅源\",\n        \"capacity\": \"容量\",\n        \"exitGroup\": \"退出分组\",\n        \"deleteSource\": \"从分组删除订阅源\",\n        \"sourceHint\": \"拖拽订阅源以排序\",\n        \"create\": \"新建分组\",\n        \"selectedGroup\": \"选中分组\",\n        \"selectedSource\": \"选中订阅源\",\n        \"enterName\": \"输入名称\",\n        \"editName\": \"修改名称\",\n        \"deleteGroup\": \"删除分组\",\n        \"chooseGroup\": \"选择分组\",\n        \"addToGroup\": \"添加至分组\",\n        \"groupHint\": \"双击分组以修改订阅源，可通过拖拽排序\"\n    },\n    \"rules\": {\n        \"intro\": \"通过正则表达式自动标记文章或推送通知\",\n        \"help\": \"了解更多\",\n        \"source\": \"订阅源\",\n        \"selectSource\": \"选择一个订阅源\",\n        \"new\": \"新建规则\",\n        \"if\": \"若\",\n        \"then\": \"则\",\n        \"title\": \"标题\",\n        \"content\": \"正文\",\n        \"fullSearch\": \"标题或正文\",\n        \"creator\": \"作者\",\n        \"match\": \"匹配\",\n        \"notMatch\": \"不匹配\",\n        \"regex\": \"正则表达式\",\n        \"badRegex\": \"正则表达式非法\",\n        \"action\": \"行为\",\n        \"selectAction\": \"选择行为\",\n        \"hint\": \"规则将按顺序执行，拖拽以排序\",\n        \"test\": \"测试规则\"\n    },\n    \"service\": {\n        \"intro\": \"通过 RSS 服务跨设备保持同步\",\n        \"select\": \"选择服务\",\n        \"suggest\": \"建议一项新服务\",\n        \"overwriteWarning\": \"若本地与服务端存在URL相同的订阅源，则本地订阅源将被删除\",\n        \"groupsWarning\": \"分组不会自动与服务端保持同步\",\n        \"rateLimitWarning\": \"为避免限流，您需要新建自己的 API Key\",\n        \"removeAd\": \"移除广告\",\n        \"endpoint\": \"端点\",\n        \"username\": \"用户名\",\n        \"password\": \"密码\",\n        \"unchanged\": \"未更改\",\n        \"fetchLimit\": \"同步数量\",\n        \"fetchLimitNum\": \"最近 {count} 篇文章\",\n        \"importGroups\": \"导入分组\",\n        \"failure\": \"连接到服务时出错\",\n        \"failureHint\": \"请检查服务配置或网络连接\",\n        \"fetchUnlimited\": \"无限制（不建议）\",\n        \"exportToLite\": \"导出至 Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"清理\",\n        \"cache\": \"清空缓存\",\n        \"cacheSize\": \"已缓存{size}数据\",\n        \"deleteChoices\": \"删除 … 天前的文章\",\n        \"confirmDelete\": \"删除文章\",\n        \"daysAgo\": \"{days} 天前\",\n        \"deleteAll\": \"删除全部文章\",\n        \"calculatingSize\": \"正在计算占用空间…\",\n        \"itemSize\": \"本地文章约占用{size}空间\",\n        \"confirmImport\": \"确认要从备份文件导入数据吗？这将清除所有应用数据。\",\n        \"data\": \"应用数据\",\n        \"backup\": \"备份\",\n        \"restore\": \"还原\",\n        \"frData\": \"Fluent Reader数据\",\n        \"language\": \"界面语言\",\n        \"theme\": \"应用主题\",\n        \"lightTheme\": \"浅色模式\",\n        \"darkTheme\": \"深色模式\",\n        \"enableProxy\": \"启用代理\",\n        \"badUrl\": \"请正确输入URL\",\n        \"pac\": \"PAC地址\",\n        \"setPac\": \"设置PAC\",\n        \"pacHint\": \"对于Socks代理建议PAC返回“SOCKS5”以启用代理端解析。关闭代理需重启应用后生效。\",\n        \"fetchInterval\": \"自动抓取频率\",\n        \"never\": \"从不\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/i18n/zh-TW.json",
    "content": "{\n    \"allArticles\": \"全部文章\",\n    \"add\": \"新增\",\n    \"create\": \"新建\",\n    \"icon\": \"圖示\",\n    \"name\": \"名稱\",\n    \"openExternal\": \"在瀏覽器中開啟\",\n    \"emptyName\": \"名稱不得為空\",\n    \"emptyField\": \"此項不得為空\",\n    \"edit\": \"編輯\",\n    \"delete\": \"刪除\",\n    \"followSystem\": \"跟隨系統\",\n    \"more\": \"更多\",\n    \"close\": \"關閉\",\n    \"search\": \"搜尋\",\n    \"loadMore\": \"載入更多\",\n    \"dangerButton\": \"確認{action}？\",\n    \"confirmMarkAll\": \"確認將本頁所有文章標為已讀？\",\n    \"confirm\": \"確認\",\n    \"cancel\": \"取消\",\n    \"default\": \"預設\",\n    \"time\": {\n        \"now\": \"now\",\n        \"m\": \"m\",\n        \"h\": \"h\",\n        \"d\": \"d\",\n        \"minute\": \"{m}分鐘\",\n        \"hour\": \"{h}小時\",\n        \"day\": \"{d}天\"\n    },\n    \"log\": {\n        \"empty\": \"無訊息\",\n        \"fetchFailure\": \"無法載入訂閱源“{name}”\",\n        \"fetchSuccess\": \"成功載入 {count} 篇文章\",\n        \"networkError\": \"連線訂閱源時出錯\",\n        \"parseError\": \"解析XML資訊流時出錯\",\n        \"syncFailure\": \"無法與服務同步\"\n    },\n    \"nav\": {\n        \"menu\": \"選單\",\n        \"refresh\": \"重新整理\",\n        \"markAllRead\": \"全部標為已讀\",\n        \"notifications\": \"訊息\",\n        \"view\": \"檢視\",\n        \"settings\": \"選項\",\n        \"minimize\": \"最小化\",\n        \"maximize\": \"最大化\"\n    },\n    \"menu\": {\n        \"close\": \"關閉選單\",\n        \"subscriptions\": \"訂閱源\"\n    },\n    \"article\": {\n        \"error\": \"文章載入失敗\",\n        \"reload\": \"重新載入\",\n        \"empty\": \"無文章\",\n        \"untitled\": \"（無標題）\",\n        \"hide\": \"隱藏文章\",\n        \"unhide\": \"取消隱藏\",\n        \"markRead\": \"標為已讀\",\n        \"markUnread\": \"標為未讀\",\n        \"markAbove\": \"將以上標為已讀\",\n        \"markBelow\": \"將以下標為已讀\",\n        \"star\": \"標為星標\",\n        \"unstar\": \"取消星標\",\n        \"fontSize\": \"字型大小\",\n        \"loadWebpage\": \"載入網頁\",\n        \"loadFull\": \"抓取全文\",\n        \"notify\": \"後臺抓取時傳送通知\",\n        \"dontNotify\": \"不傳送通知\",\n        \"textDir\": \"文本方向\",\n        \"LTR\": \"從左到右\",\n        \"RTL\": \"從右到左\",\n        \"Vertical\": \"縱書\",\n        \"font\": \"字體\"\n    },\n    \"context\": {\n        \"share\": \"分享\",\n        \"read\": \"閱讀\",\n        \"copyTitle\": \"複製標題\",\n        \"copyURL\": \"複製連結\",\n        \"copy\": \"複製\",\n        \"search\": \"使用 {engine} 搜尋“{text}”\",\n        \"view\": \"檢視\",\n        \"cardView\": \"卡片檢視\",\n        \"listView\": \"列表檢視\",\n        \"magazineView\": \"雜誌檢視\",\n        \"compactView\": \"緊湊檢視\",\n        \"filter\": \"篩選\",\n        \"unreadOnly\": \"僅未讀文章\",\n        \"starredOnly\": \"僅星標文章\",\n        \"fullSearch\": \"在正文中搜尋\",\n        \"showHidden\": \"顯示隱藏文章\",\n        \"manageSources\": \"管理訂閱源\",\n        \"saveImageAs\": \"將影象另存為\",\n        \"copyImage\": \"複製影象\",\n        \"copyImageURL\": \"複製影象連結\",\n        \"caseSensitive\": \"區分大小寫\",\n        \"showCover\": \"顯示封面\",\n        \"showSnippet\": \"顯示摘要\",\n        \"fadeRead\": \"淡化已讀文章\"\n    },\n    \"searchEngine\": {\n        \"name\": \"搜尋引擎\",\n        \"bing\": \"必應\",\n        \"baidu\": \"百度\"\n    },\n    \"settings\": {\n        \"writeError\": \"寫入檔案時發生錯誤\",\n        \"name\": \"選項\",\n        \"fetching\": \"正在更新訂閱源，請稍候…\",\n        \"exit\": \"退出選項\",\n        \"sources\": \"訂閱源\",\n        \"grouping\": \"分組與排序\",\n        \"rules\": \"規則\",\n        \"service\": \"服務\",\n        \"app\": \"應用偏好\",\n        \"about\": \"關於\",\n        \"version\": \"版本\",\n        \"shortcuts\": \"快捷鍵\",\n        \"openSource\": \"開源項目\",\n        \"feedback\": \"反饋\"\n    },\n    \"sources\": {\n        \"serviceWarning\": \"此處匯入或新增的訂閱源將不會與服務端同步\",\n        \"serviceManaged\": \"該訂閱源由服務端管理\",\n        \"untitled\": \"訂閱源\",\n        \"errorAdd\": \"新增訂閱源時出錯\",\n        \"errorParse\": \"解析OPML檔案時出錯\",\n        \"errorParseHint\": \"請確保OPML檔案完整且使用UTF-8編碼。\",\n        \"errorImport\": \"匯入{count}項訂閱源時出錯\",\n        \"exist\": \"該訂閱源已存在\",\n        \"opmlFile\": \"OPML檔案\",\n        \"name\": \"訂閱源名稱\",\n        \"editName\": \"修改名稱\",\n        \"fetchFrequency\": \"抓取頻率限制\",\n        \"unlimited\": \"無限制\",\n        \"openTarget\": \"訂閱源文章開啟方式\",\n        \"delete\": \"刪除訂閱源\",\n        \"add\": \"新增訂閱源\",\n        \"import\": \"匯入檔案\",\n        \"export\": \"匯出檔案\",\n        \"rssText\": \"RSS正文\",\n        \"loadWebpage\": \"載入網頁\",\n        \"inputUrl\": \"輸入URL\",\n        \"badIcon\": \"圖示不存在或非圖片\",\n        \"badUrl\": \"請正確輸入URL\",\n        \"deleteWarning\": \"這將移除訂閱源與所有已儲存的文章\",\n        \"selected\": \"選中訂閱源\",\n        \"selectedMulti\": \"選中多個訂閱源\",\n        \"hidden\": \"從“全部文章”中隱藏\"\n    },\n    \"groups\": {\n        \"exist\": \"該分組已存在\",\n        \"type\": \"類型\",\n        \"group\": \"分組\",\n        \"source\": \"訂閱源\",\n        \"capacity\": \"容量\",\n        \"exitGroup\": \"退出分組\",\n        \"deleteSource\": \"從分組刪除訂閱源\",\n        \"sourceHint\": \"拖拽訂閱源以排序\",\n        \"create\": \"新建分組\",\n        \"selectedGroup\": \"選中分組\",\n        \"selectedSource\": \"選中訂閱源\",\n        \"enterName\": \"輸入名稱\",\n        \"editName\": \"修改名稱\",\n        \"deleteGroup\": \"刪除分組\",\n        \"chooseGroup\": \"選擇分組\",\n        \"addToGroup\": \"新增至分組\",\n        \"groupHint\": \"雙擊分組以修改訂閱源，可通過拖拽排序\"\n    },\n    \"rules\": {\n        \"intro\": \"通過正規表示式自動標記文章或推送通知\",\n        \"help\": \"瞭解更多\",\n        \"source\": \"訂閱源\",\n        \"selectSource\": \"選擇一個訂閱源\",\n        \"new\": \"新建規則\",\n        \"if\": \"若\",\n        \"then\": \"則\",\n        \"title\": \"標題\",\n        \"content\": \"正文\",\n        \"fullSearch\": \"標題或正文\",\n        \"creator\": \"作者\",\n        \"match\": \"匹配\",\n        \"notMatch\": \"不匹配\",\n        \"regex\": \"正規表示式\",\n        \"badRegex\": \"正規表示式非法\",\n        \"action\": \"行為\",\n        \"selectAction\": \"選擇行為\",\n        \"hint\": \"規則將按順序執行，拖拽以排序\",\n        \"test\": \"測試規則\"\n    },\n    \"service\": {\n        \"intro\": \"通過 RSS 服務跨裝置保持同步\",\n        \"select\": \"選擇服務\",\n        \"suggest\": \"建議一項新服務\",\n        \"overwriteWarning\": \"若本地與服務端存在URL相同的訂閱源，則本地訂閱源將被刪除\",\n        \"groupsWarning\": \"分組不會自動與服務端保持同步\",\n        \"rateLimitWarning\": \"為避免限流，您需要新建自己的 API Key\",\n        \"removeAd\": \"移除廣告\",\n        \"endpoint\": \"端點\",\n        \"username\": \"使用者名稱\",\n        \"password\": \"密碼\",\n        \"unchanged\": \"未更改\",\n        \"fetchLimit\": \"同步數量\",\n        \"fetchLimitNum\": \"最近 {count} 篇文章\",\n        \"importGroups\": \"匯入分組\",\n        \"failure\": \"連線到服務時出錯\",\n        \"failureHint\": \"請檢查服務配置或網路連線\",\n        \"fetchUnlimited\": \"無限制（不建議）\",\n        \"exportToLite\": \"匯出至 Fluent Reader Lite\"\n    },\n    \"app\": {\n        \"cleanup\": \"清理\",\n        \"cache\": \"清空快取\",\n        \"cacheSize\": \"已快取{size}資料\",\n        \"deleteChoices\": \"刪除 … 天前的文章\",\n        \"confirmDelete\": \"刪除文章\",\n        \"daysAgo\": \"{days} 天前\",\n        \"deleteAll\": \"刪除全部文章\",\n        \"calculatingSize\": \"正在計算佔用空間…\",\n        \"itemSize\": \"本地文章約佔用{size}空間\",\n        \"confirmImport\": \"確認要從備份檔案匯入資料嗎？這將清除所有應用資料。\",\n        \"data\": \"應用資料\",\n        \"backup\": \"備份\",\n        \"restore\": \"還原\",\n        \"frData\": \"Fluent Reader資料\",\n        \"language\": \"介面語言\",\n        \"theme\": \"應用主題\",\n        \"lightTheme\": \"淺色模式\",\n        \"darkTheme\": \"深色模式\",\n        \"enableProxy\": \"啟用代理\",\n        \"badUrl\": \"請正確輸入URL\",\n        \"pac\": \"PAC地址\",\n        \"setPac\": \"設定PAC\",\n        \"pacHint\": \"對於Socks代理建議PAC返回“SOCKS5”以啟用代理端解析。關閉代理需重啟應用後生效。\",\n        \"fetchInterval\": \"自動抓取頻率\",\n        \"never\": \"從不\"\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/app.ts",
    "content": "import intl from \"react-intl-universal\"\nimport {\n    INIT_SOURCES,\n    SourceActionTypes,\n    ADD_SOURCE,\n    UPDATE_SOURCE,\n    DELETE_SOURCE,\n    initSources,\n    SourceOpenTarget,\n    updateFavicon,\n} from \"./source\"\nimport { RSSItem, ItemActionTypes, FETCH_ITEMS, fetchItems } from \"./item\"\nimport {\n    ActionStatus,\n    AppThunk,\n    getWindowBreakpoint,\n    initTouchBarWithTexts,\n} from \"../utils\"\nimport { INIT_FEEDS, FeedActionTypes, ALL, initFeeds } from \"./feed\"\nimport {\n    SourceGroupActionTypes,\n    UPDATE_SOURCE_GROUP,\n    ADD_SOURCE_TO_GROUP,\n    DELETE_SOURCE_GROUP,\n    REMOVE_SOURCE_FROM_GROUP,\n    REORDER_SOURCE_GROUPS,\n} from \"./group\"\nimport {\n    PageActionTypes,\n    SELECT_PAGE,\n    PageType,\n    selectAllArticles,\n    showItemFromId,\n} from \"./page\"\nimport { getCurrentLocale, setThemeDefaultFont } from \"../settings\"\nimport locales from \"../i18n/_locales\"\nimport { SYNC_SERVICE, ServiceActionTypes } from \"./service\"\n\nexport const enum ContextMenuType {\n    Hidden,\n    Item,\n    Text,\n    View,\n    Group,\n    Image,\n    MarkRead,\n}\n\nexport const enum AppLogType {\n    Info,\n    Warning,\n    Failure,\n    Article,\n}\n\nexport class AppLog {\n    type: AppLogType\n    title: string\n    details?: string\n    iid?: number\n    time: Date\n\n    constructor(\n        type: AppLogType,\n        title: string,\n        details: string = null,\n        iid: number = null\n    ) {\n        this.type = type\n        this.title = title\n        this.details = details\n        this.iid = iid\n        this.time = new Date()\n    }\n}\n\nexport class AppState {\n    locale = null as string\n    sourceInit = false\n    feedInit = false\n    syncing = false\n    fetchingItems = false\n    fetchingProgress = 0\n    fetchingTotal = 0\n    lastFetched = new Date()\n    menu = getWindowBreakpoint() && window.settings.getDefaultMenu()\n    menuKey = ALL\n    title = \"\"\n    settings = {\n        display: false,\n        changed: false,\n        sids: new Array<number>(),\n        saving: false,\n    }\n    logMenu = {\n        display: false,\n        notify: false,\n        logs: new Array<AppLog>(),\n    }\n\n    contextMenu: {\n        type: ContextMenuType\n        event?: MouseEvent | string\n        position?: [number, number]\n        target?: [RSSItem, string] | number[] | [string, string]\n    }\n\n    constructor() {\n        this.contextMenu = {\n            type: ContextMenuType.Hidden,\n        }\n    }\n}\n\nexport const CLOSE_CONTEXT_MENU = \"CLOSE_CONTEXT_MENU\"\nexport const OPEN_ITEM_MENU = \"OPEN_ITEM_MENU\"\nexport const OPEN_TEXT_MENU = \"OPEN_TEXT_MENU\"\nexport const OPEN_VIEW_MENU = \"OPEN_VIEW_MENU\"\nexport const OPEN_GROUP_MENU = \"OPEN_GROUP_MENU\"\nexport const OPEN_IMAGE_MENU = \"OPEN_IMAGE_MENU\"\nexport const OPEN_MARK_ALL_MENU = \"OPEN_MARK_ALL_MENU\"\n\ninterface CloseContextMenuAction {\n    type: typeof CLOSE_CONTEXT_MENU\n}\n\ninterface OpenItemMenuAction {\n    type: typeof OPEN_ITEM_MENU\n    event: MouseEvent\n    item: RSSItem\n    feedId: string\n}\n\ninterface OpenTextMenuAction {\n    type: typeof OPEN_TEXT_MENU\n    position: [number, number]\n    item: [string, string]\n}\n\ninterface OpenViewMenuAction {\n    type: typeof OPEN_VIEW_MENU\n}\n\ninterface OpenMarkAllMenuAction {\n    type: typeof OPEN_MARK_ALL_MENU\n}\n\ninterface OpenGroupMenuAction {\n    type: typeof OPEN_GROUP_MENU\n    event: MouseEvent\n    sids: number[]\n}\n\ninterface OpenImageMenuAction {\n    type: typeof OPEN_IMAGE_MENU\n    position: [number, number]\n}\n\nexport type ContextMenuActionTypes =\n    | CloseContextMenuAction\n    | OpenItemMenuAction\n    | OpenTextMenuAction\n    | OpenViewMenuAction\n    | OpenGroupMenuAction\n    | OpenImageMenuAction\n    | OpenMarkAllMenuAction\n\nexport const TOGGLE_LOGS = \"TOGGLE_LOGS\"\nexport const PUSH_NOTIFICATION = \"PUSH_NOTIFICATION\"\n\ninterface ToggleLogMenuAction {\n    type: typeof TOGGLE_LOGS\n}\n\ninterface PushNotificationAction {\n    type: typeof PUSH_NOTIFICATION\n    iid: number\n    title: string\n    source: string\n}\n\nexport type LogMenuActionType = ToggleLogMenuAction | PushNotificationAction\n\nexport const TOGGLE_MENU = \"TOGGLE_MENU\"\n\nexport interface MenuActionTypes {\n    type: typeof TOGGLE_MENU\n}\n\nexport const TOGGLE_SETTINGS = \"TOGGLE_SETTINGS\"\nexport const SAVE_SETTINGS = \"SAVE_SETTINGS\"\nexport const FREE_MEMORY = \"FREE_MEMORY\"\n\ninterface ToggleSettingsAction {\n    type: typeof TOGGLE_SETTINGS\n    open: boolean\n    sids: number[]\n}\ninterface SaveSettingsAction {\n    type: typeof SAVE_SETTINGS\n}\ninterface FreeMemoryAction {\n    type: typeof FREE_MEMORY\n    iids: Set<number>\n}\nexport type SettingsActionTypes =\n    | ToggleSettingsAction\n    | SaveSettingsAction\n    | FreeMemoryAction\n\nexport function closeContextMenu(): AppThunk {\n    return (dispatch, getState) => {\n        if (getState().app.contextMenu.type !== ContextMenuType.Hidden) {\n            dispatch({ type: CLOSE_CONTEXT_MENU })\n        }\n    }\n}\n\nexport function openItemMenu(\n    item: RSSItem,\n    feedId: string,\n    event: React.MouseEvent\n): ContextMenuActionTypes {\n    return {\n        type: OPEN_ITEM_MENU,\n        event: event.nativeEvent,\n        item: item,\n        feedId: feedId,\n    }\n}\n\nexport function openTextMenu(\n    position: [number, number],\n    text: string,\n    url: string = null\n): ContextMenuActionTypes {\n    return {\n        type: OPEN_TEXT_MENU,\n        position: position,\n        item: [text, url],\n    }\n}\n\nexport const openViewMenu = (): ContextMenuActionTypes => ({\n    type: OPEN_VIEW_MENU,\n})\n\nexport function openGroupMenu(\n    sids: number[],\n    event: React.MouseEvent\n): ContextMenuActionTypes {\n    return {\n        type: OPEN_GROUP_MENU,\n        event: event.nativeEvent,\n        sids: sids,\n    }\n}\n\nexport function openImageMenu(\n    position: [number, number]\n): ContextMenuActionTypes {\n    return {\n        type: OPEN_IMAGE_MENU,\n        position: position,\n    }\n}\n\nexport const openMarkAllMenu = (): ContextMenuActionTypes => ({\n    type: OPEN_MARK_ALL_MENU,\n})\n\nexport function toggleMenu(): AppThunk {\n    return (dispatch, getState) => {\n        dispatch({ type: TOGGLE_MENU })\n        window.settings.setDefaultMenu(getState().app.menu)\n    }\n}\n\nexport const toggleLogMenu = () => ({ type: TOGGLE_LOGS })\nexport const saveSettings = () => ({ type: SAVE_SETTINGS })\n\nexport const toggleSettings = (open = true, sids = new Array<number>()) => ({\n    type: TOGGLE_SETTINGS,\n    open: open,\n    sids: sids,\n})\n\nexport function exitSettings(): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        if (!getState().app.settings.saving) {\n            if (getState().app.settings.changed) {\n                dispatch(saveSettings())\n                dispatch(selectAllArticles(true))\n                await dispatch(initFeeds(true))\n                dispatch(toggleSettings(false))\n                freeMemory()\n            } else {\n                dispatch(toggleSettings(false))\n            }\n        }\n    }\n}\n\nfunction freeMemory(): AppThunk {\n    return (dispatch, getState) => {\n        const iids = new Set<number>()\n        for (let feed of Object.values(getState().feeds)) {\n            if (feed.loaded) feed.iids.forEach(iids.add, iids)\n        }\n        dispatch({\n            type: FREE_MEMORY,\n            iids: iids,\n        })\n    }\n}\n\nlet fetchTimeout: NodeJS.Timeout\nexport function setupAutoFetch(): AppThunk {\n    return (dispatch, getState) => {\n        clearTimeout(fetchTimeout)\n        const setupTimeout = (interval?: number) => {\n            if (!interval) interval = window.settings.getFetchInterval()\n            if (interval) {\n                fetchTimeout = setTimeout(() => {\n                    let state = getState()\n                    if (!state.app.settings.display) {\n                        if (!state.app.fetchingItems) dispatch(fetchItems(true))\n                    } else {\n                        setupTimeout(1)\n                    }\n                }, interval * 60000)\n            }\n        }\n        setupTimeout()\n    }\n}\n\nexport function pushNotification(item: RSSItem): AppThunk {\n    return (dispatch, getState) => {\n        const sourceName = getState().sources[item.source].name\n        if (!window.utils.isFocused()) {\n            const options = { body: sourceName } as any\n            if (item.thumb) options.icon = item.thumb\n            const notification = new Notification(item.title, options)\n            notification.onclick = () => {\n                const state = getState()\n                if (\n                    state.sources[item.source].openTarget ===\n                    SourceOpenTarget.External\n                ) {\n                    window.utils.openExternal(item.link)\n                } else if (!state.app.settings.display) {\n                    window.utils.focus()\n                    dispatch(showItemFromId(item._id))\n                }\n            }\n        }\n        dispatch({\n            type: PUSH_NOTIFICATION,\n            iid: item._id,\n            title: item.title,\n            source: sourceName,\n        })\n    }\n}\n\nexport const INIT_INTL = \"INIT_INTL\"\nexport interface InitIntlAction {\n    type: typeof INIT_INTL\n    locale: string\n}\nexport const initIntlDone = (locale: string): InitIntlAction => {\n    document.documentElement.lang = locale\n    setThemeDefaultFont(locale)\n    return {\n        type: INIT_INTL,\n        locale: locale,\n    }\n}\n\nexport function initIntl(): AppThunk<Promise<void>> {\n    return dispatch => {\n        let locale = getCurrentLocale()\n        return intl\n            .init({\n                currentLocale: locale,\n                locales: locales,\n                fallbackLocale: \"en-US\",\n            })\n            .then(() => {\n                dispatch(initIntlDone(locale))\n            })\n    }\n}\n\nexport function initApp(): AppThunk {\n    return dispatch => {\n        document.body.classList.add(window.utils.platform)\n        dispatch(initIntl())\n            .then(async () => {\n                if (window.utils.platform === \"darwin\") initTouchBarWithTexts()\n                await dispatch(initSources())\n            })\n            .then(() => dispatch(initFeeds()))\n            .then(async () => {\n                dispatch(selectAllArticles())\n                await dispatch(fetchItems())\n            })\n            .then(() => {\n                dispatch(updateFavicon())\n            })\n    }\n}\n\nexport function appReducer(\n    state = new AppState(),\n    action:\n        | SourceActionTypes\n        | ItemActionTypes\n        | ContextMenuActionTypes\n        | SettingsActionTypes\n        | InitIntlAction\n        | MenuActionTypes\n        | LogMenuActionType\n        | FeedActionTypes\n        | PageActionTypes\n        | SourceGroupActionTypes\n        | ServiceActionTypes\n): AppState {\n    switch (action.type) {\n        case INIT_INTL:\n            return {\n                ...state,\n                locale: action.locale,\n            }\n        case INIT_SOURCES:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        sourceInit: true,\n                    }\n                default:\n                    return state\n            }\n        case ADD_SOURCE:\n            switch (action.status) {\n                case ActionStatus.Request:\n                    return {\n                        ...state,\n                        fetchingItems: true,\n                        settings: {\n                            ...state.settings,\n                            changed: true,\n                            saving: true,\n                        },\n                    }\n                default:\n                    return {\n                        ...state,\n                        fetchingItems: state.fetchingTotal !== 0,\n                        settings: {\n                            ...state.settings,\n                            saving: action.batch,\n                        },\n                    }\n            }\n        case UPDATE_SOURCE:\n        case DELETE_SOURCE:\n        case UPDATE_SOURCE_GROUP:\n        case ADD_SOURCE_TO_GROUP:\n        case REMOVE_SOURCE_FROM_GROUP:\n        case REORDER_SOURCE_GROUPS:\n        case DELETE_SOURCE_GROUP:\n            return {\n                ...state,\n                settings: {\n                    ...state.settings,\n                    changed: true,\n                },\n            }\n        case INIT_FEEDS:\n            switch (action.status) {\n                case ActionStatus.Request:\n                    return state\n                default:\n                    return {\n                        ...state,\n                        feedInit: true,\n                    }\n            }\n        case SYNC_SERVICE:\n            switch (action.status) {\n                case ActionStatus.Request:\n                    return {\n                        ...state,\n                        syncing: true,\n                    }\n                case ActionStatus.Failure:\n                    return {\n                        ...state,\n                        syncing: false,\n                        logMenu: {\n                            ...state.logMenu,\n                            notify: true,\n                            logs: [\n                                ...state.logMenu.logs,\n                                new AppLog(\n                                    AppLogType.Failure,\n                                    intl.get(\"log.syncFailure\"),\n                                    String(action.err)\n                                ),\n                            ],\n                        },\n                    }\n                default:\n                    return {\n                        ...state,\n                        syncing: false,\n                    }\n            }\n        case FETCH_ITEMS:\n            switch (action.status) {\n                case ActionStatus.Request:\n                    return {\n                        ...state,\n                        fetchingItems: true,\n                        fetchingProgress: 0,\n                        fetchingTotal: action.fetchCount,\n                    }\n                case ActionStatus.Failure:\n                    return {\n                        ...state,\n                        logMenu: {\n                            ...state.logMenu,\n                            notify: !state.logMenu.display,\n                            logs: [\n                                ...state.logMenu.logs,\n                                new AppLog(\n                                    AppLogType.Failure,\n                                    intl.get(\"log.fetchFailure\", {\n                                        name: action.errSource.name,\n                                    }),\n                                    String(action.err)\n                                ),\n                            ],\n                        },\n                    }\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        fetchingItems: false,\n                        fetchingTotal: 0,\n                        logMenu:\n                            action.items.length == 0\n                                ? state.logMenu\n                                : {\n                                      ...state.logMenu,\n                                      logs: [\n                                          ...state.logMenu.logs,\n                                          new AppLog(\n                                              AppLogType.Info,\n                                              intl.get(\"log.fetchSuccess\", {\n                                                  count: action.items.length,\n                                              })\n                                          ),\n                                      ],\n                                  },\n                    }\n                case ActionStatus.Intermediate:\n                    return {\n                        ...state,\n                        fetchingProgress: state.fetchingProgress + 1,\n                    }\n                default:\n                    return state\n            }\n        case SELECT_PAGE:\n            switch (action.pageType) {\n                case PageType.AllArticles:\n                    return {\n                        ...state,\n                        menu: state.menu && action.keepMenu,\n                        menuKey: ALL,\n                        title: intl.get(\"allArticles\"),\n                    }\n                case PageType.Sources:\n                    return {\n                        ...state,\n                        menu: state.menu && action.keepMenu,\n                        menuKey: action.menuKey,\n                        title: action.title,\n                    }\n            }\n        case CLOSE_CONTEXT_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type: ContextMenuType.Hidden,\n                },\n            }\n        case OPEN_ITEM_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type: ContextMenuType.Item,\n                    event: action.event,\n                    target: [action.item, action.feedId],\n                },\n            }\n        case OPEN_TEXT_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type: ContextMenuType.Text,\n                    position: action.position,\n                    target: action.item,\n                },\n            }\n        case OPEN_VIEW_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type:\n                        state.contextMenu.type === ContextMenuType.View\n                            ? ContextMenuType.Hidden\n                            : ContextMenuType.View,\n                    event: \"#view-toggle\",\n                },\n            }\n        case OPEN_GROUP_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type: ContextMenuType.Group,\n                    event: action.event,\n                    target: action.sids,\n                },\n            }\n        case OPEN_IMAGE_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type: ContextMenuType.Image,\n                    position: action.position,\n                },\n            }\n        case OPEN_MARK_ALL_MENU:\n            return {\n                ...state,\n                contextMenu: {\n                    type:\n                        state.contextMenu.type === ContextMenuType.MarkRead\n                            ? ContextMenuType.Hidden\n                            : ContextMenuType.MarkRead,\n                    event: \"#mark-all-toggle\",\n                },\n            }\n        case TOGGLE_MENU:\n            return {\n                ...state,\n                menu: !state.menu,\n            }\n        case SAVE_SETTINGS:\n            return {\n                ...state,\n                settings: {\n                    ...state.settings,\n                    display: true,\n                    changed: true,\n                    saving: !state.settings.saving,\n                },\n            }\n        case TOGGLE_SETTINGS:\n            return {\n                ...state,\n                settings: {\n                    display: action.open,\n                    changed: false,\n                    sids: action.sids,\n                    saving: false,\n                },\n            }\n        case TOGGLE_LOGS:\n            return {\n                ...state,\n                logMenu: {\n                    ...state.logMenu,\n                    display: !state.logMenu.display,\n                    notify: false,\n                },\n            }\n        case PUSH_NOTIFICATION:\n            return {\n                ...state,\n                logMenu: {\n                    ...state.logMenu,\n                    notify: true,\n                    logs: [\n                        ...state.logMenu.logs,\n                        new AppLog(\n                            AppLogType.Article,\n                            action.title,\n                            action.source,\n                            action.iid\n                        ),\n                    ],\n                },\n            }\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/feed.ts",
    "content": "import * as db from \"../db\"\nimport lf from \"lovefield\"\nimport {\n    SourceActionTypes,\n    INIT_SOURCES,\n    ADD_SOURCE,\n    DELETE_SOURCE,\n    UNHIDE_SOURCE,\n    HIDE_SOURCE,\n} from \"./source\"\nimport {\n    ItemActionTypes,\n    FETCH_ITEMS,\n    RSSItem,\n    TOGGLE_HIDDEN,\n    applyItemReduction,\n} from \"./item\"\nimport { ActionStatus, AppThunk, mergeSortedArrays } from \"../utils\"\nimport { PageActionTypes, SELECT_PAGE, PageType, APPLY_FILTER } from \"./page\"\n\nexport enum FilterType {\n    None,\n    ShowRead = 1 << 0,\n    ShowNotStarred = 1 << 1,\n    ShowHidden = 1 << 2,\n    FullSearch = 1 << 3,\n    CaseInsensitive = 1 << 4,\n    CreatorSearch = 1 << 5,\n\n    Default = ShowRead | ShowNotStarred,\n    UnreadOnly = ShowNotStarred,\n    StarredOnly = ShowRead,\n    Toggles = ShowHidden | FullSearch | CaseInsensitive,\n}\nexport class FeedFilter {\n    type: FilterType\n    search: string\n\n    constructor(type: FilterType = null, search = \"\") {\n        if (\n            type === null &&\n            (type = window.settings.getFilterType()) === null\n        ) {\n            type = FilterType.Default | FilterType.CaseInsensitive\n        }\n        this.type = type\n        this.search = search\n    }\n\n    static toPredicates(filter: FeedFilter) {\n        let type = filter.type\n        const predicates = new Array<lf.Predicate>()\n        if (!(type & FilterType.ShowRead))\n            predicates.push(db.items.hasRead.eq(false))\n        if (!(type & FilterType.ShowNotStarred))\n            predicates.push(db.items.starred.eq(true))\n        if (!(type & FilterType.ShowHidden))\n            predicates.push(db.items.hidden.eq(false))\n        if (filter.search !== \"\") {\n            const flags = type & FilterType.CaseInsensitive ? \"i\" : \"\"\n            const regex = RegExp(filter.search, flags)\n            if (type & FilterType.FullSearch) {\n                predicates.push(\n                    lf.op.or(\n                        db.items.title.match(regex),\n                        db.items.snippet.match(regex)\n                    )\n                )\n            } else {\n                predicates.push(db.items.title.match(regex))\n            }\n        }\n        return predicates\n    }\n\n    static testItem(filter: FeedFilter, item: RSSItem) {\n        let type = filter.type\n        let flag = true\n        if (!(type & FilterType.ShowRead)) flag = flag && !item.hasRead\n        if (!(type & FilterType.ShowNotStarred)) flag = flag && item.starred\n        if (!(type & FilterType.ShowHidden)) flag = flag && !item.hidden\n        if (filter.search !== \"\") {\n            const flags = type & FilterType.CaseInsensitive ? \"i\" : \"\"\n            const regex = RegExp(filter.search, flags)\n            if (type & FilterType.FullSearch) {\n                flag =\n                    flag && (regex.test(item.title) || regex.test(item.snippet))\n            } else if (type & FilterType.CreatorSearch) {\n                flag = flag && regex.test(item.creator || \"\")\n            } else {\n                flag = flag && regex.test(item.title)\n            }\n        }\n        return Boolean(flag)\n    }\n}\n\nexport const ALL = \"ALL\"\nexport const SOURCE = \"SOURCE\"\n\nconst LOAD_QUANTITY = 50\n\nexport class RSSFeed {\n    _id: string\n    loaded: boolean\n    loading: boolean\n    allLoaded: boolean\n    sids: number[]\n    iids: number[]\n    filter: FeedFilter\n\n    constructor(id: string = null, sids = [], filter = null) {\n        this._id = id\n        this.sids = sids\n        this.iids = []\n        this.loaded = false\n        this.allLoaded = false\n        this.filter = filter === null ? new FeedFilter() : filter\n    }\n\n    static async loadFeed(feed: RSSFeed, skip = 0): Promise<RSSItem[]> {\n        const predicates = FeedFilter.toPredicates(feed.filter)\n        predicates.push(db.items.source.in(feed.sids))\n        return (await db.itemsDB\n            .select()\n            .from(db.items)\n            .where(lf.op.and.apply(null, predicates))\n            .orderBy(db.items.date, lf.Order.DESC)\n            .skip(skip)\n            .limit(LOAD_QUANTITY)\n            .exec()) as RSSItem[]\n    }\n}\n\nexport type FeedState = {\n    [_id: string]: RSSFeed\n}\n\nexport const INIT_FEEDS = \"INIT_FEEDS\"\nexport const INIT_FEED = \"INIT_FEED\"\nexport const LOAD_MORE = \"LOAD_MORE\"\nexport const DISMISS_ITEMS = \"DISMISS_ITEMS\"\n\ninterface initFeedsAction {\n    type: typeof INIT_FEEDS\n    status: ActionStatus\n}\n\ninterface initFeedAction {\n    type: typeof INIT_FEED\n    status: ActionStatus\n    feed?: RSSFeed\n    items?: RSSItem[]\n    err?\n}\n\ninterface loadMoreAction {\n    type: typeof LOAD_MORE\n    status: ActionStatus\n    feed: RSSFeed\n    items?: RSSItem[]\n    err?\n}\n\ninterface dismissItemsAction {\n    type: typeof DISMISS_ITEMS\n    fid: string\n    iids: Set<number>\n}\n\nexport type FeedActionTypes =\n    | initFeedAction\n    | initFeedsAction\n    | loadMoreAction\n    | dismissItemsAction\n\nexport function dismissItems(): AppThunk {\n    return (dispatch, getState) => {\n        const state = getState()\n        let fid = state.page.feedId\n        let filter = state.feeds[fid].filter\n        let iids = new Set<number>()\n        for (let iid of state.feeds[fid].iids) {\n            let item = state.items[iid]\n            if (!FeedFilter.testItem(filter, item)) {\n                iids.add(iid)\n            }\n        }\n        dispatch({\n            type: DISMISS_ITEMS,\n            fid: fid,\n            iids: iids,\n        })\n    }\n}\n\nexport function initFeedsRequest(): FeedActionTypes {\n    return {\n        type: INIT_FEEDS,\n        status: ActionStatus.Request,\n    }\n}\nexport function initFeedsSuccess(): FeedActionTypes {\n    return {\n        type: INIT_FEEDS,\n        status: ActionStatus.Success,\n    }\n}\n\nexport function initFeedSuccess(\n    feed: RSSFeed,\n    items: RSSItem[]\n): FeedActionTypes {\n    return {\n        type: INIT_FEED,\n        status: ActionStatus.Success,\n        items: items,\n        feed: feed,\n    }\n}\n\nexport function initFeedFailure(err): FeedActionTypes {\n    return {\n        type: INIT_FEED,\n        status: ActionStatus.Failure,\n        err: err,\n    }\n}\n\nexport function initFeeds(force = false): AppThunk<Promise<void>> {\n    return (dispatch, getState) => {\n        dispatch(initFeedsRequest())\n        let promises = new Array<Promise<void>>()\n        for (let feed of Object.values(getState().feeds)) {\n            if (!feed.loaded || force) {\n                let p = RSSFeed.loadFeed(feed)\n                    .then(items => {\n                        dispatch(initFeedSuccess(feed, items))\n                    })\n                    .catch(err => {\n                        console.log(err)\n                        dispatch(initFeedFailure(err))\n                    })\n                promises.push(p)\n            }\n        }\n        return Promise.allSettled(promises).then(() => {\n            dispatch(initFeedsSuccess())\n        })\n    }\n}\n\nexport function loadMoreRequest(feed: RSSFeed): FeedActionTypes {\n    return {\n        type: LOAD_MORE,\n        status: ActionStatus.Request,\n        feed: feed,\n    }\n}\n\nexport function loadMoreSuccess(\n    feed: RSSFeed,\n    items: RSSItem[]\n): FeedActionTypes {\n    return {\n        type: LOAD_MORE,\n        status: ActionStatus.Success,\n        feed: feed,\n        items: items,\n    }\n}\n\nexport function loadMoreFailure(feed: RSSFeed, err): FeedActionTypes {\n    return {\n        type: LOAD_MORE,\n        status: ActionStatus.Failure,\n        feed: feed,\n        err: err,\n    }\n}\n\nexport function loadMore(feed: RSSFeed): AppThunk<Promise<void>> {\n    return (dispatch, getState) => {\n        if (feed.loaded && !feed.loading && !feed.allLoaded) {\n            dispatch(loadMoreRequest(feed))\n            const state = getState()\n            const skipNum = feed.iids.filter(i =>\n                FeedFilter.testItem(feed.filter, state.items[i])\n            ).length\n            return RSSFeed.loadFeed(feed, skipNum)\n                .then(items => {\n                    dispatch(loadMoreSuccess(feed, items))\n                })\n                .catch(e => {\n                    console.log(e)\n                    dispatch(loadMoreFailure(feed, e))\n                })\n        }\n        return new Promise((_, reject) => {\n            reject()\n        })\n    }\n}\n\nexport function feedReducer(\n    state: FeedState = { [ALL]: new RSSFeed(ALL) },\n    action:\n        | SourceActionTypes\n        | ItemActionTypes\n        | FeedActionTypes\n        | PageActionTypes\n): FeedState {\n    switch (action.type) {\n        case INIT_SOURCES:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        [ALL]: new RSSFeed(\n                            ALL,\n                            Object.values(action.sources)\n                                .filter(s => !s.hidden)\n                                .map(s => s.sid)\n                        ),\n                    }\n                default:\n                    return state\n            }\n        case ADD_SOURCE:\n        case UNHIDE_SOURCE:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        [ALL]: new RSSFeed(\n                            ALL,\n                            [...state[ALL].sids, action.source.sid],\n                            state[ALL].filter\n                        ),\n                    }\n                default:\n                    return state\n            }\n        case DELETE_SOURCE:\n        case HIDE_SOURCE: {\n            let nextState = {}\n            for (let [id, feed] of Object.entries(state)) {\n                nextState[id] = new RSSFeed(\n                    id,\n                    feed.sids.filter(sid => sid != action.source.sid),\n                    feed.filter\n                )\n            }\n            return nextState\n        }\n        case APPLY_FILTER: {\n            let nextState = {}\n            for (let [id, feed] of Object.entries(state)) {\n                nextState[id] = {\n                    ...feed,\n                    filter: action.filter,\n                }\n            }\n            return nextState\n        }\n        case FETCH_ITEMS:\n            switch (action.status) {\n                case ActionStatus.Success: {\n                    let nextState = { ...state }\n                    for (let feed of Object.values(state)) {\n                        if (feed.loaded) {\n                            let items = action.items.filter(\n                                i =>\n                                    feed.sids.includes(i.source) &&\n                                    FeedFilter.testItem(feed.filter, i)\n                            )\n                            if (items.length > 0) {\n                                let oldItems = feed.iids.map(\n                                    id => action.itemState[id]\n                                )\n                                let nextItems = mergeSortedArrays(\n                                    oldItems,\n                                    items,\n                                    (a, b) =>\n                                        b.date.getTime() - a.date.getTime()\n                                )\n                                nextState[feed._id] = {\n                                    ...feed,\n                                    iids: nextItems.map(i => i._id),\n                                }\n                            }\n                        }\n                    }\n                    return nextState\n                }\n                default:\n                    return state\n            }\n        case DISMISS_ITEMS:\n            let nextState = { ...state }\n            let feed = state[action.fid]\n            nextState[action.fid] = {\n                ...feed,\n                iids: feed.iids.filter(iid => !action.iids.has(iid)),\n            }\n            return nextState\n        case INIT_FEED:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        [action.feed._id]: {\n                            ...action.feed,\n                            loaded: true,\n                            allLoaded: action.items.length < LOAD_QUANTITY,\n                            iids: action.items.map(i => i._id),\n                        },\n                    }\n                default:\n                    return state\n            }\n        case LOAD_MORE:\n            switch (action.status) {\n                case ActionStatus.Request:\n                    return {\n                        ...state,\n                        [action.feed._id]: {\n                            ...action.feed,\n                            loading: true,\n                        },\n                    }\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        [action.feed._id]: {\n                            ...action.feed,\n                            loading: false,\n                            allLoaded: action.items.length < LOAD_QUANTITY,\n                            iids: [\n                                ...action.feed.iids,\n                                ...action.items.map(i => i._id),\n                            ],\n                        },\n                    }\n                case ActionStatus.Failure:\n                    return {\n                        ...state,\n                        [action.feed._id]: {\n                            ...action.feed,\n                            loading: false,\n                        },\n                    }\n                default:\n                    return state\n            }\n        case TOGGLE_HIDDEN: {\n            let nextItem = applyItemReduction(action.item, action.type)\n            let filteredFeeds = Object.values(state).filter(\n                feed =>\n                    feed.loaded && !FeedFilter.testItem(feed.filter, nextItem)\n            )\n            if (filteredFeeds.length > 0) {\n                let nextState = { ...state }\n                for (let feed of filteredFeeds) {\n                    nextState[feed._id] = {\n                        ...feed,\n                        iids: feed.iids.filter(id => id != nextItem._id),\n                    }\n                }\n                return nextState\n            } else {\n                return state\n            }\n        }\n        case SELECT_PAGE:\n            switch (action.pageType) {\n                case PageType.Sources:\n                    return {\n                        ...state,\n                        [SOURCE]: new RSSFeed(\n                            SOURCE,\n                            action.sids,\n                            action.filter\n                        ),\n                    }\n                case PageType.AllArticles:\n                    return action.init\n                        ? {\n                              ...state,\n                              [ALL]: {\n                                  ...state[ALL],\n                                  loaded: false,\n                                  filter: action.filter,\n                              },\n                          }\n                        : state\n                default:\n                    return state\n            }\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/group.ts",
    "content": "import intl from \"react-intl-universal\"\nimport {\n    SourceActionTypes,\n    ADD_SOURCE,\n    DELETE_SOURCE,\n    addSource,\n    RSSSource,\n    SourceState,\n} from \"./source\"\nimport { SourceGroup } from \"../../schema-types\"\nimport { ActionStatus, AppThunk, domParser } from \"../utils\"\nimport { saveSettings } from \"./app\"\nimport {\n    fetchItemsIntermediate,\n    fetchItemsRequest,\n    fetchItemsSuccess,\n} from \"./item\"\n\nexport const CREATE_SOURCE_GROUP = \"CREATE_SOURCE_GROUP\"\nexport const ADD_SOURCE_TO_GROUP = \"ADD_SOURCE_TO_GROUP\"\nexport const REMOVE_SOURCE_FROM_GROUP = \"REMOVE_SOURCE_FROM_GROUP\"\nexport const UPDATE_SOURCE_GROUP = \"UPDATE_SOURCE_GROUP\"\nexport const REORDER_SOURCE_GROUPS = \"REORDER_SOURCE_GROUPS\"\nexport const DELETE_SOURCE_GROUP = \"DELETE_SOURCE_GROUP\"\nexport const TOGGLE_GROUP_EXPANSION = \"TOGGLE_GROUP_EXPANSION\"\n\ninterface CreateSourceGroupAction {\n    type: typeof CREATE_SOURCE_GROUP\n    group: SourceGroup\n}\n\ninterface AddSourceToGroupAction {\n    type: typeof ADD_SOURCE_TO_GROUP\n    groupIndex: number\n    sid: number\n}\n\ninterface RemoveSourceFromGroupAction {\n    type: typeof REMOVE_SOURCE_FROM_GROUP\n    groupIndex: number\n    sids: number[]\n}\n\ninterface UpdateSourceGroupAction {\n    type: typeof UPDATE_SOURCE_GROUP\n    groupIndex: number\n    group: SourceGroup\n}\n\ninterface ReorderSourceGroupsAction {\n    type: typeof REORDER_SOURCE_GROUPS\n    groups: SourceGroup[]\n}\n\ninterface DeleteSourceGroupAction {\n    type: typeof DELETE_SOURCE_GROUP\n    groupIndex: number\n}\n\ninterface ToggleGroupExpansionAction {\n    type: typeof TOGGLE_GROUP_EXPANSION\n    groupIndex: number\n}\n\nexport type SourceGroupActionTypes =\n    | CreateSourceGroupAction\n    | AddSourceToGroupAction\n    | RemoveSourceFromGroupAction\n    | UpdateSourceGroupAction\n    | ReorderSourceGroupsAction\n    | DeleteSourceGroupAction\n    | ToggleGroupExpansionAction\n\nexport function createSourceGroupDone(\n    group: SourceGroup\n): SourceGroupActionTypes {\n    return {\n        type: CREATE_SOURCE_GROUP,\n        group: group,\n    }\n}\n\nexport function createSourceGroup(name: string): AppThunk<number> {\n    return (dispatch, getState) => {\n        let groups = getState().groups\n        for (let i = 0; i < groups.length; i += 1) {\n            const g = groups[i]\n            if (g.isMultiple && g.name === name) {\n                return i\n            }\n        }\n        let group = new SourceGroup([], name)\n        dispatch(createSourceGroupDone(group))\n        groups = getState().groups\n        window.settings.saveGroups(groups)\n        return groups.length - 1\n    }\n}\n\nfunction addSourceToGroupDone(\n    groupIndex: number,\n    sid: number\n): SourceGroupActionTypes {\n    return {\n        type: ADD_SOURCE_TO_GROUP,\n        groupIndex: groupIndex,\n        sid: sid,\n    }\n}\n\nexport function addSourceToGroup(groupIndex: number, sid: number): AppThunk {\n    return (dispatch, getState) => {\n        dispatch(addSourceToGroupDone(groupIndex, sid))\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nfunction removeSourceFromGroupDone(\n    groupIndex: number,\n    sids: number[]\n): SourceGroupActionTypes {\n    return {\n        type: REMOVE_SOURCE_FROM_GROUP,\n        groupIndex: groupIndex,\n        sids: sids,\n    }\n}\n\nexport function removeSourceFromGroup(\n    groupIndex: number,\n    sids: number[]\n): AppThunk {\n    return (dispatch, getState) => {\n        dispatch(removeSourceFromGroupDone(groupIndex, sids))\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nfunction deleteSourceGroupDone(groupIndex: number): SourceGroupActionTypes {\n    return {\n        type: DELETE_SOURCE_GROUP,\n        groupIndex: groupIndex,\n    }\n}\n\nexport function deleteSourceGroup(groupIndex: number): AppThunk {\n    return (dispatch, getState) => {\n        dispatch(deleteSourceGroupDone(groupIndex))\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nfunction updateSourceGroupDone(group: SourceGroup): SourceGroupActionTypes {\n    return {\n        type: UPDATE_SOURCE_GROUP,\n        groupIndex: group.index,\n        group: group,\n    }\n}\n\nexport function updateSourceGroup(group: SourceGroup): AppThunk {\n    return (dispatch, getState) => {\n        dispatch(updateSourceGroupDone(group))\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nfunction reorderSourceGroupsDone(\n    groups: SourceGroup[]\n): SourceGroupActionTypes {\n    return {\n        type: REORDER_SOURCE_GROUPS,\n        groups: groups,\n    }\n}\n\nexport function reorderSourceGroups(groups: SourceGroup[]): AppThunk {\n    return (dispatch, getState) => {\n        dispatch(reorderSourceGroupsDone(groups))\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nexport function toggleGroupExpansion(groupIndex: number): AppThunk {\n    return (dispatch, getState) => {\n        dispatch({\n            type: TOGGLE_GROUP_EXPANSION,\n            groupIndex: groupIndex,\n        })\n        window.settings.saveGroups(getState().groups)\n    }\n}\n\nexport function fixBrokenGroups(sources: SourceState): AppThunk {\n    return (dispatch, getState) => {\n        const { groups } = getState()\n        const sids = new Set(Object.values(sources).map(s => s.sid))\n        let isBroken = false\n        const newGroups: SourceGroup[] = groups\n            .map(group => {\n                const newGroup: SourceGroup = {\n                    ...group,\n                    sids: group.sids.filter(sid => sids.delete(sid)),\n                }\n                if (newGroup.sids.length !== group.sids.length) {\n                    isBroken = true\n                }\n                return newGroup\n            })\n            .filter(group => group.isMultiple || group.sids.length > 0)\n        if (isBroken || sids.size > 0) {\n            for (let sid of sids) {\n                newGroups.push(new SourceGroup([sid]))\n            }\n            dispatch(reorderSourceGroups(newGroups))\n        }\n    }\n}\n\nfunction outlineToSource(\n    outline: Element\n): [ReturnType<typeof addSource>, string] {\n    let url = outline.getAttribute(\"xmlUrl\")\n    let name = outline.getAttribute(\"text\") || outline.getAttribute(\"title\")\n    if (url) {\n        return [addSource(url.trim(), name, true), url]\n    } else {\n        return null\n    }\n}\n\nexport function importOPML(): AppThunk {\n    return async dispatch => {\n        const filters = [\n            { name: intl.get(\"sources.opmlFile\"), extensions: [\"xml\", \"opml\"] },\n        ]\n        window.utils.showOpenDialog(filters).then(data => {\n            if (data) {\n                dispatch(saveSettings())\n                let doc = domParser\n                    .parseFromString(data, \"text/xml\")\n                    .getElementsByTagName(\"body\")\n                if (doc.length == 0) {\n                    dispatch(saveSettings())\n                    return\n                }\n                let parseError = doc[0].getElementsByTagName(\"parsererror\")\n                if (parseError.length > 0) {\n                    dispatch(saveSettings())\n                    window.utils.showErrorBox(\n                        intl.get(\"sources.errorParse\"),\n                        intl.get(\"sources.errorParseHint\")\n                    )\n                    return\n                }\n                let sources: [ReturnType<typeof addSource>, number, string][] =\n                    []\n                let errors: [string, any][] = []\n                for (let el of doc[0].children) {\n                    if (el.getAttribute(\"type\") === \"rss\") {\n                        let source = outlineToSource(el)\n                        if (source) sources.push([source[0], -1, source[1]])\n                    } else if (\n                        el.hasAttribute(\"text\") ||\n                        el.hasAttribute(\"title\")\n                    ) {\n                        let groupName =\n                            el.getAttribute(\"text\") || el.getAttribute(\"title\")\n                        let gid = dispatch(createSourceGroup(groupName))\n                        for (let child of el.children) {\n                            let source = outlineToSource(child)\n                            if (source)\n                                sources.push([source[0], gid, source[1]])\n                        }\n                    }\n                }\n                dispatch(fetchItemsRequest(sources.length))\n                let promises = sources.map(([s, gid, url]) => {\n                    return dispatch(s)\n                        .then(sid => {\n                            if (sid !== null && gid > -1)\n                                dispatch(addSourceToGroup(gid, sid))\n                        })\n                        .catch(err => {\n                            errors.push([url, err])\n                        })\n                        .finally(() => {\n                            dispatch(fetchItemsIntermediate())\n                        })\n                })\n                Promise.allSettled(promises).then(() => {\n                    dispatch(fetchItemsSuccess([], {}))\n                    dispatch(saveSettings())\n                    if (errors.length > 0) {\n                        window.utils.showErrorBox(\n                            intl.get(\"sources.errorImport\", {\n                                count: errors.length,\n                            }),\n                            errors\n                                .map(e => {\n                                    return e[0] + \"\\n\" + String(e[1])\n                                })\n                                .join(\"\\n\"),\n                            intl.get(\"context.copy\")\n                        )\n                    }\n                })\n            }\n        })\n    }\n}\n\nfunction sourceToOutline(source: RSSSource, xml: Document) {\n    let outline = xml.createElement(\"outline\")\n    outline.setAttribute(\"text\", source.name)\n    outline.setAttribute(\"title\", source.name)\n    outline.setAttribute(\"type\", \"rss\")\n    outline.setAttribute(\"xmlUrl\", source.url)\n    return outline\n}\n\nexport function exportOPML(): AppThunk {\n    return (_, getState) => {\n        const filters = [\n            { name: intl.get(\"sources.opmlFile\"), extensions: [\"opml\"] },\n        ]\n        window.utils\n            .showSaveDialog(filters, \"*/Fluent_Reader_Export.opml\")\n            .then(write => {\n                if (write) {\n                    let state = getState()\n                    let xml = domParser.parseFromString(\n                        '<?xml version=\"1.0\" encoding=\"UTF-8\"?><opml version=\"1.0\"><head><title>Fluent Reader Export</title></head><body></body></opml>',\n                        \"text/xml\"\n                    )\n                    let body = xml.getElementsByTagName(\"body\")[0]\n                    for (let group of state.groups) {\n                        if (group.isMultiple) {\n                            let outline = xml.createElement(\"outline\")\n                            outline.setAttribute(\"text\", group.name)\n                            outline.setAttribute(\"title\", group.name)\n                            for (let sid of group.sids) {\n                                outline.appendChild(\n                                    sourceToOutline(state.sources[sid], xml)\n                                )\n                            }\n                            body.appendChild(outline)\n                        } else {\n                            body.appendChild(\n                                sourceToOutline(\n                                    state.sources[group.sids[0]],\n                                    xml\n                                )\n                            )\n                        }\n                    }\n                    let serializer = new XMLSerializer()\n                    write(\n                        serializer.serializeToString(xml),\n                        intl.get(\"settings.writeError\")\n                    )\n                }\n            })\n    }\n}\n\nexport type GroupState = SourceGroup[]\n\nexport function groupReducer(\n    state = window.settings.loadGroups(),\n    action: SourceActionTypes | SourceGroupActionTypes\n): GroupState {\n    switch (action.type) {\n        case ADD_SOURCE:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return [...state, new SourceGroup([action.source.sid])]\n                default:\n                    return state\n            }\n        case DELETE_SOURCE:\n            return [\n                ...state\n                    .map(group => ({\n                        ...group,\n                        sids: group.sids.filter(\n                            sid => sid != action.source.sid\n                        ),\n                    }))\n                    .filter(g => g.isMultiple || g.sids.length == 1),\n            ]\n        case CREATE_SOURCE_GROUP:\n            return [...state, action.group]\n        case ADD_SOURCE_TO_GROUP:\n            return state\n                .map((g, i) => ({\n                    ...g,\n                    sids:\n                        i == action.groupIndex\n                            ? [\n                                  ...g.sids.filter(sid => sid !== action.sid),\n                                  action.sid,\n                              ]\n                            : g.sids.filter(sid => sid !== action.sid),\n                }))\n                .filter(g => g.isMultiple || g.sids.length > 0)\n        case REMOVE_SOURCE_FROM_GROUP:\n            return [\n                ...state.slice(0, action.groupIndex),\n                {\n                    ...state[action.groupIndex],\n                    sids: state[action.groupIndex].sids.filter(\n                        sid => !action.sids.includes(sid)\n                    ),\n                },\n                ...action.sids.map(sid => new SourceGroup([sid])),\n                ...state.slice(action.groupIndex + 1),\n            ]\n        case UPDATE_SOURCE_GROUP:\n            return [\n                ...state.slice(0, action.groupIndex),\n                action.group,\n                ...state.slice(action.groupIndex + 1),\n            ]\n        case REORDER_SOURCE_GROUPS:\n            return action.groups\n        case DELETE_SOURCE_GROUP:\n            return [\n                ...state.slice(0, action.groupIndex),\n                ...state[action.groupIndex].sids.map(\n                    sid => new SourceGroup([sid])\n                ),\n                ...state.slice(action.groupIndex + 1),\n            ]\n        case TOGGLE_GROUP_EXPANSION:\n            return state.map((g, i) =>\n                i == action.groupIndex\n                    ? {\n                          ...g,\n                          expanded: !g.expanded,\n                      }\n                    : g\n            )\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/item.ts",
    "content": "import * as db from \"../db\"\nimport lf from \"lovefield\"\nimport intl from \"react-intl-universal\"\nimport type { MyParserItem } from \"../utils\"\nimport {\n    domParser,\n    htmlDecode,\n    ActionStatus,\n    AppThunk,\n    platformCtrl,\n} from \"../utils\"\nimport { RSSSource, updateSource, updateUnreadCounts } from \"./source\"\nimport { FeedActionTypes, INIT_FEED, LOAD_MORE, dismissItems } from \"./feed\"\nimport {\n    pushNotification,\n    setupAutoFetch,\n    SettingsActionTypes,\n    FREE_MEMORY,\n} from \"./app\"\nimport {\n    getServiceHooks,\n    syncWithService,\n    ServiceActionTypes,\n    SYNC_LOCAL_ITEMS,\n} from \"./service\"\n\nexport class RSSItem {\n    _id: number\n    source: number\n    title: string\n    link: string\n    date: Date\n    fetchedDate: Date\n    thumb?: string\n    content: string\n    snippet: string\n    creator?: string\n    hasRead: boolean\n    starred: boolean\n    hidden: boolean\n    notify: boolean\n    serviceRef?: string\n\n    constructor(item: MyParserItem, source: RSSSource) {\n        for (let field of [\"title\", \"link\", \"creator\"]) {\n            const content = item[field]\n            if (content && typeof content !== \"string\") delete item[field]\n        }\n        this.source = source.sid\n        this.title = item.title || intl.get(\"article.untitled\")\n        this.link = item.link || \"\"\n        this.fetchedDate = new Date()\n        this.date = new Date(item.isoDate ?? item.pubDate ?? this.fetchedDate)\n        this.creator = item.creator\n        this.hasRead = false\n        this.starred = false\n        this.hidden = false\n        this.notify = false\n    }\n\n    static parseContent(item: RSSItem, parsed: MyParserItem) {\n        for (let field of [\"thumb\", \"content\", \"fullContent\"]) {\n            const content = parsed[field]\n            if (content && typeof content !== \"string\") delete parsed[field]\n        }\n        if (parsed.fullContent) {\n            item.content = parsed.fullContent\n            item.snippet = htmlDecode(parsed.fullContent)\n        } else {\n            item.content = parsed.content || \"\"\n            item.snippet = htmlDecode(parsed.contentSnippet || \"\")\n        }\n        if (parsed.thumb) {\n            item.thumb = parsed.thumb\n        } else if (parsed.image?.$?.url) {\n            item.thumb = parsed.image.$.url\n        } else if (parsed.image && typeof parsed.image === \"string\") {\n            item.thumb = parsed.image\n        } else if (parsed.mediaContent) {\n            let images = parsed.mediaContent.filter(\n                c => c.$ && c.$.medium === \"image\" && c.$.url\n            )\n            if (images.length > 0) item.thumb = images[0].$.url\n        }\n        if (!item.thumb) {\n            let dom = domParser.parseFromString(item.content, \"text/html\")\n            let baseEl = dom.createElement(\"base\")\n            baseEl.setAttribute(\n                \"href\",\n                item.link.split(\"/\").slice(0, 3).join(\"/\")\n            )\n            dom.head.append(baseEl)\n            let img = dom.querySelector(\"img\")\n            if (img && img.src) item.thumb = img.src\n        }\n        if (\n            item.thumb &&\n            !item.thumb.startsWith(\"https://\") &&\n            !item.thumb.startsWith(\"http://\")\n        ) {\n            delete item.thumb\n        }\n    }\n}\n\nexport type ItemState = {\n    [_id: number]: RSSItem\n}\n\nexport const FETCH_ITEMS = \"FETCH_ITEMS\"\nexport const MARK_READ = \"MARK_READ\"\nexport const MARK_ALL_READ = \"MARK_ALL_READ\"\nexport const MARK_UNREAD = \"MARK_UNREAD\"\nexport const TOGGLE_STARRED = \"TOGGLE_STARRED\"\nexport const TOGGLE_HIDDEN = \"TOGGLE_HIDDEN\"\n\ninterface FetchItemsAction {\n    type: typeof FETCH_ITEMS\n    status: ActionStatus\n    fetchCount?: number\n    items?: RSSItem[]\n    itemState?: ItemState\n    errSource?: RSSSource\n    err?\n}\n\ninterface MarkReadAction {\n    type: typeof MARK_READ\n    item: RSSItem\n}\n\ninterface MarkAllReadAction {\n    type: typeof MARK_ALL_READ\n    sids: number[]\n    time?: number\n    before?: boolean\n}\n\ninterface MarkUnreadAction {\n    type: typeof MARK_UNREAD\n    item: RSSItem\n}\n\ninterface ToggleStarredAction {\n    type: typeof TOGGLE_STARRED\n    item: RSSItem\n}\n\ninterface ToggleHiddenAction {\n    type: typeof TOGGLE_HIDDEN\n    item: RSSItem\n}\n\nexport type ItemActionTypes =\n    | FetchItemsAction\n    | MarkReadAction\n    | MarkAllReadAction\n    | MarkUnreadAction\n    | ToggleStarredAction\n    | ToggleHiddenAction\n\nexport function fetchItemsRequest(fetchCount = 0): ItemActionTypes {\n    return {\n        type: FETCH_ITEMS,\n        status: ActionStatus.Request,\n        fetchCount: fetchCount,\n    }\n}\n\nexport function fetchItemsSuccess(\n    items: RSSItem[],\n    itemState: ItemState\n): ItemActionTypes {\n    return {\n        type: FETCH_ITEMS,\n        status: ActionStatus.Success,\n        items: items,\n        itemState: itemState,\n    }\n}\n\nexport function fetchItemsFailure(source: RSSSource, err): ItemActionTypes {\n    return {\n        type: FETCH_ITEMS,\n        status: ActionStatus.Failure,\n        errSource: source,\n        err: err,\n    }\n}\n\nexport function fetchItemsIntermediate(): ItemActionTypes {\n    return {\n        type: FETCH_ITEMS,\n        status: ActionStatus.Intermediate,\n    }\n}\n\nexport async function insertItems(items: RSSItem[]): Promise<RSSItem[]> {\n    items.sort((a, b) => a.date.getTime() - b.date.getTime())\n    const rows = items.map(item => db.items.createRow(item))\n    return (await db.itemsDB\n        .insert()\n        .into(db.items)\n        .values(rows)\n        .exec()) as RSSItem[]\n}\n\nexport function fetchItems(\n    background = false,\n    sids: number[] = null\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        let promises = new Array<Promise<RSSItem[]>>()\n        const initState = getState()\n        if (!initState.app.fetchingItems && !initState.app.syncing) {\n            if (\n                sids === null ||\n                sids.filter(\n                    sid => initState.sources[sid].serviceRef !== undefined\n                ).length > 0\n            )\n                await dispatch(syncWithService(background))\n            let timenow = new Date().getTime()\n            const sourcesState = getState().sources\n            let sources =\n                sids === null\n                    ? Object.values(sourcesState).filter(s => {\n                          let last = s.lastFetched ? s.lastFetched.getTime() : 0\n                          return (\n                              !s.serviceRef &&\n                              (last > timenow ||\n                                  last + (s.fetchFrequency || 0) * 60000 <=\n                                      timenow)\n                          )\n                      })\n                    : sids\n                          .map(sid => sourcesState[sid])\n                          .filter(s => !s.serviceRef)\n            for (let source of sources) {\n                let promise = RSSSource.fetchItems(source)\n                promise.then(() =>\n                    dispatch(\n                        updateSource({ ...source, lastFetched: new Date() })\n                    )\n                )\n                promise.finally(() => dispatch(fetchItemsIntermediate()))\n                promises.push(promise)\n            }\n            dispatch(fetchItemsRequest(promises.length))\n            const results = await Promise.allSettled(promises)\n            return await new Promise<void>((resolve, reject) => {\n                let items = new Array<RSSItem>()\n                results.map((r, i) => {\n                    if (r.status === \"fulfilled\") items.push(...r.value)\n                    else {\n                        console.log(r.reason)\n                        dispatch(fetchItemsFailure(sources[i], r.reason))\n                    }\n                })\n                insertItems(items)\n                    .then(inserted => {\n                        dispatch(\n                            fetchItemsSuccess(\n                                inserted.reverse(),\n                                getState().items\n                            )\n                        )\n                        resolve()\n                        if (background) {\n                            for (let item of inserted) {\n                                if (item.notify) {\n                                    dispatch(pushNotification(item))\n                                }\n                            }\n                            if (inserted.length > 0) {\n                                window.utils.requestAttention()\n                            }\n                        } else {\n                            dispatch(dismissItems())\n                        }\n                        dispatch(setupAutoFetch())\n                    })\n                    .catch(err => {\n                        dispatch(fetchItemsSuccess([], getState().items))\n                        window.utils.showErrorBox(\n                            \"A database error has occurred.\",\n                            String(err)\n                        )\n                        console.log(err)\n                        reject(err)\n                    })\n            })\n        }\n    }\n}\n\nconst markReadDone = (item: RSSItem): ItemActionTypes => ({\n    type: MARK_READ,\n    item: item,\n})\n\nconst markUnreadDone = (item: RSSItem): ItemActionTypes => ({\n    type: MARK_UNREAD,\n    item: item,\n})\n\nexport function markRead(item: RSSItem): AppThunk {\n    return (dispatch, getState) => {\n        item = getState().items[item._id]\n        if (!item.hasRead) {\n            db.itemsDB\n                .update(db.items)\n                .where(db.items._id.eq(item._id))\n                .set(db.items.hasRead, true)\n                .exec()\n            dispatch(markReadDone(item))\n            if (item.serviceRef) {\n                dispatch(dispatch(getServiceHooks()).markRead?.(item))\n            }\n        }\n    }\n}\n\nexport function markAllRead(\n    sids: number[] = null,\n    date: Date = null,\n    before = true\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        let state = getState()\n        if (sids === null) {\n            let feed = state.feeds[state.page.feedId]\n            sids = feed.sids\n        }\n        const action = dispatch(getServiceHooks()).markAllRead?.(\n            sids,\n            date,\n            before\n        )\n        if (action) await dispatch(action)\n        const predicates: lf.Predicate[] = [\n            db.items.source.in(sids),\n            db.items.hasRead.eq(false),\n        ]\n        if (date) {\n            predicates.push(\n                before ? db.items.date.lte(date) : db.items.date.gte(date)\n            )\n        }\n        const query = lf.op.and.apply(null, predicates)\n        await db.itemsDB\n            .update(db.items)\n            .set(db.items.hasRead, true)\n            .where(query)\n            .exec()\n        if (date) {\n            dispatch({\n                type: MARK_ALL_READ,\n                sids: sids,\n                time: date.getTime(),\n                before: before,\n            })\n            dispatch(updateUnreadCounts())\n        } else {\n            dispatch({\n                type: MARK_ALL_READ,\n                sids: sids,\n            })\n        }\n    }\n}\n\nexport function markUnread(item: RSSItem): AppThunk {\n    return (dispatch, getState) => {\n        item = getState().items[item._id]\n        if (item.hasRead) {\n            db.itemsDB\n                .update(db.items)\n                .where(db.items._id.eq(item._id))\n                .set(db.items.hasRead, false)\n                .exec()\n            dispatch(markUnreadDone(item))\n            if (item.serviceRef) {\n                dispatch(dispatch(getServiceHooks()).markUnread?.(item))\n            }\n        }\n    }\n}\n\nconst toggleStarredDone = (item: RSSItem): ItemActionTypes => ({\n    type: TOGGLE_STARRED,\n    item: item,\n})\n\nexport function toggleStarred(item: RSSItem): AppThunk {\n    return dispatch => {\n        db.itemsDB\n            .update(db.items)\n            .where(db.items._id.eq(item._id))\n            .set(db.items.starred, !item.starred)\n            .exec()\n        dispatch(toggleStarredDone(item))\n        if (item.serviceRef) {\n            const hooks = dispatch(getServiceHooks())\n            if (item.starred) dispatch(hooks.unstar?.(item))\n            else dispatch(hooks.star?.(item))\n        }\n    }\n}\n\nconst toggleHiddenDone = (item: RSSItem): ItemActionTypes => ({\n    type: TOGGLE_HIDDEN,\n    item: item,\n})\n\nexport function toggleHidden(item: RSSItem): AppThunk {\n    return dispatch => {\n        db.itemsDB\n            .update(db.items)\n            .where(db.items._id.eq(item._id))\n            .set(db.items.hidden, !item.hidden)\n            .exec()\n        dispatch(toggleHiddenDone(item))\n    }\n}\n\nexport function itemShortcuts(item: RSSItem, e: KeyboardEvent): AppThunk {\n    return dispatch => {\n        if (e.metaKey) return\n        switch (e.key) {\n            case \"m\":\n            case \"M\":\n                if (item.hasRead) dispatch(markUnread(item))\n                else dispatch(markRead(item))\n                break\n            case \"b\":\n            case \"B\":\n                if (!item.hasRead) dispatch(markRead(item))\n                window.utils.openExternal(item.link, platformCtrl(e))\n                break\n            case \"s\":\n            case \"S\":\n                dispatch(toggleStarred(item))\n                break\n            case \"h\":\n            case \"H\":\n                if (!item.hasRead && !item.hidden) dispatch(markRead(item))\n                dispatch(toggleHidden(item))\n                break\n        }\n    }\n}\n\nexport function applyItemReduction(item: RSSItem, type: string) {\n    let nextItem = { ...item }\n    switch (type) {\n        case MARK_READ:\n        case MARK_UNREAD: {\n            nextItem.hasRead = type === MARK_READ\n            break\n        }\n        case TOGGLE_STARRED: {\n            nextItem.starred = !item.starred\n            break\n        }\n        case TOGGLE_HIDDEN: {\n            nextItem.hidden = !item.hidden\n            break\n        }\n    }\n    return nextItem\n}\n\nexport function itemReducer(\n    state: ItemState = {},\n    action:\n        | ItemActionTypes\n        | FeedActionTypes\n        | ServiceActionTypes\n        | SettingsActionTypes\n): ItemState {\n    switch (action.type) {\n        case FETCH_ITEMS:\n            switch (action.status) {\n                case ActionStatus.Success: {\n                    let newMap = {}\n                    for (let i of action.items) {\n                        newMap[i._id] = i\n                    }\n                    return { ...newMap, ...state }\n                }\n                default:\n                    return state\n            }\n        case MARK_UNREAD:\n        case MARK_READ:\n        case TOGGLE_STARRED:\n        case TOGGLE_HIDDEN: {\n            return {\n                ...state,\n                [action.item._id]: applyItemReduction(\n                    state[action.item._id],\n                    action.type\n                ),\n            }\n        }\n        case MARK_ALL_READ: {\n            let nextState = { ...state }\n            let sids = new Set(action.sids)\n            for (let item of Object.values(state)) {\n                if (sids.has(item.source) && !item.hasRead) {\n                    if (\n                        !action.time ||\n                        (action.before\n                            ? item.date.getTime() <= action.time\n                            : item.date.getTime() >= action.time)\n                    ) {\n                        nextState[item._id] = {\n                            ...item,\n                            hasRead: true,\n                        }\n                    }\n                }\n            }\n            return nextState\n        }\n        case LOAD_MORE:\n        case INIT_FEED: {\n            switch (action.status) {\n                case ActionStatus.Success: {\n                    let nextState = { ...state }\n                    for (let i of action.items) {\n                        nextState[i._id] = i\n                    }\n                    return nextState\n                }\n                default:\n                    return state\n            }\n        }\n        case SYNC_LOCAL_ITEMS: {\n            let nextState = { ...state }\n            for (let item of Object.values(state)) {\n                if (item.hasOwnProperty(\"serviceRef\")) {\n                    const nextItem = { ...item }\n                    nextItem.hasRead = !action.unreadIds.has(item.serviceRef)\n                    nextItem.starred = action.starredIds.has(item.serviceRef)\n                    nextState[item._id] = nextItem\n                }\n            }\n            return nextState\n        }\n        case FREE_MEMORY: {\n            const nextState: ItemState = {}\n            for (let item of Object.values(state)) {\n                if (action.iids.has(item._id)) nextState[item._id] = item\n            }\n            return nextState\n        }\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/page.ts",
    "content": "import {\n    ALL,\n    SOURCE,\n    loadMore,\n    FeedFilter,\n    FilterType,\n    initFeeds,\n    FeedActionTypes,\n    INIT_FEED,\n} from \"./feed\"\nimport { getWindowBreakpoint, AppThunk, ActionStatus } from \"../utils\"\nimport { RSSItem, markRead } from \"./item\"\nimport { SourceActionTypes, DELETE_SOURCE } from \"./source\"\nimport { toggleMenu } from \"./app\"\nimport { ViewType, ViewConfigs } from \"../../schema-types\"\n\nexport const SELECT_PAGE = \"SELECT_PAGE\"\nexport const SWITCH_VIEW = \"SWITCH_VIEW\"\nexport const SET_VIEW_CONFIGS = \"SET_VIEW_CONFIGS\"\nexport const SHOW_ITEM = \"SHOW_ITEM\"\nexport const SHOW_OFFSET_ITEM = \"SHOW_OFFSET_ITEM\"\nexport const DISMISS_ITEM = \"DISMISS_ITEM\"\nexport const APPLY_FILTER = \"APPLY_FILTER\"\nexport const TOGGLE_SEARCH = \"TOGGLE_SEARCH\"\n\nexport enum PageType {\n    AllArticles,\n    Sources,\n    Page,\n}\n\ninterface SelectPageAction {\n    type: typeof SELECT_PAGE\n    pageType: PageType\n    init: boolean\n    keepMenu: boolean\n    filter: FeedFilter\n    sids?: number[]\n    menuKey?: string\n    title?: string\n}\n\ninterface SwitchViewAction {\n    type: typeof SWITCH_VIEW\n    viewType: ViewType\n}\n\ninterface SetViewConfigsAction {\n    type: typeof SET_VIEW_CONFIGS\n    configs: ViewConfigs\n}\n\ninterface ShowItemAction {\n    type: typeof SHOW_ITEM\n    feedId: string\n    item: RSSItem\n}\n\ninterface ApplyFilterAction {\n    type: typeof APPLY_FILTER\n    filter: FeedFilter\n}\n\ninterface DismissItemAction {\n    type: typeof DISMISS_ITEM\n}\ninterface ToggleSearchAction {\n    type: typeof TOGGLE_SEARCH\n}\n\nexport type PageActionTypes =\n    | SelectPageAction\n    | SwitchViewAction\n    | ShowItemAction\n    | DismissItemAction\n    | ApplyFilterAction\n    | ToggleSearchAction\n    | SetViewConfigsAction\n\nexport function selectAllArticles(init = false): AppThunk {\n    return (dispatch, getState) => {\n        dispatch({\n            type: SELECT_PAGE,\n            keepMenu: getWindowBreakpoint(),\n            filter: getState().page.filter,\n            pageType: PageType.AllArticles,\n            init: init,\n        } as PageActionTypes)\n    }\n}\n\nexport function selectSources(\n    sids: number[],\n    menuKey: string,\n    title: string\n): AppThunk {\n    return (dispatch, getState) => {\n        if (getState().app.menuKey !== menuKey) {\n            dispatch({\n                type: SELECT_PAGE,\n                pageType: PageType.Sources,\n                keepMenu: getWindowBreakpoint(),\n                filter: getState().page.filter,\n                sids: sids,\n                menuKey: menuKey,\n                title: title,\n                init: true,\n            } as PageActionTypes)\n        }\n    }\n}\n\nexport function switchView(viewType: ViewType): PageActionTypes {\n    return {\n        type: SWITCH_VIEW,\n        viewType: viewType,\n    }\n}\n\nexport function setViewConfigs(configs: ViewConfigs): AppThunk {\n    return (dispatch, getState) => {\n        window.settings.setViewConfigs(getState().page.viewType, configs)\n        dispatch({\n            type: \"SET_VIEW_CONFIGS\",\n            configs: configs,\n        })\n    }\n}\n\nexport function showItem(feedId: string, item: RSSItem): AppThunk {\n    return (dispatch, getState) => {\n        const state = getState()\n        if (\n            state.items.hasOwnProperty(item._id) &&\n            state.sources.hasOwnProperty(item.source)\n        ) {\n            dispatch({\n                type: SHOW_ITEM,\n                feedId: feedId,\n                item: item,\n            })\n        }\n    }\n}\nexport function showItemFromId(iid: number): AppThunk {\n    return (dispatch, getState) => {\n        const state = getState()\n        const item = state.items[iid]\n        if (!item.hasRead) dispatch(markRead(item))\n        if (item) dispatch(showItem(null, item))\n    }\n}\n\nexport const dismissItem = (): PageActionTypes => ({ type: DISMISS_ITEM })\n\nexport const toggleSearch = (): AppThunk => {\n    return (dispatch, getState) => {\n        let state = getState()\n        dispatch({ type: TOGGLE_SEARCH })\n        if (!getWindowBreakpoint() && state.app.menu) {\n            dispatch(toggleMenu())\n        }\n        if (state.page.searchOn) {\n            dispatch(\n                applyFilter({\n                    ...state.page.filter,\n                    search: \"\",\n                })\n            )\n        }\n    }\n}\n\nexport function showOffsetItem(offset: number): AppThunk {\n    return (dispatch, getState) => {\n        let state = getState()\n        if (!state.page.itemFromFeed) return\n        let [itemId, feedId] = [state.page.itemId, state.page.feedId]\n        let feed = state.feeds[feedId]\n        let iids = feed.iids\n        let itemIndex = iids.indexOf(itemId)\n        let newIndex = itemIndex + offset\n        if (itemIndex < 0) {\n            let item = state.items[itemId]\n            let prevs = feed.iids\n                .map(\n                    (id, index) => [state.items[id], index] as [RSSItem, number]\n                )\n                .filter(([i, _]) => i.date > item.date)\n            if (prevs.length > 0) {\n                let prev = prevs[0]\n                for (let j = 1; j < prevs.length; j += 1) {\n                    if (prevs[j][0].date < prev[0].date) prev = prevs[j]\n                }\n                newIndex = prev[1] + offset + (offset < 0 ? 1 : 0)\n            } else {\n                newIndex = offset - 1\n            }\n        }\n        if (newIndex >= 0) {\n            if (newIndex < iids.length) {\n                let item = state.items[iids[newIndex]]\n                dispatch(markRead(item))\n                dispatch(showItem(feedId, item))\n                return\n            } else if (!feed.allLoaded) {\n                dispatch(loadMore(feed))\n                    .then(() => {\n                        dispatch(showOffsetItem(offset))\n                    })\n                    .catch(() => dispatch(dismissItem()))\n                return\n            }\n        }\n        dispatch(dismissItem())\n    }\n}\n\nconst applyFilterDone = (filter: FeedFilter): PageActionTypes => ({\n    type: APPLY_FILTER,\n    filter: filter,\n})\n\nfunction applyFilter(filter: FeedFilter): AppThunk {\n    return (dispatch, getState) => {\n        const oldFilterType = getState().page.filter.type\n        if (filter.type !== oldFilterType)\n            window.settings.setFilterType(filter.type)\n        dispatch(applyFilterDone(filter))\n        dispatch(initFeeds(true))\n    }\n}\n\nexport function switchFilter(filter: FilterType): AppThunk {\n    return (dispatch, getState) => {\n        let oldFilter = getState().page.filter\n        let oldType = oldFilter.type\n        let newType = filter | (oldType & FilterType.Toggles)\n        if (oldType != newType) {\n            dispatch(\n                applyFilter({\n                    ...oldFilter,\n                    type: newType,\n                })\n            )\n        }\n    }\n}\n\nexport function toggleFilter(filter: FilterType): AppThunk {\n    return (dispatch, getState) => {\n        let nextFilter = { ...getState().page.filter }\n        nextFilter.type ^= filter\n        dispatch(applyFilter(nextFilter))\n    }\n}\n\nexport function performSearch(query: string): AppThunk {\n    return (dispatch, getState) => {\n        let state = getState()\n        if (state.page.searchOn) {\n            dispatch(\n                applyFilter({\n                    ...state.page.filter,\n                    search: query,\n                })\n            )\n        }\n    }\n}\n\nexport class PageState {\n    viewType = window.settings.getDefaultView()\n    viewConfigs = window.settings.getViewConfigs(\n        window.settings.getDefaultView()\n    )\n    filter = new FeedFilter()\n    feedId = ALL\n    itemId = null as number\n    itemFromFeed = true\n    searchOn = false\n}\n\nexport function pageReducer(\n    state = new PageState(),\n    action: PageActionTypes | SourceActionTypes | FeedActionTypes\n): PageState {\n    switch (action.type) {\n        case SELECT_PAGE:\n            switch (action.pageType) {\n                case PageType.AllArticles:\n                    return {\n                        ...state,\n                        feedId: ALL,\n                        itemId: null,\n                    }\n                case PageType.Sources:\n                    return {\n                        ...state,\n                        feedId: SOURCE,\n                        itemId: null,\n                    }\n                default:\n                    return state\n            }\n        case SWITCH_VIEW:\n            return {\n                ...state,\n                viewType: action.viewType,\n                viewConfigs: window.settings.getViewConfigs(action.viewType),\n                itemId: null,\n            }\n        case SET_VIEW_CONFIGS:\n            return {\n                ...state,\n                viewConfigs: action.configs,\n            }\n        case APPLY_FILTER:\n            return {\n                ...state,\n                filter: action.filter,\n            }\n        case SHOW_ITEM:\n            return {\n                ...state,\n                itemId: action.item._id,\n                itemFromFeed: Boolean(action.feedId),\n            }\n        case INIT_FEED:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        itemId:\n                            action.feed._id === state.feedId &&\n                            action.items.filter(i => i._id === state.itemId)\n                                .length === 0\n                                ? null\n                                : state.itemId,\n                    }\n                default:\n                    return state\n            }\n        case DELETE_SOURCE:\n        case DISMISS_ITEM:\n            return {\n                ...state,\n                itemId: null,\n            }\n        case TOGGLE_SEARCH:\n            return {\n                ...state,\n                searchOn: !state.searchOn,\n            }\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/rule.ts",
    "content": "import { FeedFilter, FilterType } from \"./feed\"\nimport { RSSItem } from \"./item\"\n\nexport const enum ItemAction {\n    Read = \"r\",\n    Star = \"s\",\n    Hide = \"h\",\n    Notify = \"n\",\n}\n\nexport type RuleActions = {\n    [type in ItemAction]: boolean\n}\nexport namespace RuleActions {\n    export function toKeys(actions: RuleActions): string[] {\n        return Object.entries(actions).map(([t, f]) => `${t}-${f}`)\n    }\n\n    export function fromKeys(strs: string[]): RuleActions {\n        const fromKey = (str: string): [ItemAction, boolean] => {\n            let [t, f] = str.split(\"-\") as [ItemAction, string]\n            if (f) return [t, f === \"true\"]\n            else return [t, true]\n        }\n        return Object.fromEntries(strs.map(fromKey)) as RuleActions\n    }\n}\n\ntype ActionTransformType = {\n    [type in ItemAction]: (i: RSSItem, f: boolean) => void\n}\nconst actionTransform: ActionTransformType = {\n    [ItemAction.Read]: (i, f) => {\n        i.hasRead = f\n    },\n    [ItemAction.Star]: (i, f) => {\n        i.starred = f\n    },\n    [ItemAction.Hide]: (i, f) => {\n        i.hidden = f\n    },\n    [ItemAction.Notify]: (i, f) => {\n        i.notify = f\n    },\n}\n\nexport class SourceRule {\n    filter: FeedFilter\n    match: boolean\n    actions: RuleActions\n\n    constructor(\n        regex: string,\n        actions: string[],\n        filter: FilterType,\n        match: boolean\n    ) {\n        this.filter = new FeedFilter(filter, regex)\n        this.match = match\n        this.actions = RuleActions.fromKeys(actions)\n    }\n\n    static apply(rule: SourceRule, item: RSSItem) {\n        let result = FeedFilter.testItem(rule.filter, item)\n        if (result === rule.match) {\n            for (let [action, flag] of Object.entries(rule.actions)) {\n                actionTransform[action](item, flag)\n            }\n        }\n    }\n\n    static applyAll(rules: SourceRule[], item: RSSItem) {\n        for (let rule of rules) {\n            this.apply(rule, item)\n        }\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/service.ts",
    "content": "import * as db from \"../db\"\nimport lf from \"lovefield\"\nimport { SyncService, ServiceConfigs } from \"../../schema-types\"\nimport { AppThunk, ActionStatus } from \"../utils\"\nimport { RSSItem, insertItems, fetchItemsSuccess } from \"./item\"\nimport { saveSettings, pushNotification } from \"./app\"\nimport {\n    deleteSource,\n    updateUnreadCounts,\n    RSSSource,\n    insertSource,\n    addSourceSuccess,\n    updateSource,\n    updateFavicon,\n} from \"./source\"\nimport { createSourceGroup, addSourceToGroup } from \"./group\"\n\nimport { feverServiceHooks } from \"./services/fever\"\nimport { feedbinServiceHooks } from \"./services/feedbin\"\nimport { gReaderServiceHooks } from \"./services/greader\"\nimport { minifluxServiceHooks } from \"./services/miniflux\"\nimport { nextcloudServiceHooks } from \"./services/nextcloud\"\n\nexport interface ServiceHooks {\n    authenticate?: (configs: ServiceConfigs) => Promise<boolean>\n    reauthenticate?: (configs: ServiceConfigs) => Promise<ServiceConfigs>\n    updateSources?: () => AppThunk<Promise<[RSSSource[], Map<string, string>]>>\n    fetchItems?: () => AppThunk<Promise<[RSSItem[], ServiceConfigs]>>\n    syncItems?: () => AppThunk<Promise<[Set<string>, Set<string>]>>\n    markRead?: (item: RSSItem) => AppThunk\n    markUnread?: (item: RSSItem) => AppThunk\n    markAllRead?: (\n        sids?: number[],\n        date?: Date,\n        before?: boolean\n    ) => AppThunk<Promise<void>>\n    star?: (item: RSSItem) => AppThunk\n    unstar?: (item: RSSItem) => AppThunk\n}\n\nexport function getServiceHooksFromType(type: SyncService): ServiceHooks {\n    switch (type) {\n        case SyncService.Fever:\n            return feverServiceHooks\n        case SyncService.Feedbin:\n            return feedbinServiceHooks\n        case SyncService.GReader:\n        case SyncService.Inoreader:\n            return gReaderServiceHooks\n        case SyncService.Miniflux:\n            return minifluxServiceHooks\n        case SyncService.Nextcloud:\n            return nextcloudServiceHooks\n        default:\n            return {}\n    }\n}\n\nexport function getServiceHooks(): AppThunk<ServiceHooks> {\n    return (_, getState) => {\n        return getServiceHooksFromType(getState().service.type)\n    }\n}\n\nexport function syncWithService(background = false): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const hooks = dispatch(getServiceHooks())\n        if (hooks.updateSources && hooks.fetchItems && hooks.syncItems) {\n            try {\n                dispatch({\n                    type: SYNC_SERVICE,\n                    status: ActionStatus.Request,\n                })\n                if (hooks.reauthenticate) await dispatch(reauthenticate(hooks))\n                await dispatch(updateSources(hooks.updateSources))\n                await dispatch(syncItems(hooks.syncItems))\n                await dispatch(fetchItems(hooks.fetchItems, background))\n                dispatch({\n                    type: SYNC_SERVICE,\n                    status: ActionStatus.Success,\n                })\n            } catch (err) {\n                console.log(err)\n                dispatch({\n                    type: SYNC_SERVICE,\n                    status: ActionStatus.Failure,\n                    err: err,\n                })\n            } finally {\n                if (getState().app.settings.saving) dispatch(saveSettings())\n            }\n        }\n    }\n}\n\nfunction reauthenticate(hooks: ServiceHooks): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        let configs = getState().service\n        if (!(await hooks.authenticate(configs))) {\n            configs = await hooks.reauthenticate(configs)\n            dispatch(saveServiceConfigs(configs))\n        }\n    }\n}\n\nfunction updateSources(\n    hook: ServiceHooks[\"updateSources\"]\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const [sources, groupsMap] = await dispatch(hook())\n        const existing = new Map<string, RSSSource>()\n        for (let source of Object.values(getState().sources)) {\n            if (source.serviceRef) {\n                existing.set(source.serviceRef, source)\n            }\n        }\n        const forceSettings = () => {\n            if (!getState().app.settings.saving) dispatch(saveSettings())\n        }\n        let promises = sources.map(async s => {\n            if (existing.has(s.serviceRef)) {\n                const doc = existing.get(s.serviceRef)\n                existing.delete(s.serviceRef)\n                return doc\n            } else {\n                const docs = (await db.sourcesDB\n                    .select()\n                    .from(db.sources)\n                    .where(db.sources.url.eq(s.url))\n                    .exec()) as RSSSource[]\n                if (docs.length === 0) {\n                    // Create a new source\n                    forceSettings()\n                    const inserted = await dispatch(insertSource(s))\n                    inserted.unreadCount = 0\n                    dispatch(addSourceSuccess(inserted, true))\n                    window.settings.saveGroups(getState().groups)\n                    dispatch(updateFavicon([inserted.sid]))\n                    return inserted\n                } else if (docs[0].serviceRef !== s.serviceRef) {\n                    // Mark an existing source as remote and remove all items\n                    const doc = docs[0]\n                    forceSettings()\n                    doc.serviceRef = s.serviceRef\n                    doc.unreadCount = 0\n                    await dispatch(updateSource(doc))\n                    await db.itemsDB\n                        .delete()\n                        .from(db.items)\n                        .where(db.items.source.eq(doc.sid))\n                        .exec()\n                    return doc\n                } else {\n                    return docs[0]\n                }\n            }\n        })\n        for (let [_, source] of existing) {\n            // Delete sources removed from the service side\n            forceSettings()\n            promises.push(dispatch(deleteSource(source, true)).then(() => null))\n        }\n        let sourcesResults = (await Promise.all(promises)).filter(s => s)\n        if (groupsMap) {\n            // Add sources to imported groups\n            forceSettings()\n            for (let source of sourcesResults) {\n                if (groupsMap.has(source.serviceRef)) {\n                    const gid = dispatch(\n                        createSourceGroup(groupsMap.get(source.serviceRef))\n                    )\n                    dispatch(addSourceToGroup(gid, source.sid))\n                }\n            }\n            const configs = getState().service\n            delete configs.importGroups\n            dispatch(saveServiceConfigs(configs))\n        }\n    }\n}\n\nfunction syncItems(hook: ServiceHooks[\"syncItems\"]): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const state = getState()\n        const [unreadRefs, starredRefs] = await dispatch(hook())\n        const unreadCopy = new Set(unreadRefs)\n        const starredCopy = new Set(starredRefs)\n        const rows = await db.itemsDB\n            .select(db.items.serviceRef, db.items.hasRead, db.items.starred)\n            .from(db.items)\n            .where(\n                lf.op.and(\n                    db.items.serviceRef.isNotNull(),\n                    lf.op.or(\n                        db.items.hasRead.eq(false),\n                        db.items.starred.eq(true)\n                    )\n                )\n            )\n            .exec()\n        const updates = new Array<lf.query.Update>()\n        for (let row of rows) {\n            const serviceRef = row[\"serviceRef\"]\n            if (row[\"hasRead\"] === false && !unreadRefs.delete(serviceRef)) {\n                updates.push(\n                    db.itemsDB\n                        .update(db.items)\n                        .set(db.items.hasRead, true)\n                        .where(db.items.serviceRef.eq(serviceRef))\n                )\n            }\n            if (row[\"starred\"] === true && !starredRefs.delete(serviceRef)) {\n                updates.push(\n                    db.itemsDB\n                        .update(db.items)\n                        .set(db.items.starred, false)\n                        .where(db.items.serviceRef.eq(serviceRef))\n                )\n            }\n        }\n        for (let unread of unreadRefs) {\n            updates.push(\n                db.itemsDB\n                    .update(db.items)\n                    .set(db.items.hasRead, false)\n                    .where(db.items.serviceRef.eq(unread))\n            )\n        }\n        for (let starred of starredRefs) {\n            updates.push(\n                db.itemsDB\n                    .update(db.items)\n                    .set(db.items.starred, true)\n                    .where(db.items.serviceRef.eq(starred))\n            )\n        }\n        if (updates.length > 0) {\n            await db.itemsDB.createTransaction().exec(updates)\n            await dispatch(updateUnreadCounts())\n            dispatch(syncLocalItems(unreadCopy, starredCopy))\n        }\n    }\n}\n\nfunction fetchItems(\n    hook: ServiceHooks[\"fetchItems\"],\n    background: boolean\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const [items, configs] = await dispatch(hook())\n        if (items.length > 0) {\n            const inserted = await insertItems(items)\n            dispatch(fetchItemsSuccess(inserted.reverse(), getState().items))\n            if (background) {\n                for (let item of inserted) {\n                    if (item.notify) dispatch(pushNotification(item))\n                }\n                if (inserted.length > 0) window.utils.requestAttention()\n            }\n            dispatch(saveServiceConfigs(configs))\n        }\n    }\n}\n\nexport function importGroups(): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const configs = getState().service\n        if (configs.type !== SyncService.None) {\n            dispatch(saveSettings())\n            configs.importGroups = true\n            dispatch(saveServiceConfigs(configs))\n            await dispatch(syncWithService())\n        }\n    }\n}\n\nexport function removeService(): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        dispatch(saveSettings())\n        const state = getState()\n        const promises = Object.values(state.sources)\n            .filter(s => s.serviceRef)\n            .map(async s => {\n                await dispatch(deleteSource(s, true))\n            })\n        await Promise.all(promises)\n        dispatch(saveServiceConfigs({ type: SyncService.None }))\n        dispatch(saveSettings())\n    }\n}\n\nexport const SAVE_SERVICE_CONFIGS = \"SAVE_SERVICE_CONFIGS\"\nexport const SYNC_SERVICE = \"SYNC_SERVICE\"\nexport const SYNC_LOCAL_ITEMS = \"SYNC_LOCAL_ITEMS\"\n\ninterface SaveServiceConfigsAction {\n    type: typeof SAVE_SERVICE_CONFIGS\n    configs: ServiceConfigs\n}\n\ninterface SyncWithServiceAction {\n    type: typeof SYNC_SERVICE\n    status: ActionStatus\n    err?\n}\n\ninterface SyncLocalItemsAction {\n    type: typeof SYNC_LOCAL_ITEMS\n    unreadIds: Set<string>\n    starredIds: Set<string>\n}\n\nexport type ServiceActionTypes =\n    | SaveServiceConfigsAction\n    | SyncWithServiceAction\n    | SyncLocalItemsAction\n\nexport function saveServiceConfigs(configs: ServiceConfigs): AppThunk {\n    return dispatch => {\n        window.settings.setServiceConfigs(configs)\n        dispatch({\n            type: SAVE_SERVICE_CONFIGS,\n            configs: configs,\n        })\n    }\n}\n\nfunction syncLocalItems(\n    unread: Set<string>,\n    starred: Set<string>\n): ServiceActionTypes {\n    return {\n        type: SYNC_LOCAL_ITEMS,\n        unreadIds: unread,\n        starredIds: starred,\n    }\n}\n\nexport function serviceReducer(\n    state = window.settings.getServiceConfigs(),\n    action: ServiceActionTypes\n): ServiceConfigs {\n    switch (action.type) {\n        case SAVE_SERVICE_CONFIGS:\n            return action.configs\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/models/services/feedbin.ts",
    "content": "import intl from \"react-intl-universal\"\nimport * as db from \"../../db\"\nimport lf from \"lovefield\"\nimport { ServiceHooks } from \"../service\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { createSourceGroup } from \"../group\"\nimport { RSSSource } from \"../source\"\nimport { domParser } from \"../../utils\"\nimport { RSSItem } from \"../item\"\nimport { SourceRule } from \"../rule\"\n\nexport interface FeedbinConfigs extends ServiceConfigs {\n    type: SyncService.Feedbin\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    lastId?: number\n}\n\nasync function fetchAPI(configs: FeedbinConfigs, params: string) {\n    const headers = new Headers()\n    headers.set(\n        \"Authorization\",\n        \"Basic \" + btoa(configs.username + \":\" + configs.password)\n    )\n    return await fetch(configs.endpoint + params, { headers: headers })\n}\n\nasync function markItems(\n    configs: FeedbinConfigs,\n    type: string,\n    method: string,\n    refs: number[]\n) {\n    const headers = new Headers()\n    headers.set(\n        \"Authorization\",\n        \"Basic \" + btoa(configs.username + \":\" + configs.password)\n    )\n    headers.set(\"Content-Type\", \"application/json; charset=utf-8\")\n    const promises = new Array<Promise<Response>>()\n    while (refs.length > 0) {\n        const batch = new Array<number>()\n        while (batch.length < 1000 && refs.length > 0) {\n            batch.push(refs.pop())\n        }\n        const bodyObject: any = {}\n        bodyObject[`${type}_entries`] = batch\n        promises.push(\n            fetch(configs.endpoint + type + \"_entries.json\", {\n                method: method,\n                headers: headers,\n                body: JSON.stringify(bodyObject),\n            })\n        )\n    }\n    return await Promise.all(promises)\n}\n\nconst APIError = () => new Error(intl.get(\"service.failure\"))\n\nexport const feedbinServiceHooks: ServiceHooks = {\n    authenticate: async (configs: FeedbinConfigs) => {\n        try {\n            const result = await fetchAPI(configs, \"authentication.json\")\n            return result.status === 200\n        } catch {\n            return false\n        }\n    },\n\n    updateSources: () => async (dispatch, getState) => {\n        const configs = getState().service as FeedbinConfigs\n        const response = await fetchAPI(configs, \"subscriptions.json\")\n        if (response.status !== 200) throw APIError()\n        const subscriptions: any[] = await response.json()\n        let groupsMap: Map<string, string>\n        if (configs.importGroups) {\n            const tagsResponse = await fetchAPI(configs, \"taggings.json\")\n            if (tagsResponse.status !== 200) throw APIError()\n            const tags: any[] = await tagsResponse.json()\n            const tagsSet = new Set<string>()\n            groupsMap = new Map()\n            for (let tag of tags) {\n                const title = tag.name.trim()\n                if (!tagsSet.has(title)) {\n                    tagsSet.add(title)\n                    dispatch(createSourceGroup(title))\n                }\n                groupsMap.set(String(tag.feed_id), title)\n            }\n        }\n        const sources = subscriptions.map(s => {\n            const source = new RSSSource(s.feed_url, s.title)\n            source.serviceRef = String(s.feed_id)\n            return source\n        })\n        return [sources, groupsMap]\n    },\n\n    syncItems: () => async (_, getState) => {\n        const configs = getState().service as FeedbinConfigs\n        const [unreadResponse, starredResponse] = await Promise.all([\n            fetchAPI(configs, \"unread_entries.json\"),\n            fetchAPI(configs, \"starred_entries.json\"),\n        ])\n        if (unreadResponse.status !== 200 || starredResponse.status !== 200)\n            throw APIError()\n        const unread = await unreadResponse.json()\n        const starred = await starredResponse.json()\n        return [\n            new Set(unread.map(i => String(i))),\n            new Set(starred.map(i => String(i))),\n        ]\n    },\n\n    fetchItems: () => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as FeedbinConfigs\n        const items = new Array()\n        configs.lastId = configs.lastId || 0\n        let page = 1\n        let min = Number.MAX_SAFE_INTEGER\n        let lastFetched: any[]\n        do {\n            try {\n                const response = await fetchAPI(\n                    configs,\n                    \"entries.json?mode=extended&per_page=125&page=\" + page\n                )\n                if (response.status !== 200) throw APIError()\n                lastFetched = await response.json()\n                items.push(\n                    ...lastFetched.filter(\n                        i => i.id > configs.lastId && i.id < min\n                    )\n                )\n                min = lastFetched.reduce((m, n) => Math.min(m, n.id), min)\n                page += 1\n            } catch {\n                break\n            }\n        } while (\n            min > configs.lastId &&\n            lastFetched &&\n            lastFetched.length >= 125 &&\n            items.length < configs.fetchLimit\n        )\n        configs.lastId = items.reduce(\n            (m, n) => Math.max(m, n.id),\n            configs.lastId\n        )\n        if (items.length > 0) {\n            const fidMap = new Map<string, RSSSource>()\n            for (let source of Object.values(state.sources)) {\n                if (source.serviceRef) {\n                    fidMap.set(source.serviceRef, source)\n                }\n            }\n            const [unreadResponse, starredResponse] = await Promise.all([\n                fetchAPI(configs, \"unread_entries.json\"),\n                fetchAPI(configs, \"starred_entries.json\"),\n            ])\n            if (unreadResponse.status !== 200 || starredResponse.status !== 200)\n                throw APIError()\n            const unread: Set<number> = new Set(await unreadResponse.json())\n            const starred: Set<number> = new Set(await starredResponse.json())\n            const parsedItems = new Array<RSSItem>()\n            items.forEach(i => {\n                if (i.content === null) return\n                const source = fidMap.get(String(i.feed_id))\n                const dom = domParser.parseFromString(i.content, \"text/html\")\n                const item = {\n                    source: source.sid,\n                    title: i.title,\n                    link: i.url,\n                    date: new Date(i.published),\n                    fetchedDate: new Date(i.created_at),\n                    content: i.content,\n                    snippet: dom.documentElement.textContent.trim(),\n                    creator: i.author,\n                    hasRead: !unread.has(i.id),\n                    starred: starred.has(i.id),\n                    hidden: false,\n                    notify: false,\n                    serviceRef: String(i.id),\n                } as RSSItem\n                if (i.images && i.images.original_url) {\n                    item.thumb = i.images.original_url\n                } else {\n                    let baseEl = dom.createElement(\"base\")\n                    baseEl.setAttribute(\n                        \"href\",\n                        item.link.split(\"/\").slice(0, 3).join(\"/\")\n                    )\n                    dom.head.append(baseEl)\n                    let img = dom.querySelector(\"img\")\n                    if (img && img.src) item.thumb = img.src\n                }\n                // Apply rules and sync back to the service\n                if (source.rules) SourceRule.applyAll(source.rules, item)\n                if (unread.has(i.id) === item.hasRead)\n                    markItems(\n                        configs,\n                        \"unread\",\n                        item.hasRead ? \"DELETE\" : \"POST\",\n                        [i.id]\n                    )\n                if (starred.has(i.id) !== Boolean(item.starred))\n                    markItems(\n                        configs,\n                        \"starred\",\n                        item.starred ? \"POST\" : \"DELETE\",\n                        [i.id]\n                    )\n                parsedItems.push(item)\n            })\n            return [parsedItems, configs]\n        } else {\n            return [[], configs]\n        }\n    },\n\n    markAllRead: (sids, date, before) => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as FeedbinConfigs\n        const predicates: lf.Predicate[] = [\n            db.items.source.in(sids),\n            db.items.hasRead.eq(false),\n            db.items.serviceRef.isNotNull(),\n        ]\n        if (date) {\n            predicates.push(\n                before ? db.items.date.lte(date) : db.items.date.gte(date)\n            )\n        }\n        const query = lf.op.and.apply(null, predicates)\n        const rows = await db.itemsDB\n            .select(db.items.serviceRef)\n            .from(db.items)\n            .where(query)\n            .exec()\n        const refs = rows.map(row => parseInt(row[\"serviceRef\"]))\n        markItems(configs, \"unread\", \"DELETE\", refs)\n    },\n\n    markRead: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as FeedbinConfigs,\n            \"unread\",\n            \"DELETE\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    markUnread: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as FeedbinConfigs,\n            \"unread\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    star: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as FeedbinConfigs,\n            \"starred\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    unstar: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as FeedbinConfigs,\n            \"starred\",\n            \"DELETE\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n}\n"
  },
  {
    "path": "src/scripts/models/services/fever.ts",
    "content": "import intl from \"react-intl-universal\"\nimport { ServiceHooks } from \"../service\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { createSourceGroup } from \"../group\"\nimport { RSSSource } from \"../source\"\nimport { htmlDecode, domParser } from \"../../utils\"\nimport { RSSItem } from \"../item\"\nimport { SourceRule } from \"../rule\"\n\nexport interface FeverConfigs extends ServiceConfigs {\n    type: SyncService.Fever\n    endpoint: string\n    username: string\n    apiKey: string\n    fetchLimit: number\n    lastId?: number\n    useInt32?: boolean\n}\n\nasync function fetchAPI(configs: FeverConfigs, params = \"\", postparams = \"\") {\n    const response = await fetch(configs.endpoint + \"?api\" + params, {\n        method: \"POST\",\n        headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n        body: `api_key=${configs.apiKey}${postparams}`,\n    })\n    return await response.json()\n}\n\nasync function markItem(configs: FeverConfigs, item: RSSItem, as: string) {\n    if (item.serviceRef) {\n        try {\n            await fetchAPI(\n                configs,\n                \"\",\n                `&mark=item&as=${as}&id=${item.serviceRef}`\n            )\n        } catch (err) {\n            console.log(err)\n        }\n    }\n}\n\nconst APIError = () => new Error(intl.get(\"service.failure\"))\n\nexport const feverServiceHooks: ServiceHooks = {\n    authenticate: async (configs: FeverConfigs) => {\n        try {\n            return Boolean((await fetchAPI(configs)).auth)\n        } catch {\n            return false\n        }\n    },\n\n    updateSources: () => async (dispatch, getState) => {\n        const configs = getState().service as FeverConfigs\n        const response = await fetchAPI(configs, \"&feeds\")\n        const feeds: any[] = response.feeds\n        const feedGroups: any[] = response.feeds_groups\n        if (feeds === undefined) throw APIError()\n        let groupsMap: Map<string, string>\n        if (configs.importGroups) {\n            // Import groups on the first sync\n            const groups: any[] = (await fetchAPI(configs, \"&groups\")).groups\n            if (groups === undefined || feedGroups === undefined)\n                throw APIError()\n            const groupsIdMap = new Map<number, string>()\n            for (let group of groups) {\n                const title = group.title.trim()\n                dispatch(createSourceGroup(title))\n                groupsIdMap.set(group.id, title)\n            }\n            groupsMap = new Map()\n            for (let group of feedGroups) {\n                for (let fid of group.feed_ids.split(\",\")) {\n                    groupsMap.set(fid, groupsIdMap.get(group.group_id))\n                }\n            }\n        }\n        const sources = feeds.map(f => {\n            const source = new RSSSource(f.url, f.title)\n            source.serviceRef = String(f.id)\n            return source\n        })\n        return [sources, groupsMap]\n    },\n\n    fetchItems: () => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as FeverConfigs\n        const items = new Array()\n        configs.lastId = configs.lastId || 0\n        let min = configs.useInt32 ? 2147483647 : Number.MAX_SAFE_INTEGER\n        let response\n        do {\n            response = await fetchAPI(configs, `&items&max_id=${min}`)\n            if (response.items === undefined) throw APIError()\n            items.push(...response.items.filter(i => i.id > configs.lastId))\n            if (\n                response.items.length === 0 &&\n                min === Number.MAX_SAFE_INTEGER\n            ) {\n                configs.useInt32 = true\n                min = 2147483647\n                response = undefined\n            } else {\n                min = response.items.reduce((m, n) => Math.min(m, n.id), min)\n            }\n        } while (\n            min > configs.lastId &&\n            (response === undefined || response.items.length >= 50) &&\n            items.length < configs.fetchLimit\n        )\n        configs.lastId = items.reduce(\n            (m, n) => Math.max(m, n.id),\n            configs.lastId\n        )\n        if (items.length > 0) {\n            const fidMap = new Map<string, RSSSource>()\n            for (let source of Object.values(state.sources)) {\n                if (source.serviceRef) {\n                    fidMap.set(source.serviceRef, source)\n                }\n            }\n            const parsedItems = items.map(i => {\n                const source = fidMap.get(String(i.feed_id))\n                const item = {\n                    source: source.sid,\n                    title: i.title,\n                    link: i.url,\n                    date: new Date(i.created_on_time * 1000),\n                    fetchedDate: new Date(),\n                    content: i.html,\n                    snippet: htmlDecode(i.html).trim(),\n                    creator: i.author,\n                    hasRead: Boolean(i.is_read),\n                    starred: Boolean(i.is_saved),\n                    hidden: false,\n                    notify: false,\n                    serviceRef: String(i.id),\n                } as RSSItem\n                // Try to get the thumbnail of the item\n                let dom = domParser.parseFromString(item.content, \"text/html\")\n                let baseEl = dom.createElement(\"base\")\n                baseEl.setAttribute(\n                    \"href\",\n                    item.link.split(\"/\").slice(0, 3).join(\"/\")\n                )\n                dom.head.append(baseEl)\n                let img = dom.querySelector(\"img\")\n                if (img && img.src) {\n                    item.thumb = img.src\n                } else if (configs.useInt32) {\n                    // TTRSS Fever Plugin attachments\n                    let a = dom.querySelector(\n                        \"body>ul>li:first-child>a\"\n                    ) as HTMLAnchorElement\n                    if (a && /, image\\/generic$/.test(a.innerText) && a.href)\n                        item.thumb = a.href\n                }\n                // Apply rules and sync back to the service\n                if (source.rules) SourceRule.applyAll(source.rules, item)\n                if (Boolean(i.is_read) !== item.hasRead)\n                    markItem(configs, item, item.hasRead ? \"read\" : \"unread\")\n                if (Boolean(i.is_saved) !== Boolean(item.starred))\n                    markItem(configs, item, item.starred ? \"saved\" : \"unsaved\")\n                return item\n            })\n            return [parsedItems, configs]\n        } else {\n            return [[], configs]\n        }\n    },\n\n    syncItems: () => async (_, getState) => {\n        const configs = getState().service as FeverConfigs\n        const [unreadResponse, starredResponse] = await Promise.all([\n            fetchAPI(configs, \"&unread_item_ids\"),\n            fetchAPI(configs, \"&saved_item_ids\"),\n        ])\n        if (\n            typeof unreadResponse.unread_item_ids !== \"string\" ||\n            typeof starredResponse.saved_item_ids !== \"string\"\n        ) {\n            throw APIError()\n        }\n        const unreadFids: string[] = unreadResponse.unread_item_ids.split(\",\")\n        const starredFids: string[] = starredResponse.saved_item_ids.split(\",\")\n        return [new Set(unreadFids), new Set(starredFids)]\n    },\n\n    markAllRead: (sids, date, before) => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as FeverConfigs\n        if (date && !before) {\n            const iids = state.feeds[state.page.feedId].iids\n            const items = iids\n                .map(iid => state.items[iid])\n                .filter(i => !i.hasRead && i.date.getTime() >= date.getTime())\n            for (let item of items) {\n                if (item.serviceRef) {\n                    markItem(configs, item, \"read\")\n                }\n            }\n        } else {\n            const sources = sids.map(sid => state.sources[sid])\n            const timestamp =\n                Math.floor((date ? date.getTime() : Date.now()) / 1000) + 1\n            for (let source of sources) {\n                if (source.serviceRef) {\n                    fetchAPI(\n                        configs,\n                        \"\",\n                        `&mark=feed&as=read&id=${source.serviceRef}&before=${timestamp}`\n                    )\n                }\n            }\n        }\n    },\n\n    markRead: (item: RSSItem) => async (_, getState) => {\n        await markItem(getState().service as FeverConfigs, item, \"read\")\n    },\n\n    markUnread: (item: RSSItem) => async (_, getState) => {\n        await markItem(getState().service as FeverConfigs, item, \"unread\")\n    },\n\n    star: (item: RSSItem) => async (_, getState) => {\n        await markItem(getState().service as FeverConfigs, item, \"saved\")\n    },\n\n    unstar: (item: RSSItem) => async (_, getState) => {\n        await markItem(getState().service as FeverConfigs, item, \"unsaved\")\n    },\n}\n"
  },
  {
    "path": "src/scripts/models/services/greader.ts",
    "content": "import intl from \"react-intl-universal\"\nimport * as db from \"../../db\"\nimport lf from \"lovefield\"\nimport { ServiceHooks } from \"../service\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { createSourceGroup } from \"../group\"\nimport { RSSSource } from \"../source\"\nimport { RSSItem } from \"../item\"\nimport { domParser, htmlDecode } from \"../../utils\"\nimport { SourceRule } from \"../rule\"\n\nconst ALL_TAG = \"user/-/state/com.google/reading-list\"\nconst READ_TAG = \"user/-/state/com.google/read\"\nconst STAR_TAG = \"user/-/state/com.google/starred\"\n\nexport interface GReaderConfigs extends ServiceConfigs {\n    type: SyncService.GReader | SyncService.Inoreader\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    lastFetched?: number\n    lastId?: string\n    auth?: string\n    useInt64: boolean // The Old Reader uses ids longer than 64 bits\n    inoreaderId?: string\n    inoreaderKey?: string\n    removeInoreaderAd?: boolean\n}\n\nasync function fetchAPI(\n    configs: GReaderConfigs,\n    params: string,\n    method = \"GET\",\n    body: BodyInit = null\n) {\n    const headers = new Headers()\n    if (configs.auth !== null) headers.set(\"Authorization\", configs.auth)\n    if (configs.type == SyncService.Inoreader) {\n        if (configs.inoreaderId) {\n            headers.set(\"AppId\", configs.inoreaderId)\n            headers.set(\"AppKey\", configs.inoreaderKey)\n        } else {\n            headers.set(\"AppId\", \"999999298\")\n            headers.set(\"AppKey\", \"KPbKYXTfgrKbwmroOeYC7mcW21ZRwF5Y\")\n        }\n    }\n    return await fetch(configs.endpoint + params, {\n        method: method,\n        headers: headers,\n        body: body,\n    })\n}\n\nasync function fetchAll(\n    configs: GReaderConfigs,\n    params: string\n): Promise<Set<string>> {\n    let results = new Array()\n    let fetched: any[]\n    let continuation: string\n    do {\n        let p = params\n        if (continuation) p += `&c=${continuation}`\n        const response = await fetchAPI(configs, p)\n        const parsed = await response.json()\n        fetched = parsed.itemRefs\n        if (fetched) {\n            for (let i of fetched) {\n                results.push(i.id)\n            }\n        }\n        continuation = parsed.continuation\n    } while (continuation && fetched && fetched.length >= 1000)\n    return new Set(results)\n}\n\nasync function editTag(\n    configs: GReaderConfigs,\n    ref: string,\n    tag: string,\n    add = true\n) {\n    const body = new URLSearchParams(`i=${ref}&${add ? \"a\" : \"r\"}=${tag}`)\n    return await fetchAPI(configs, \"/reader/api/0/edit-tag\", \"POST\", body)\n}\n\nfunction compactId(longId: string, useInt64: boolean) {\n    let parts = longId.split(\"/\")\n    const last = parts[parts.length - 1]\n    if (!useInt64) return last\n    let i = BigInt(\"0x\" + last)\n    return BigInt.asIntN(64, i).toString()\n}\n\nconst APIError = () => new Error(intl.get(\"service.failure\"))\n\nexport const gReaderServiceHooks: ServiceHooks = {\n    authenticate: async (configs: GReaderConfigs) => {\n        if (configs.auth !== null) {\n            try {\n                const result = await fetchAPI(\n                    configs,\n                    \"/reader/api/0/user-info\"\n                )\n                return result.status === 200\n            } catch {\n                return false\n            }\n        }\n    },\n\n    reauthenticate: async (\n        configs: GReaderConfigs\n    ): Promise<GReaderConfigs> => {\n        const body = new URLSearchParams()\n        body.append(\"Email\", configs.username)\n        body.append(\"Passwd\", configs.password)\n        const result = await fetchAPI(\n            configs,\n            \"/accounts/ClientLogin\",\n            \"POST\",\n            body\n        )\n        if (result.status === 200) {\n            const text = await result.text()\n            const matches = text.match(/Auth=(\\S+)/)\n            if (matches.length > 1)\n                configs.auth = \"GoogleLogin auth=\" + matches[1]\n            return configs\n        } else {\n            throw APIError()\n        }\n    },\n\n    updateSources: () => async (dispatch, getState) => {\n        const configs = getState().service as GReaderConfigs\n        const response = await fetchAPI(\n            configs,\n            \"/reader/api/0/subscription/list?output=json\"\n        )\n        if (response.status !== 200) throw APIError()\n        const subscriptions: any[] = (await response.json()).subscriptions\n        let groupsMap: Map<string, string>\n        if (configs.importGroups) {\n            groupsMap = new Map()\n            const groupSet = new Set<string>()\n            for (let s of subscriptions) {\n                if (s.categories && s.categories.length > 0) {\n                    const group: string = s.categories[0].label\n                    if (!groupSet.has(group)) {\n                        groupSet.add(group)\n                        dispatch(createSourceGroup(group))\n                    }\n                    groupsMap.set(s.id, group)\n                }\n            }\n        }\n        const sources = new Array<RSSSource>()\n        subscriptions.forEach(s => {\n            const source = new RSSSource(s.url || s.htmlUrl, s.title)\n            source.serviceRef = s.id\n            // Omit duplicate sources in The Old Reader\n            if (\n                configs.useInt64 ||\n                s.url != \"http://blog.theoldreader.com/rss\"\n            ) {\n                sources.push(source)\n            }\n        })\n        return [sources, groupsMap]\n    },\n\n    syncItems: () => async (_, getState) => {\n        const configs = getState().service as GReaderConfigs\n        if (configs.type == SyncService.Inoreader) {\n            return await Promise.all([\n                fetchAll(\n                    configs,\n                    `/reader/api/0/stream/items/ids?output=json&xt=${READ_TAG}&n=1000`\n                ),\n                fetchAll(\n                    configs,\n                    `/reader/api/0/stream/items/ids?output=json&it=${STAR_TAG}&n=1000`\n                ),\n            ])\n        } else {\n            return await Promise.all([\n                fetchAll(\n                    configs,\n                    `/reader/api/0/stream/items/ids?output=json&s=${ALL_TAG}&xt=${READ_TAG}&n=1000`\n                ),\n                fetchAll(\n                    configs,\n                    `/reader/api/0/stream/items/ids?output=json&s=${STAR_TAG}&n=1000`\n                ),\n            ])\n        }\n    },\n\n    fetchItems: () => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as GReaderConfigs\n        const items = new Array()\n        let fetchedItems: any[]\n        let continuation: string\n        do {\n            try {\n                const limit = Math.min(configs.fetchLimit - items.length, 1000)\n                let params = `/reader/api/0/stream/contents?output=json&n=${limit}`\n                if (configs.lastFetched) params += `&ot=${configs.lastFetched}`\n                if (continuation) params += `&c=${continuation}`\n                const response = await fetchAPI(configs, params)\n                let fetched = await response.json()\n                fetchedItems = fetched.items\n                for (let i of fetchedItems) {\n                    i.id = compactId(i.id, configs.useInt64)\n                    if (\n                        i.id === configs.lastId ||\n                        items.length >= configs.fetchLimit\n                    ) {\n                        break\n                    } else {\n                        items.push(i)\n                    }\n                }\n                continuation = fetched.continuation\n            } catch {\n                break\n            }\n        } while (continuation && items.length < configs.fetchLimit)\n        if (items.length > 0) {\n            configs.lastId = items[0].id\n            const fidMap = new Map<string, RSSSource>()\n            for (let source of Object.values(state.sources)) {\n                if (source.serviceRef) {\n                    fidMap.set(source.serviceRef, source)\n                }\n            }\n            const parsedItems = new Array<RSSItem>()\n            items.map(i => {\n                const source = fidMap.get(i.origin.streamId)\n                if (source === undefined) return\n                const dom = domParser.parseFromString(\n                    i.summary.content,\n                    \"text/html\"\n                )\n                if (\n                    configs.type == SyncService.Inoreader &&\n                    configs.removeInoreaderAd !== false\n                ) {\n                    if (\n                        dom.documentElement.textContent\n                            .trim()\n                            .startsWith(\"Ads from Inoreader\")\n                    ) {\n                        dom.body.firstChild.remove()\n                    }\n                }\n                const item = {\n                    source: source.sid,\n                    title: i.title,\n                    link: i.canonical[0].href,\n                    date: new Date(i.published * 1000),\n                    fetchedDate: new Date(parseInt(i.crawlTimeMsec)),\n                    content: dom.body.innerHTML,\n                    snippet: dom.documentElement.textContent.trim(),\n                    creator: i.author,\n                    hasRead: false,\n                    starred: false,\n                    hidden: false,\n                    notify: false,\n                    serviceRef: i.id,\n                } as RSSItem\n                const baseEl = dom.createElement(\"base\")\n                baseEl.setAttribute(\n                    \"href\",\n                    item.link.split(\"/\").slice(0, 3).join(\"/\")\n                )\n                dom.head.append(baseEl)\n                let img = dom.querySelector(\"img\")\n                if (img && img.src) item.thumb = img.src\n                if (configs.type == SyncService.Inoreader)\n                    item.title = htmlDecode(item.title)\n                for (let c of i.categories) {\n                    if (!item.hasRead && c.endsWith(\"/state/com.google/read\"))\n                        item.hasRead = true\n                    else if (\n                        !item.starred &&\n                        c.endsWith(\"/state/com.google/starred\")\n                    )\n                        item.starred = true\n                }\n                // Apply rules and sync back to the service\n                if (source.rules) {\n                    const hasRead = item.hasRead\n                    const starred = item.starred\n                    SourceRule.applyAll(source.rules, item)\n                    if (item.hasRead !== hasRead)\n                        editTag(\n                            configs,\n                            item.serviceRef,\n                            READ_TAG,\n                            item.hasRead\n                        )\n                    if (item.starred !== starred)\n                        editTag(\n                            configs,\n                            item.serviceRef,\n                            STAR_TAG,\n                            item.starred\n                        )\n                }\n                parsedItems.push(item)\n            })\n            if (parsedItems.length > 0) {\n                configs.lastFetched = Math.round(\n                    parsedItems[0].fetchedDate.getTime() / 1000\n                )\n            }\n            return [parsedItems, configs]\n        } else {\n            return [[], configs]\n        }\n    },\n\n    markAllRead: (sids, date, before) => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as GReaderConfigs\n        if (date) {\n            const predicates: lf.Predicate[] = [\n                db.items.source.in(sids),\n                db.items.hasRead.eq(false),\n                db.items.serviceRef.isNotNull(),\n            ]\n            if (date) {\n                predicates.push(\n                    before ? db.items.date.lte(date) : db.items.date.gte(date)\n                )\n            }\n            const query = lf.op.and.apply(null, predicates)\n            const rows = await db.itemsDB\n                .select(db.items.serviceRef)\n                .from(db.items)\n                .where(query)\n                .exec()\n            const refs = rows.map(row => row[\"serviceRef\"]).join(\"&i=\")\n            if (refs) {\n                editTag(getState().service as GReaderConfigs, refs, READ_TAG)\n            }\n        } else {\n            const sources = sids.map(sid => state.sources[sid])\n            for (let source of sources) {\n                if (source.serviceRef) {\n                    const body = new URLSearchParams()\n                    body.set(\"s\", source.serviceRef)\n                    fetchAPI(\n                        configs,\n                        \"/reader/api/0/mark-all-as-read\",\n                        \"POST\",\n                        body\n                    )\n                }\n            }\n        }\n    },\n\n    markRead: (item: RSSItem) => async (_, getState) => {\n        await editTag(\n            getState().service as GReaderConfigs,\n            item.serviceRef,\n            READ_TAG\n        )\n    },\n\n    markUnread: (item: RSSItem) => async (_, getState) => {\n        await editTag(\n            getState().service as GReaderConfigs,\n            item.serviceRef,\n            READ_TAG,\n            false\n        )\n    },\n\n    star: (item: RSSItem) => async (_, getState) => {\n        await editTag(\n            getState().service as GReaderConfigs,\n            item.serviceRef,\n            STAR_TAG\n        )\n    },\n\n    unstar: (item: RSSItem) => async (_, getState) => {\n        await editTag(\n            getState().service as GReaderConfigs,\n            item.serviceRef,\n            STAR_TAG,\n            false\n        )\n    },\n}\n"
  },
  {
    "path": "src/scripts/models/services/miniflux.ts",
    "content": "import intl from \"react-intl-universal\"\nimport * as db from \"../../db\"\nimport lf from \"lovefield\"\nimport { ServiceHooks } from \"../service\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { createSourceGroup } from \"../group\"\nimport { RSSSource } from \"../source\"\nimport { domParser, htmlDecode } from \"../../utils\"\nimport { RSSItem } from \"../item\"\nimport { SourceRule } from \"../rule\"\n\n// miniflux service configs\nexport interface MinifluxConfigs extends ServiceConfigs {\n    type: SyncService.Miniflux\n    endpoint: string\n    apiKeyAuth: boolean\n    authKey: string\n    fetchLimit: number\n    lastId?: number\n}\n\n// partial api schema\ninterface Feed {\n    id: number\n    feed_url: string\n    title: string\n    category: { title: string }\n}\n\ninterface Category {\n    title: string\n}\n\ninterface Entry {\n    id: number\n    status: \"unread\" | \"read\" | \"removed\"\n    title: string\n    url: string\n    published_at: string\n    created_at: string\n    content: string\n    author: string\n    starred: boolean\n    feed: Feed\n}\n\ninterface Entries {\n    total: number\n    entries: Entry[]\n}\n\nconst APIError = () => new Error(intl.get(\"service.failure\"))\n\n// base endpoint, authorization with dedicated token or http basic user/pass pair\nasync function fetchAPI(\n    configs: MinifluxConfigs,\n    endpoint: string = \"\",\n    method: string = \"GET\",\n    body: string = null\n): Promise<Response> {\n    try {\n        const headers = new Headers()\n        headers.append(\"content-type\", \"application/x-www-form-urlencoded\")\n\n        configs.apiKeyAuth\n            ? headers.append(\"X-Auth-Token\", configs.authKey)\n            : headers.append(\"Authorization\", `Basic ${configs.authKey}`)\n\n        let baseUrl = configs.endpoint\n        if (!baseUrl.endsWith(\"/\")) baseUrl = baseUrl + \"/\"\n        if (!baseUrl.endsWith(\"/v1/\")) baseUrl = baseUrl + \"v1/\"\n        const response = await fetch(baseUrl + endpoint, {\n            method: method,\n            body: body,\n            headers: headers,\n        })\n\n        return response\n    } catch (error) {\n        console.log(error)\n        throw APIError()\n    }\n}\n\nexport const minifluxServiceHooks: ServiceHooks = {\n    // poll service info endpoint to verify auth\n    authenticate: async (configs: MinifluxConfigs) => {\n        const response = await fetchAPI(configs, \"me\")\n\n        if (await response.json().then(json => json.error_message)) return false\n\n        return true\n    },\n\n    // collect sources from service, along with associated groups/categories\n    updateSources: () => async (dispatch, getState) => {\n        const configs = getState().service as MinifluxConfigs\n\n        // fetch and create groups in redux\n        if (configs.importGroups) {\n            const groups: Category[] = await fetchAPI(\n                configs,\n                \"categories\"\n            ).then(response => response.json())\n            groups.forEach(group => dispatch(createSourceGroup(group.title)))\n        }\n\n        // fetch all feeds\n        const feedResponse = await fetchAPI(configs, \"feeds\")\n        const feeds = await feedResponse.json()\n\n        if (feeds === undefined) throw APIError()\n\n        // go through feeds, create typed source while also mapping by group\n        let sources: RSSSource[] = new Array<RSSSource>()\n        let groupsMap: Map<string, string> = new Map<string, string>()\n        for (let feed of feeds) {\n            let source = new RSSSource(feed.feed_url, feed.title)\n            // associate service christened id to match in other request\n            source.serviceRef = feed.id.toString()\n            sources.push(source)\n            groupsMap.set(feed.id.toString(), feed.category.title)\n        }\n\n        return [sources, configs.importGroups ? groupsMap : undefined]\n    },\n\n    // fetch entries from after the last fetched id (if exists)\n    // limit by quantity and maximum safe integer (id)\n    // NOTE: miniflux endpoint /entries default order with \"published at\", and does not offer \"created_at\"\n    //          but does offer id sort, directly correlated with \"created\". some feeds give strange published_at.\n\n    fetchItems: () => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as MinifluxConfigs\n        const items: Entry[] = new Array()\n        let entriesResponse: Entries\n\n        // parameters\n        configs.lastId = configs.lastId ?? 0\n        // intermediate\n        const quantity = 125\n        let continueId: number\n\n        do {\n            try {\n                if (continueId) {\n                    entriesResponse = await fetchAPI(\n                        configs,\n                        `entries?order=id&direction=desc&after_entry_id=${configs.lastId}&before_entry_id=${continueId}&limit=${quantity}`\n                    ).then(response => response.json())\n                } else {\n                    entriesResponse = await fetchAPI(\n                        configs,\n                        `entries?order=id&direction=desc&after_entry_id=${configs.lastId}&limit=${quantity}`\n                    ).then(response => response.json())\n                }\n\n                items.push(...entriesResponse.entries)\n                continueId = items[items.length - 1].id\n            } catch {\n                break\n            }\n        } while (\n            entriesResponse.entries &&\n            entriesResponse.total >= quantity &&\n            items.length < configs.fetchLimit\n        )\n\n        // break/return nothing if no new items acquired\n        if (items.length === 0) return [[], configs]\n        configs.lastId = items[0].id\n\n        // get sources that possess ref/id given by service, associate new items\n        const sourceMap = new Map<string, RSSSource>()\n        for (let source of Object.values(state.sources)) {\n            if (source.serviceRef) {\n                sourceMap.set(source.serviceRef, source)\n            }\n        }\n\n        // map item objects to rssitem type while appling rules (if exist)\n        const parsedItems = items.map(item => {\n            const source = sourceMap.get(item.feed.id.toString())\n\n            let parsedItem = {\n                source: source.sid,\n                title: item.title,\n                link: item.url,\n                date: new Date(item.published_at ?? item.created_at),\n                fetchedDate: new Date(),\n                content: item.content,\n                snippet: htmlDecode(item.content).trim(),\n                creator: item.author,\n                hasRead: Boolean(item.status === \"read\"),\n                starred: Boolean(item.starred),\n                hidden: false,\n                notify: false,\n                serviceRef: String(item.id),\n            } as RSSItem\n\n            // Try to get the thumbnail of the item\n            let dom = domParser.parseFromString(item.content, \"text/html\")\n            let baseEl = dom.createElement(\"base\")\n            baseEl.setAttribute(\n                \"href\",\n                parsedItem.link.split(\"/\").slice(0, 3).join(\"/\")\n            )\n            dom.head.append(baseEl)\n            let img = dom.querySelector(\"img\")\n            if (img && img.src) parsedItem.thumb = img.src\n\n            if (source.rules) {\n                SourceRule.applyAll(source.rules, parsedItem)\n                if ((item.status === \"read\") !== parsedItem.hasRead)\n                    minifluxServiceHooks.markRead(parsedItem)\n                if (item.starred !== parsedItem.starred)\n                    minifluxServiceHooks.markUnread(parsedItem)\n            }\n\n            return parsedItem\n        })\n\n        return [parsedItems, configs]\n    },\n\n    // get remote read and star state of articles, for local sync\n    syncItems: () => async (_, getState) => {\n        const configs = getState().service as MinifluxConfigs\n\n        const unreadPromise: Promise<Entries> = fetchAPI(\n            configs,\n            \"entries?status=unread\"\n        ).then(response => response.json())\n        const starredPromise: Promise<Entries> = fetchAPI(\n            configs,\n            \"entries?starred=true\"\n        ).then(response => response.json())\n        const [unread, starred] = await Promise.all([\n            unreadPromise,\n            starredPromise,\n        ])\n\n        return [\n            new Set(unread.entries.map((entry: Entry) => String(entry.id))),\n            new Set(starred.entries.map((entry: Entry) => String(entry.id))),\n        ]\n    },\n\n    markRead: (item: RSSItem) => async (_, getState) => {\n        if (!item.serviceRef) return\n\n        const body = `{\n            \"entry_ids\": [${item.serviceRef}],\n            \"status\": \"read\"\n        }`\n\n        const response = await fetchAPI(\n            getState().service as MinifluxConfigs,\n            \"entries\",\n            \"PUT\",\n            body\n        )\n\n        if (response.status !== 204) throw APIError()\n    },\n\n    markUnread: (item: RSSItem) => async (_, getState) => {\n        if (!item.serviceRef) return\n\n        const body = `{\n            \"entry_ids\": [${item.serviceRef}],\n            \"status\": \"unread\"\n        }`\n        await fetchAPI(\n            getState().service as MinifluxConfigs,\n            \"entries\",\n            \"PUT\",\n            body\n        )\n    },\n\n    // mark entries for source ids as read, relative to date, determined by \"before\" bool\n\n    // context menu component:\n    // item - null, item date, either\n    // group - group sources, null, true\n    // nav - null, daysago, true\n\n    // if null, state consulted for context sids\n\n    markAllRead: (sids, date, before) => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as MinifluxConfigs\n\n        if (date) {\n            const predicates: lf.Predicate[] = [\n                db.items.source.in(sids),\n                db.items.hasRead.eq(false),\n                db.items.serviceRef.isNotNull(),\n                before ? db.items.date.lte(date) : db.items.date.gte(date),\n            ]\n            const query = lf.op.and.apply(null, predicates)\n            const rows = await db.itemsDB\n                .select(db.items.serviceRef)\n                .from(db.items)\n                .where(query)\n                .exec()\n            const refs = rows.map(row => row[\"serviceRef\"])\n            const body = `{\n                \"entry_ids\": [${refs}],\n                \"status\": \"read\"\n            }`\n            await fetchAPI(configs, \"entries\", \"PUT\", body)\n        } else {\n            const sources = state.sources\n            await Promise.all(\n                sids.map(sid =>\n                    fetchAPI(\n                        configs,\n                        `feeds/${sources[sid]?.serviceRef}/mark-all-as-read`,\n                        \"PUT\"\n                    )\n                )\n            )\n        }\n    },\n\n    star: (item: RSSItem) => async (_, getState) => {\n        if (!item.serviceRef) return\n\n        await fetchAPI(\n            getState().service as MinifluxConfigs,\n            `entries/${item.serviceRef}/bookmark`,\n            \"PUT\"\n        )\n    },\n\n    unstar: (item: RSSItem) => async (_, getState) => {\n        if (!item.serviceRef) return\n\n        await fetchAPI(\n            getState().service as MinifluxConfigs,\n            `entries/${item.serviceRef}/bookmark`,\n            \"PUT\"\n        )\n    },\n}\n"
  },
  {
    "path": "src/scripts/models/services/nextcloud.ts",
    "content": "import intl from \"react-intl-universal\"\nimport * as db from \"../../db\"\nimport lf from \"lovefield\"\nimport { ServiceHooks } from \"../service\"\nimport { ServiceConfigs, SyncService } from \"../../../schema-types\"\nimport { createSourceGroup } from \"../group\"\nimport { RSSSource } from \"../source\"\nimport { domParser } from \"../../utils\"\nimport { RSSItem } from \"../item\"\nimport { SourceRule } from \"../rule\"\n\nexport interface NextcloudConfigs extends ServiceConfigs {\n    type: SyncService.Nextcloud\n    endpoint: string\n    username: string\n    password: string\n    fetchLimit: number\n    lastModified?: number\n    lastId?: number\n}\n\nasync function fetchAPI(configs: NextcloudConfigs, params: string) {\n    const headers = new Headers()\n    headers.set(\n        \"Authorization\",\n        \"Basic \" + btoa(configs.username + \":\" + configs.password)\n    )\n    return await fetch(configs.endpoint + params, { headers: headers })\n}\n\nasync function markItems(\n    configs: NextcloudConfigs,\n    type: string,\n    method: string,\n    refs: number[]\n) {\n    const headers = new Headers()\n    headers.set(\n        \"Authorization\",\n        \"Basic \" + btoa(configs.username + \":\" + configs.password)\n    )\n    headers.set(\"Content-Type\", \"application/json; charset=utf-8\")\n    const promises = new Array<Promise<Response>>()\n    while (refs.length > 0) {\n        const batch = new Array<number>()\n        while (batch.length < 1000 && refs.length > 0) {\n            batch.push(refs.pop())\n        }\n        const bodyObject: any = {}\n        bodyObject[\"itemIds\"] = batch\n        promises.push(\n            fetch(configs.endpoint + \"/items/\" + type + \"/multiple\", {\n                method: method,\n                headers: headers,\n                body: JSON.stringify(bodyObject),\n            })\n        )\n    }\n    return await Promise.all(promises)\n}\n\nconst APIError = () => new Error(intl.get(\"service.failure\"))\n\nexport const nextcloudServiceHooks: ServiceHooks = {\n    authenticate: async (configs: NextcloudConfigs) => {\n        try {\n            const result = await fetchAPI(configs, \"/version\")\n            return result.status === 200\n        } catch {\n            return false\n        }\n    },\n\n    updateSources: () => async (dispatch, getState) => {\n        const configs = getState().service as NextcloudConfigs\n        const response = await fetchAPI(configs, \"/feeds\")\n        if (response.status !== 200) throw APIError()\n        const feeds = await response.json()\n        let groupsMap: Map<string, string>\n        let groupsByTagId: Map<string, string> = new Map()\n        if (configs.importGroups) {\n            const foldersResponse = await fetchAPI(configs, \"/folders\")\n            if (foldersResponse.status !== 200) throw APIError()\n            const folders = await foldersResponse.json()\n            const foldersSet = new Set<string>()\n            groupsMap = new Map()\n            for (let folder of folders.folders) {\n                const title = folder.name.trim()\n                if (!foldersSet.has(title)) {\n                    foldersSet.add(title)\n                    dispatch(createSourceGroup(title))\n                }\n                groupsByTagId.set(String(folder.id), title)\n            }\n        }\n        const sources = feeds.feeds.map(s => {\n            const source = new RSSSource(s.url, s.title)\n            source.iconurl = s.faviconLink\n            source.serviceRef = String(s.id)\n            if (s.folderId && groupsByTagId.has(String(s.folderId))) {\n                groupsMap.set(\n                    String(s.id),\n                    groupsByTagId.get(String(s.folderId))\n                )\n            }\n            return source\n        })\n        return [sources, groupsMap]\n    },\n\n    syncItems: () => async (_, getState) => {\n        const configs = getState().service as NextcloudConfigs\n        const [unreadResponse, starredResponse] = await Promise.all([\n            fetchAPI(configs, \"/items?getRead=false&type=3&batchSize=-1\"),\n            fetchAPI(configs, \"/items?getRead=true&type=2&batchSize=-1\"),\n        ])\n        if (unreadResponse.status !== 200 || starredResponse.status !== 200)\n            throw APIError()\n        const unread = await unreadResponse.json()\n        const starred = await starredResponse.json()\n        return [\n            new Set(unread.items.map(i => String(i.id))),\n            new Set(starred.items.map(i => String(i.id))),\n        ]\n    },\n\n    fetchItems: () => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as NextcloudConfigs\n        let items = new Array()\n        configs.lastModified = configs.lastModified || 0\n        configs.lastId = configs.lastId || 0\n        let lastFetched: any\n\n        if (!configs.lastModified || configs.lastModified == 0) {\n            //first sync\n            let min = Number.MAX_SAFE_INTEGER\n            do {\n                const response = await fetchAPI(\n                    configs,\n                    \"/items?getRead=true&type=3&batchSize=125&offset=\" + min\n                )\n                if (response.status !== 200) throw APIError()\n                lastFetched = await response.json()\n                items = [...items, ...lastFetched.items]\n                min = lastFetched.items.reduce((m, n) => Math.min(m, n.id), min)\n            } while (\n                lastFetched.items &&\n                lastFetched.items.length >= 125 &&\n                items.length < configs.fetchLimit\n            )\n        } else {\n            //incremental sync\n            const response = await fetchAPI(\n                configs,\n                \"/items/updated?lastModified=\" +\n                    configs.lastModified +\n                    \"&type=3\"\n            )\n            if (response.status !== 200) throw APIError()\n            lastFetched = (await response.json()).items\n            items.push(...lastFetched.filter(i => i.id > configs.lastId))\n        }\n        configs.lastModified = items.reduce(\n            (m, n) => Math.max(m, n.lastModified),\n            configs.lastModified\n        )\n        configs.lastId = items.reduce(\n            (m, n) => Math.max(m, n.id),\n            configs.lastId\n        )\n        configs.lastModified++ //+1 to avoid fetching articles with same lastModified next time\n        if (items.length > 0) {\n            const fidMap = new Map<string, RSSSource>()\n            for (let source of Object.values(state.sources)) {\n                if (source.serviceRef) {\n                    fidMap.set(source.serviceRef, source)\n                }\n            }\n\n            const parsedItems = new Array<RSSItem>()\n            items.forEach(i => {\n                if (i.body === null || i.url === null) return\n                const unreadItem = i.unread\n                const starredItem = i.starred\n                const source = fidMap.get(String(i.feedId))\n                const dom = domParser.parseFromString(i.body, \"text/html\")\n                const item = {\n                    source: source.sid,\n                    title: i.title,\n                    link: i.url,\n                    date: new Date(i.pubDate * 1000),\n                    fetchedDate: new Date(),\n                    content: i.body,\n                    snippet: dom.documentElement.textContent.trim(),\n                    creator: i.author,\n                    hasRead: !i.unread,\n                    starred: i.starred,\n                    hidden: false,\n                    notify: false,\n                    serviceRef: String(i.id),\n                } as RSSItem\n                if (i.enclosureLink) {\n                    item.thumb = i.enclosureLink\n                } else {\n                    let baseEl = dom.createElement(\"base\")\n                    baseEl.setAttribute(\n                        \"href\",\n                        item.link.split(\"/\").slice(0, 3).join(\"/\")\n                    )\n                    dom.head.append(baseEl)\n                    let img = dom.querySelector(\"img\")\n                    if (img && img.src) item.thumb = img.src\n                }\n                // Apply rules and sync back to the service\n                if (source.rules) SourceRule.applyAll(source.rules, item)\n                if (unreadItem && item.hasRead)\n                    markItems(\n                        configs,\n                        item.hasRead ? \"read\" : \"unread\",\n                        \"POST\",\n                        [i.id]\n                    )\n                if (starredItem !== Boolean(item.starred))\n                    markItems(\n                        configs,\n                        item.starred ? \"star\" : \"unstar\",\n                        \"POST\",\n                        [i.id]\n                    )\n\n                parsedItems.push(item)\n            })\n            return [parsedItems, configs]\n        } else {\n            return [[], configs]\n        }\n    },\n\n    markAllRead: (sids, date, before) => async (_, getState) => {\n        const state = getState()\n        const configs = state.service as NextcloudConfigs\n        const predicates: lf.Predicate[] = [\n            db.items.source.in(sids),\n            db.items.hasRead.eq(false),\n            db.items.serviceRef.isNotNull(),\n        ]\n        if (date) {\n            predicates.push(\n                before ? db.items.date.lte(date) : db.items.date.gte(date)\n            )\n        }\n        const query = lf.op.and.apply(null, predicates)\n        const rows = await db.itemsDB\n            .select(db.items.serviceRef)\n            .from(db.items)\n            .where(query)\n            .exec()\n        const refs = rows.map(row => parseInt(row[\"serviceRef\"]))\n        markItems(configs, \"unread\", \"POST\", refs)\n    },\n\n    markRead: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as NextcloudConfigs,\n            \"read\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    markUnread: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as NextcloudConfigs,\n            \"unread\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    star: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as NextcloudConfigs,\n            \"star\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n\n    unstar: (item: RSSItem) => async (_, getState) => {\n        await markItems(\n            getState().service as NextcloudConfigs,\n            \"unstar\",\n            \"POST\",\n            [parseInt(item.serviceRef)]\n        )\n    },\n}\n"
  },
  {
    "path": "src/scripts/models/source.ts",
    "content": "import intl from \"react-intl-universal\"\nimport * as db from \"../db\"\nimport lf from \"lovefield\"\nimport {\n    fetchFavicon,\n    ActionStatus,\n    AppThunk,\n    parseRSS,\n    MyParserItem,\n} from \"../utils\"\nimport {\n    RSSItem,\n    insertItems,\n    ItemActionTypes,\n    FETCH_ITEMS,\n    MARK_READ,\n    MARK_UNREAD,\n    MARK_ALL_READ,\n} from \"./item\"\nimport { saveSettings } from \"./app\"\nimport { SourceRule } from \"./rule\"\nimport { fixBrokenGroups } from \"./group\"\n\nexport const enum SourceOpenTarget {\n    Local,\n    Webpage,\n    External,\n    FullContent,\n}\n\nexport const enum SourceTextDirection {\n    LTR,\n    RTL,\n    Vertical,\n}\n\nexport class RSSSource {\n    sid: number\n    url: string\n    iconurl?: string\n    name: string\n    openTarget: SourceOpenTarget\n    unreadCount: number\n    lastFetched: Date\n    serviceRef?: string\n    fetchFrequency: number // in minutes\n    rules?: SourceRule[]\n    textDir: SourceTextDirection\n    hidden: boolean\n\n    constructor(url: string, name: string = null) {\n        this.url = url\n        this.name = name\n        this.openTarget = SourceOpenTarget.Local\n        this.lastFetched = new Date()\n        this.fetchFrequency = 0\n        this.textDir = SourceTextDirection.LTR\n        this.hidden = false\n    }\n\n    static async fetchMetaData(source: RSSSource) {\n        let feed = await parseRSS(source.url)\n        if (!source.name) {\n            if (feed.title) source.name = feed.title.trim()\n            source.name = source.name || intl.get(\"sources.untitled\")\n        }\n        return feed\n    }\n\n    private static async checkItem(\n        source: RSSSource,\n        item: MyParserItem\n    ): Promise<RSSItem> {\n        let i = new RSSItem(item, source)\n        const items = (await db.itemsDB\n            .select()\n            .from(db.items)\n            .where(\n                lf.op.and(\n                    db.items.source.eq(i.source),\n                    db.items.title.eq(i.title),\n                    db.items.date.eq(i.date)\n                )\n            )\n            .limit(1)\n            .exec()) as RSSItem[]\n        if (items.length === 0) {\n            RSSItem.parseContent(i, item)\n            if (source.rules) SourceRule.applyAll(source.rules, i)\n            return i\n        } else {\n            return null\n        }\n    }\n\n    static checkItems(\n        source: RSSSource,\n        items: MyParserItem[]\n    ): Promise<RSSItem[]> {\n        return new Promise<RSSItem[]>((resolve, reject) => {\n            let p = new Array<Promise<RSSItem>>()\n            for (let item of items) {\n                p.push(this.checkItem(source, item))\n            }\n            Promise.all(p)\n                .then(values => {\n                    resolve(values.filter(v => v != null))\n                })\n                .catch(e => {\n                    reject(e)\n                })\n        })\n    }\n\n    static async fetchItems(source: RSSSource) {\n        let feed = await parseRSS(source.url)\n        return await this.checkItems(source, feed.items)\n    }\n}\n\nexport type SourceState = {\n    [sid: number]: RSSSource\n}\n\nexport const INIT_SOURCES = \"INIT_SOURCES\"\nexport const ADD_SOURCE = \"ADD_SOURCE\"\nexport const UPDATE_SOURCE = \"UPDATE_SOURCE\"\nexport const UPDATE_UNREAD_COUNTS = \"UPDATE_UNREAD_COUNTS\"\nexport const DELETE_SOURCE = \"DELETE_SOURCE\"\nexport const HIDE_SOURCE = \"HIDE_SOURCE\"\nexport const UNHIDE_SOURCE = \"UNHIDE_SOURCE\"\n\ninterface InitSourcesAction {\n    type: typeof INIT_SOURCES\n    status: ActionStatus\n    sources?: SourceState\n    err?\n}\n\ninterface AddSourceAction {\n    type: typeof ADD_SOURCE\n    status: ActionStatus\n    batch: boolean\n    source?: RSSSource\n    err?\n}\n\ninterface UpdateSourceAction {\n    type: typeof UPDATE_SOURCE\n    source: RSSSource\n}\n\ninterface UpdateUnreadCountsAction {\n    type: typeof UPDATE_UNREAD_COUNTS\n    sources: SourceState\n}\n\ninterface DeleteSourceAction {\n    type: typeof DELETE_SOURCE\n    source: RSSSource\n}\n\ninterface ToggleSourceHiddenAction {\n    type: typeof HIDE_SOURCE | typeof UNHIDE_SOURCE\n    status: ActionStatus\n    source: RSSSource\n}\n\nexport type SourceActionTypes =\n    | InitSourcesAction\n    | AddSourceAction\n    | UpdateSourceAction\n    | UpdateUnreadCountsAction\n    | DeleteSourceAction\n    | ToggleSourceHiddenAction\n\nexport function initSourcesRequest(): SourceActionTypes {\n    return {\n        type: INIT_SOURCES,\n        status: ActionStatus.Request,\n    }\n}\n\nexport function initSourcesSuccess(sources: SourceState): SourceActionTypes {\n    return {\n        type: INIT_SOURCES,\n        status: ActionStatus.Success,\n        sources: sources,\n    }\n}\n\nexport function initSourcesFailure(err): SourceActionTypes {\n    return {\n        type: INIT_SOURCES,\n        status: ActionStatus.Failure,\n        err: err,\n    }\n}\n\nasync function unreadCount(sources: SourceState): Promise<SourceState> {\n    const rows = await db.itemsDB\n        .select(db.items.source, lf.fn.count(db.items._id))\n        .from(db.items)\n        .where(db.items.hasRead.eq(false))\n        .groupBy(db.items.source)\n        .exec()\n    for (let row of rows) {\n        sources[row[\"source\"]].unreadCount = row[\"COUNT(_id)\"]\n    }\n    return sources\n}\n\nexport function updateUnreadCounts(): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const sources: SourceState = {}\n        for (let source of Object.values(getState().sources)) {\n            sources[source.sid] = {\n                ...source,\n                unreadCount: 0,\n            }\n        }\n        dispatch({\n            type: UPDATE_UNREAD_COUNTS,\n            sources: await unreadCount(sources),\n        })\n    }\n}\n\nexport function initSources(): AppThunk<Promise<void>> {\n    return async dispatch => {\n        dispatch(initSourcesRequest())\n        await db.init()\n        const sources = (await db.sourcesDB\n            .select()\n            .from(db.sources)\n            .exec()) as RSSSource[]\n        const state: SourceState = {}\n        for (let source of sources) {\n            source.unreadCount = 0\n            state[source.sid] = source\n        }\n        await unreadCount(state)\n        dispatch(fixBrokenGroups(state))\n        dispatch(initSourcesSuccess(state))\n    }\n}\n\nexport function addSourceRequest(batch: boolean): SourceActionTypes {\n    return {\n        type: ADD_SOURCE,\n        batch: batch,\n        status: ActionStatus.Request,\n    }\n}\n\nexport function addSourceSuccess(\n    source: RSSSource,\n    batch: boolean\n): SourceActionTypes {\n    return {\n        type: ADD_SOURCE,\n        batch: batch,\n        status: ActionStatus.Success,\n        source: source,\n    }\n}\n\nexport function addSourceFailure(err, batch: boolean): SourceActionTypes {\n    return {\n        type: ADD_SOURCE,\n        batch: batch,\n        status: ActionStatus.Failure,\n        err: err,\n    }\n}\n\nlet insertPromises = Promise.resolve()\nexport function insertSource(source: RSSSource): AppThunk<Promise<RSSSource>> {\n    return (_, getState) => {\n        return new Promise((resolve, reject) => {\n            insertPromises = insertPromises.then(async () => {\n                let sids = Object.values(getState().sources).map(s => s.sid)\n                source.sid = Math.max(...sids, -1) + 1\n                const row = db.sources.createRow(source)\n                try {\n                    const inserted = (await db.sourcesDB\n                        .insert()\n                        .into(db.sources)\n                        .values([row])\n                        .exec()) as RSSSource[]\n                    resolve(inserted[0])\n                } catch (err) {\n                    if (err.code === 201) reject(intl.get(\"sources.exist\"))\n                    else reject(err)\n                }\n            })\n        })\n    }\n}\n\nexport function addSource(\n    url: string,\n    name: string = null,\n    batch = false\n): AppThunk<Promise<number>> {\n    return async (dispatch, getState) => {\n        const app = getState().app\n        if (app.sourceInit) {\n            dispatch(addSourceRequest(batch))\n            const source = new RSSSource(url, name)\n            try {\n                const feed = await RSSSource.fetchMetaData(source)\n                const inserted = await dispatch(insertSource(source))\n                inserted.unreadCount = feed.items.length\n                dispatch(addSourceSuccess(inserted, batch))\n                window.settings.saveGroups(getState().groups)\n                dispatch(updateFavicon([inserted.sid]))\n                const items = await RSSSource.checkItems(inserted, feed.items)\n                await insertItems(items)\n                return inserted.sid\n            } catch (e) {\n                dispatch(addSourceFailure(e, batch))\n                if (!batch) {\n                    window.utils.showErrorBox(\n                        intl.get(\"sources.errorAdd\"),\n                        String(e),\n                        intl.get(\"context.copy\")\n                    )\n                }\n                throw e\n            }\n        }\n        throw new Error(\"Sources not initialized.\")\n    }\n}\n\nexport function updateSourceDone(source: RSSSource): SourceActionTypes {\n    return {\n        type: UPDATE_SOURCE,\n        source: source,\n    }\n}\n\nexport function updateSource(source: RSSSource): AppThunk<Promise<void>> {\n    return async dispatch => {\n        let sourceCopy = { ...source }\n        delete sourceCopy.unreadCount\n        const row = db.sources.createRow(sourceCopy)\n        await db.sourcesDB\n            .insertOrReplace()\n            .into(db.sources)\n            .values([row])\n            .exec()\n        dispatch(updateSourceDone(source))\n    }\n}\n\nexport function deleteSourceDone(source: RSSSource): SourceActionTypes {\n    return {\n        type: DELETE_SOURCE,\n        source: source,\n    }\n}\n\nexport function deleteSource(\n    source: RSSSource,\n    batch = false\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        if (!batch) dispatch(saveSettings())\n        try {\n            await db.itemsDB\n                .delete()\n                .from(db.items)\n                .where(db.items.source.eq(source.sid))\n                .exec()\n            await db.sourcesDB\n                .delete()\n                .from(db.sources)\n                .where(db.sources.sid.eq(source.sid))\n                .exec()\n            dispatch(deleteSourceDone(source))\n            window.settings.saveGroups(getState().groups)\n        } catch (err) {\n            console.log(err)\n        } finally {\n            if (!batch) dispatch(saveSettings())\n        }\n    }\n}\n\nexport function deleteSources(sources: RSSSource[]): AppThunk<Promise<void>> {\n    return async dispatch => {\n        dispatch(saveSettings())\n        for (let source of sources) {\n            await dispatch(deleteSource(source, true))\n        }\n        dispatch(saveSettings())\n    }\n}\n\nexport function toggleSourceHidden(source: RSSSource): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const sourceCopy: RSSSource = { ...getState().sources[source.sid] }\n        sourceCopy.hidden = !sourceCopy.hidden\n        dispatch({\n            type: sourceCopy.hidden ? HIDE_SOURCE : UNHIDE_SOURCE,\n            status: ActionStatus.Success,\n            source: sourceCopy,\n        })\n        await dispatch(updateSource(sourceCopy))\n    }\n}\n\nexport function updateFavicon(\n    sids?: number[],\n    force = false\n): AppThunk<Promise<void>> {\n    return async (dispatch, getState) => {\n        const initSources = getState().sources\n        if (!sids) {\n            sids = Object.values(initSources)\n                .filter(s => s.iconurl === undefined)\n                .map(s => s.sid)\n        } else {\n            sids = sids.filter(sid => sid in initSources)\n        }\n        const promises = sids.map(async sid => {\n            const url = initSources[sid].url\n            let favicon = (await fetchFavicon(url)) || \"\"\n            const source = getState().sources[sid]\n            if (\n                source &&\n                source.url === url &&\n                (force || source.iconurl === undefined)\n            ) {\n                source.iconurl = favicon\n                await dispatch(updateSource(source))\n            }\n        })\n        await Promise.all(promises)\n    }\n}\n\nexport function sourceReducer(\n    state: SourceState = {},\n    action: SourceActionTypes | ItemActionTypes\n): SourceState {\n    switch (action.type) {\n        case INIT_SOURCES:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return action.sources\n                default:\n                    return state\n            }\n        case UPDATE_UNREAD_COUNTS:\n            return action.sources\n        case ADD_SOURCE:\n            switch (action.status) {\n                case ActionStatus.Success:\n                    return {\n                        ...state,\n                        [action.source.sid]: action.source,\n                    }\n                default:\n                    return state\n            }\n        case UPDATE_SOURCE:\n            return {\n                ...state,\n                [action.source.sid]: action.source,\n            }\n        case DELETE_SOURCE: {\n            delete state[action.source.sid]\n            return { ...state }\n        }\n        case FETCH_ITEMS: {\n            switch (action.status) {\n                case ActionStatus.Success: {\n                    let updateMap = new Map<number, number>()\n                    for (let item of action.items) {\n                        if (!item.hasRead) {\n                            updateMap.set(\n                                item.source,\n                                updateMap.has(item.source)\n                                    ? updateMap.get(item.source) + 1\n                                    : 1\n                            )\n                        }\n                    }\n                    let nextState = {} as SourceState\n                    for (let [s, source] of Object.entries(state)) {\n                        let sid = parseInt(s)\n                        if (updateMap.has(sid)) {\n                            nextState[sid] = {\n                                ...source,\n                                unreadCount:\n                                    source.unreadCount + updateMap.get(sid),\n                            } as RSSSource\n                        } else {\n                            nextState[sid] = source\n                        }\n                    }\n                    return nextState\n                }\n                default:\n                    return state\n            }\n        }\n        case MARK_UNREAD:\n        case MARK_READ:\n            return {\n                ...state,\n                [action.item.source]: {\n                    ...state[action.item.source],\n                    unreadCount:\n                        state[action.item.source].unreadCount +\n                        (action.type === MARK_UNREAD ? 1 : -1),\n                } as RSSSource,\n            }\n        case MARK_ALL_READ: {\n            let nextState = { ...state }\n            action.sids.forEach(sid => {\n                nextState[sid] = {\n                    ...state[sid],\n                    unreadCount: action.time ? state[sid].unreadCount : 0,\n                }\n            })\n            return nextState\n        }\n        default:\n            return state\n    }\n}\n"
  },
  {
    "path": "src/scripts/reducer.ts",
    "content": "import { applyMiddleware, combineReducers, createStore } from \"redux\"\nimport thunkMiddleware from \"redux-thunk\"\n\nimport { sourceReducer } from \"./models/source\"\nimport { itemReducer } from \"./models/item\"\nimport { feedReducer } from \"./models/feed\"\nimport { appReducer } from \"./models/app\"\nimport { groupReducer } from \"./models/group\"\nimport { pageReducer } from \"./models/page\"\nimport { serviceReducer } from \"./models/service\"\nimport { AppDispatch } from \"./utils\"\nimport {\n    TypedUseSelectorHook,\n    useDispatch,\n    useSelector,\n    useStore,\n} from \"react-redux\"\n\nexport const rootReducer = combineReducers({\n    sources: sourceReducer,\n    items: itemReducer,\n    feeds: feedReducer,\n    groups: groupReducer,\n    page: pageReducer,\n    service: serviceReducer,\n    app: appReducer,\n})\n\nexport const rootStore = createStore(\n    rootReducer,\n    applyMiddleware<AppDispatch, RootState>(thunkMiddleware)\n)\n\nexport type AppStore = typeof rootStore\nexport type RootState = ReturnType<typeof rootReducer>\n\nexport const useAppDispatch: () => AppDispatch = useDispatch\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector\nexport const useAppStore: () => AppStore = useStore\n"
  },
  {
    "path": "src/scripts/settings.ts",
    "content": "import * as db from \"./db\"\nimport { IPartialTheme, loadTheme } from \"@fluentui/react\"\nimport locales from \"./i18n/_locales\"\nimport { ThemeSettings } from \"../schema-types\"\nimport intl from \"react-intl-universal\"\nimport { SourceTextDirection } from \"./models/source\"\n\nlet lightTheme: IPartialTheme = {\n    defaultFontStyle: {\n        fontFamily: '\"Segoe UI\", \"Source Han Sans Regular\", sans-serif',\n    },\n}\nlet darkTheme: IPartialTheme = {\n    ...lightTheme,\n    palette: {\n        neutralLighterAlt: \"#282828\",\n        neutralLighter: \"#313131\",\n        neutralLight: \"#3f3f3f\",\n        neutralQuaternaryAlt: \"#484848\",\n        neutralQuaternary: \"#4f4f4f\",\n        neutralTertiaryAlt: \"#6d6d6d\",\n        neutralTertiary: \"#c8c8c8\",\n        neutralSecondary: \"#d0d0d0\",\n        neutralSecondaryAlt: \"#d2d0ce\",\n        neutralPrimaryAlt: \"#dadada\",\n        neutralPrimary: \"#ffffff\",\n        neutralDark: \"#f4f4f4\",\n        black: \"#f8f8f8\",\n        white: \"#1f1f1f\",\n        themePrimary: \"#3a96dd\",\n        themeLighterAlt: \"#020609\",\n        themeLighter: \"#091823\",\n        themeLight: \"#112d43\",\n        themeTertiary: \"#235a85\",\n        themeSecondary: \"#3385c3\",\n        themeDarkAlt: \"#4ba0e1\",\n        themeDark: \"#65aee6\",\n        themeDarker: \"#8ac2ec\",\n        accent: \"#3a96dd\",\n    },\n}\n\nexport function setThemeDefaultFont(locale: string) {\n    switch (locale) {\n        case \"zh-CN\":\n            lightTheme.defaultFontStyle.fontFamily =\n                '\"Segoe UI\", \"Source Han Sans SC Regular\", \"Microsoft YaHei\", sans-serif'\n            break\n        case \"zh-TW\":\n            lightTheme.defaultFontStyle.fontFamily =\n                '\"Segoe UI\", \"Source Han Sans TC Regular\", \"Microsoft JhengHei\", sans-serif'\n            break\n        case \"ja\":\n            lightTheme.defaultFontStyle.fontFamily =\n                '\"Segoe UI\", \"Source Han Sans JP Regular\", \"Yu Gothic UI\", sans-serif'\n            break\n        case \"ko\":\n            lightTheme.defaultFontStyle.fontFamily =\n                '\"Segoe UI\", \"Source Han Sans KR Regular\", \"Malgun Gothic\", sans-serif'\n            break\n        default:\n            lightTheme.defaultFontStyle.fontFamily =\n                '\"Segoe UI\", \"Source Han Sans Regular\", sans-serif'\n    }\n    darkTheme.defaultFontStyle.fontFamily =\n        lightTheme.defaultFontStyle.fontFamily\n    applyThemeSettings()\n}\nexport function setThemeSettings(theme: ThemeSettings) {\n    window.settings.setThemeSettings(theme)\n    applyThemeSettings()\n}\nexport function getThemeSettings(): ThemeSettings {\n    return window.settings.getThemeSettings()\n}\nexport function applyThemeSettings() {\n    loadTheme(window.settings.shouldUseDarkColors() ? darkTheme : lightTheme)\n}\nwindow.settings.addThemeUpdateListener(shouldDark => {\n    loadTheme(shouldDark ? darkTheme : lightTheme)\n})\n\nexport function getCurrentLocale() {\n    let locale = window.settings.getCurrentLocale()\n    if (locale in locales) return locale\n    locale = locale.split(\"-\")[0]\n    return locale in locales ? locale : \"en-US\"\n}\n\nexport async function exportAll() {\n    const filters = [{ name: intl.get(\"app.frData\"), extensions: [\"frdata\"] }]\n    const write = await window.utils.showSaveDialog(\n        filters,\n        \"*/Fluent_Reader_Backup.frdata\"\n    )\n    if (write) {\n        let output = window.settings.getAll()\n        output[\"lovefield\"] = {\n            sources: await db.sourcesDB.select().from(db.sources).exec(),\n            items: await db.itemsDB.select().from(db.items).exec(),\n        }\n        write(JSON.stringify(output), intl.get(\"settings.writeError\"))\n    }\n}\n\nexport async function importAll() {\n    const filters = [{ name: intl.get(\"app.frData\"), extensions: [\"frdata\"] }]\n    let data = await window.utils.showOpenDialog(filters)\n    if (!data) return true\n    let confirmed = await window.utils.showMessageBox(\n        intl.get(\"app.restore\"),\n        intl.get(\"app.confirmImport\"),\n        intl.get(\"confirm\"),\n        intl.get(\"cancel\"),\n        true,\n        \"warning\"\n    )\n    if (!confirmed) return true\n    let configs = JSON.parse(data)\n    await db.sourcesDB.delete().from(db.sources).exec()\n    await db.itemsDB.delete().from(db.items).exec()\n    if (configs.nedb) {\n        let openRequest = window.indexedDB.open(\"NeDB\")\n        configs.useNeDB = true\n        openRequest.onsuccess = () => {\n            let db = openRequest.result\n            let objectStore = db\n                .transaction(\"nedbdata\", \"readwrite\")\n                .objectStore(\"nedbdata\")\n            let requests = Object.entries(configs.nedb).map(([key, value]) => {\n                return objectStore.put(value, key)\n            })\n            let promises = requests.map(\n                req =>\n                    new Promise<void>((resolve, reject) => {\n                        req.onsuccess = () => resolve()\n                        req.onerror = () => reject()\n                    })\n            )\n            Promise.all(promises).then(() => {\n                delete configs.nedb\n                window.settings.setAll(configs)\n            })\n        }\n    } else {\n        const sRows = configs.lovefield.sources.map(s => {\n            s.lastFetched = new Date(s.lastFetched)\n            if (!s.textDir) s.textDir = SourceTextDirection.LTR\n            if (!s.hidden) s.hidden = false\n            return db.sources.createRow(s)\n        })\n        const iRows = configs.lovefield.items.map(i => {\n            i.date = new Date(i.date)\n            i.fetchedDate = new Date(i.fetchedDate)\n            return db.items.createRow(i)\n        })\n        await db.sourcesDB.insert().into(db.sources).values(sRows).exec()\n        await db.itemsDB.insert().into(db.items).values(iRows).exec()\n        delete configs.lovefield\n        window.settings.setAll(configs)\n    }\n    return false\n}\n"
  },
  {
    "path": "src/scripts/utils.ts",
    "content": "import intl from \"react-intl-universal\"\nimport { ThunkAction, ThunkDispatch } from \"redux-thunk\"\nimport { AnyAction } from \"redux\"\nimport { RootState } from \"./reducer\"\nimport Parser from \"rss-parser\"\nimport Url from \"url\"\nimport { SearchEngines } from \"../schema-types\"\n\nexport enum ActionStatus {\n    Request,\n    Success,\n    Failure,\n    Intermediate,\n}\n\nexport type AppThunk<ReturnType = void> = ThunkAction<\n    ReturnType,\n    RootState,\n    unknown,\n    AnyAction\n>\n\nexport type AppDispatch = ThunkDispatch<RootState, undefined, AnyAction>\n\nconst rssParser = new Parser({\n    customFields: {\n        item: [\n            \"thumb\",\n            \"image\",\n            [\"content:encoded\", \"fullContent\"],\n            [\"media:content\", \"mediaContent\", { keepArray: true }],\n        ],\n    },\n})\ntype extractGeneric<Type> = Type extends Parser<infer _, infer U> ? U : never\nexport type MyParserItem = extractGeneric<typeof rssParser> & Parser.Item\n\nconst CHARSET_RE = /charset=([^()<>@,;:\\\"/[\\]?.=\\s]*)/i\nconst XML_ENCODING_RE = /^<\\?xml.+encoding=\"(.+?)\".*?\\?>/i\nexport async function decodeFetchResponse(response: Response, isHTML = false) {\n    const buffer = await response.arrayBuffer()\n    let ctype =\n        response.headers.has(\"content-type\") &&\n        response.headers.get(\"content-type\")\n    let charset =\n        ctype && CHARSET_RE.test(ctype) ? CHARSET_RE.exec(ctype)[1] : undefined\n    let content = new TextDecoder(charset).decode(buffer)\n    if (charset === undefined) {\n        if (isHTML) {\n            const dom = domParser.parseFromString(content, \"text/html\")\n            charset = dom\n                .querySelector(\"meta[charset]\")\n                ?.getAttribute(\"charset\")\n                ?.toLowerCase()\n            if (!charset) {\n                ctype = dom\n                    .querySelector(\"meta[http-equiv='Content-Type']\")\n                    ?.getAttribute(\"content\")\n                charset =\n                    ctype &&\n                    CHARSET_RE.test(ctype) &&\n                    CHARSET_RE.exec(ctype)[1].toLowerCase()\n            }\n        } else {\n            charset =\n                XML_ENCODING_RE.test(content) &&\n                XML_ENCODING_RE.exec(content)[1].toLowerCase()\n        }\n        if (charset && charset !== \"utf-8\" && charset !== \"utf8\") {\n            content = new TextDecoder(charset).decode(buffer)\n        }\n    }\n    return content\n}\n\nexport async function parseRSS(url: string) {\n    let result: Response\n    try {\n        result = await fetch(url, { credentials: \"omit\" })\n    } catch {\n        throw new Error(intl.get(\"log.networkError\"))\n    }\n    if (result && result.ok) {\n        try {\n            return await rssParser.parseString(\n                await decodeFetchResponse(result)\n            )\n        } catch {\n            throw new Error(intl.get(\"log.parseError\"))\n        }\n    } else {\n        throw new Error(result.status + \" \" + result.statusText)\n    }\n}\n\nexport const domParser = new DOMParser()\n\nexport async function fetchFavicon(url: string) {\n    try {\n        url = url.split(\"/\").slice(0, 3).join(\"/\")\n        let result = await fetch(url, { credentials: \"omit\" })\n        if (result.ok) {\n            let html = await result.text()\n            let dom = domParser.parseFromString(html, \"text/html\")\n            let links = dom.getElementsByTagName(\"link\")\n            for (let link of links) {\n                let rel = link.getAttribute(\"rel\")\n                if (\n                    (rel === \"icon\" || rel === \"shortcut icon\") &&\n                    link.hasAttribute(\"href\")\n                ) {\n                    let href = link.getAttribute(\"href\")\n                    let parsedUrl = Url.parse(url)\n                    if (href.startsWith(\"//\")) return parsedUrl.protocol + href\n                    else if (href.startsWith(\"/\")) return url + href\n                    else return href\n                }\n            }\n        }\n        url = url + \"/favicon.ico\"\n        if (await validateFavicon(url)) {\n            return url\n        } else {\n            return null\n        }\n    } catch {\n        return null\n    }\n}\n\nexport async function validateFavicon(url: string) {\n    let flag = false\n    try {\n        const result = await fetch(url, { credentials: \"omit\" })\n        if (\n            result.status == 200 &&\n            result.headers.has(\"Content-Type\") &&\n            result.headers.get(\"Content-Type\").startsWith(\"image\")\n        ) {\n            flag = true\n        }\n    } finally {\n        return flag\n    }\n}\n\nexport function htmlDecode(input: string) {\n    var doc = domParser.parseFromString(input, \"text/html\")\n    return doc.documentElement.textContent\n}\n\nexport const urlTest = (s: string) =>\n    /https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,63}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)/gi.test(\n        s\n    )\n\nexport const getWindowBreakpoint = () => window.outerWidth >= 1440\n\nexport const cutText = (s: string, length: number) => {\n    return s.length <= length ? s : s.slice(0, length) + \"…\"\n}\n\nexport function getSearchEngineName(engine: SearchEngines) {\n    switch (engine) {\n        case SearchEngines.Google:\n            return intl.get(\"searchEngine.google\")\n        case SearchEngines.Bing:\n            return intl.get(\"searchEngine.bing\")\n        case SearchEngines.Baidu:\n            return intl.get(\"searchEngine.baidu\")\n        case SearchEngines.DuckDuckGo:\n            return intl.get(\"searchEngine.duckduckgo\")\n    }\n}\nexport function webSearch(text: string, engine = SearchEngines.Google) {\n    switch (engine) {\n        case SearchEngines.Google:\n            return window.utils.openExternal(\n                \"https://www.google.com/search?q=\" + encodeURIComponent(text)\n            )\n        case SearchEngines.Bing:\n            return window.utils.openExternal(\n                \"https://www.bing.com/search?q=\" + encodeURIComponent(text)\n            )\n        case SearchEngines.Baidu:\n            return window.utils.openExternal(\n                \"https://www.baidu.com/s?wd=\" + encodeURIComponent(text)\n            )\n        case SearchEngines.DuckDuckGo:\n            return window.utils.openExternal(\n                \"https://duckduckgo.com/?q=\" + encodeURIComponent(text)\n            )\n    }\n}\n\nexport function mergeSortedArrays<T>(\n    a: T[],\n    b: T[],\n    cmp: (x: T, y: T) => number\n): T[] {\n    let merged = new Array<T>()\n    let i = 0\n    let j = 0\n    while (i < a.length && j < b.length) {\n        if (cmp(a[i], b[j]) <= 0) {\n            merged.push(a[i++])\n        } else {\n            merged.push(b[j++])\n        }\n    }\n    while (i < a.length) merged.push(a[i++])\n    while (j < b.length) merged.push(b[j++])\n    return merged\n}\n\nexport function byteToMB(B: number) {\n    let MB = Math.round(B / 1048576)\n    return MB + \"MB\"\n}\n\nfunction byteLength(str: string) {\n    var s = str.length\n    for (var i = str.length - 1; i >= 0; i--) {\n        var code = str.charCodeAt(i)\n        if (code > 0x7f && code <= 0x7ff) s++\n        else if (code > 0x7ff && code <= 0xffff) s += 2\n        if (code >= 0xdc00 && code <= 0xdfff) i-- //trail surrogate\n    }\n    return s\n}\n\nexport function calculateItemSize(): Promise<number> {\n    return new Promise((resolve, reject) => {\n        let result = 0\n        let openRequest = window.indexedDB.open(\"itemsDB\")\n        openRequest.onsuccess = () => {\n            let db = openRequest.result\n            let objectStore = db.transaction(\"items\").objectStore(\"items\")\n            let cursorRequest = objectStore.openCursor()\n            cursorRequest.onsuccess = () => {\n                let cursor = cursorRequest.result\n                if (cursor) {\n                    result += byteLength(JSON.stringify(cursor.value))\n                    cursor.continue()\n                } else {\n                    resolve(result)\n                }\n            }\n            cursorRequest.onerror = () => reject()\n        }\n        openRequest.onerror = () => reject()\n    })\n}\n\nexport function validateRegex(regex: string, flags = \"\"): RegExp {\n    try {\n        return new RegExp(regex, flags)\n    } catch {\n        return null\n    }\n}\n\nexport function platformCtrl(\n    e: React.MouseEvent | React.KeyboardEvent | MouseEvent | KeyboardEvent\n) {\n    return window.utils.platform === \"darwin\" ? e.metaKey : e.ctrlKey\n}\n\nexport function initTouchBarWithTexts() {\n    window.utils.initTouchBar({\n        menu: intl.get(\"nav.menu\"),\n        search: intl.get(\"search\"),\n        refresh: intl.get(\"nav.refresh\"),\n        markAll: intl.get(\"nav.markAllRead\"),\n        notifications: intl.get(\"nav.notifications\"),\n    })\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n      \"jsx\": \"react\",\n      \"resolveJsonModule\": true,\n      \"esModuleInterop\": true,\n      \"target\": \"ES2019\",\n      \"module\": \"CommonJS\"\n    }\n}"
  },
  {
    "path": "webpack.config.js",
    "content": "const HtmlWebpackPlugin = require(\"html-webpack-plugin\")\nconst NodePolyfillPlugin = require(\"node-polyfill-webpack-plugin\")\n\nmodule.exports = [\n    {\n        mode: \"production\",\n        entry: \"./src/electron.ts\",\n        target: \"electron-main\",\n        module: {\n            rules: [\n                {\n                    test: /\\.ts$/,\n                    include: /src/,\n                    resolve: {\n                        extensions: [\".ts\", \".js\"],\n                    },\n                    use: [{ loader: \"ts-loader\" }],\n                },\n            ],\n        },\n        output: {\n            devtoolModuleFilenameTemplate: \"[absolute-resource-path]\",\n            path: __dirname + \"/dist\",\n            filename: \"electron.js\",\n        },\n        node: {\n            __dirname: false,\n        },\n    },\n    {\n        mode: \"production\",\n        entry: \"./src/preload.ts\",\n        target: \"electron-preload\",\n        module: {\n            rules: [\n                {\n                    test: /\\.ts$/,\n                    include: /src/,\n                    resolve: {\n                        extensions: [\".ts\", \".js\"],\n                    },\n                    use: [{ loader: \"ts-loader\" }],\n                },\n            ],\n        },\n        output: {\n            path: __dirname + \"/dist\",\n            filename: \"preload.js\",\n        },\n    },\n    {\n        mode: \"production\",\n        entry: \"./src/index.tsx\",\n        target: \"web\",\n        devtool: \"source-map\",\n        performance: {\n            hints: false,\n        },\n        module: {\n            rules: [\n                {\n                    test: /\\.ts(x?)$/,\n                    include: /src/,\n                    resolve: {\n                        extensions: [\".ts\", \".tsx\", \".js\"],\n                    },\n                    use: [{ loader: \"ts-loader\" }],\n                },\n            ],\n        },\n        output: {\n            path: __dirname + \"/dist\",\n            filename: \"index.js\",\n        },\n        plugins: [\n            new NodePolyfillPlugin(),\n            new HtmlWebpackPlugin({\n                template: \"./src/index.html\",\n            }),\n        ],\n    },\n]\n"
  }
]