diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..579aa61 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +artifacts +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Config files +.webextrc +.webextrc.* diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..7dc5d17 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,6 @@ +singleQuote: true +trailingComma: all +endOfLine: lf +printWidth: 100 +tabWidth: 2 +arrowParens: avoid diff --git a/README.md b/README.md index 8961d15..2304c08 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,32 @@ # Web Activity Time Tracker Add to Chrome +⚠️⚠️⚠️ **Important notice! The Chrome extension has been sold. So I am not responsible for any changes to the functionality of the extension.** ⚠️⚠️⚠️ + +**The new version is available on the Chrome Store https://chromewebstore.google.com/detail/timespy-block-websites-po/ggomgkmpcnmfhgmpfaphkbmnokllflom** + +[![Chrome Web Store](https://img.shields.io/chrome-web-store/d/hhfnghjdeddcfegfekjeihfmbjenlomm.svg?&label=Chrome%20users&ogo=google-chrome&logoColor=white)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) +[![Chrome Web Store](https://img.shields.io/chrome-web-store/rating/hhfnghjdeddcfegfekjeihfmbjenlomm?&logoColor=white;label=Rating)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) +[![Chrome Web Store](https://img.shields.io/chrome-web-store/v/hhfnghjdeddcfegfekjeihfmbjenlomm.svg?&logo=google-chrome&logoColor=white)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) + +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Edge%20users&query=%24.activeInstallCount&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf&color=gree)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Rating&suffix=/5&color=gree&query=%24.averageRating&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Microsoft%20Edge&prefix=v&query=%24.version&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf&logo=microsoft-edge)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) + Web Activity Time Tracker keeps track of how much time you spend on the web and presents the stats in a useful and intuitive way. You can set a daily visit limit for sites and block it after the expiration of the limit. -Extension uses only local [chrome.storage API](https://developer.chrome.com/apps/storage) chrome.storage API to store data and it does't send data anywhere. +Extension uses only local [chrome.storage API](https://developer.chrome.com/apps/storage) chrome.storage API to store data and it doesn't send data anywhere. ![image](https://user-images.githubusercontent.com/23387046/206865140-875bf7ab-a59e-42e3-bb9e-e348e8b85749.png) ![image](https://user-images.githubusercontent.com/23387046/206865174-aa409efe-495d-450e-a8ea-1d97024c9e23.png) You can see your daily stats. -![image](https://user-images.githubusercontent.com/23387046/206865189-2ffe27b2-c88a-40e0-82b5-a8df675554af.png) +![image](https://github.com/Stigmatoz/web-activity-time-tracker/assets/23387046/d67c812c-2ba4-4ef8-a685-ab5fd77c7fbe) + And you can see your overall stats. -![image](https://user-images.githubusercontent.com/23387046/206865219-31fe0473-b550-4a41-8348-576401be1395.png) +![image](https://github.com/Stigmatoz/web-activity-time-tracker/assets/23387046/6ea4547e-8bc6-4df7-ba0c-b5b330117270) If you have suggestions or problems using the extension, please [submit a bug or a feature request](https://github.com/Stigmatoz/web-activity-time-tracker/issues). @@ -29,6 +42,10 @@ Web Activity Time Tracker is available via the official [Chrome Web Store](https 3. Click on the "Load unpacked extension..." button. 4. Browse to the src directory of the unarchived folder and confirm. +# Run + +```pnpm run dev``` + # License -This work is licensed under a MIT License. +This work is licensed under an MIT License. diff --git a/package.json b/package.json new file mode 100644 index 0000000..9690984 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "web-activity-time-tracker", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite build --watch --mode development", + "start": "vite build --watch --mode production", + "format": "prettier --write .", + "script:zip": "vite build --mode production && powershell scripts/zip.ps1" + }, + "dependencies": { + "@vueuse/core": "^10.11.1", + "chart.js": "^4.4.7", + "d3": "^7.9.0", + "date-fns": "^2.30.0", + "rollup-plugin-copy": "^3.5.0", + "vue": "^3.5.13", + "vue-chartjs": "^5.3.2", + "vue-i18n": "^9.14.2" + }, + "devDependencies": { + "@intlify/unplugin-vue-i18n": "^0.12.3", + "@kyvg/vue3-notification": "^2.9.1", + "@types/d3": "^7.4.3", + "@types/webextension-polyfill": "^0.10.7", + "@vitejs/plugin-vue": "^4.6.2", + "@vuepic/vue-datepicker": "^5.4.0", + "typescript": "^5.7.2", + "vite": "^4.5.5", + "vite-plugin-web-extension": "^4.0.0", + "vue-tsc": "^2.2.0", + "webextension-polyfill": "^0.10.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..b18b78f --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3129 @@ +lockfileVersion: 5.4 + +specifiers: + '@intlify/unplugin-vue-i18n': ^0.12.3 + '@kyvg/vue3-notification': ^2.9.1 + '@types/d3': ^7.4.3 + '@types/webextension-polyfill': ^0.10.7 + '@vitejs/plugin-vue': ^4.6.2 + '@vuepic/vue-datepicker': ^5.4.0 + '@vueuse/core': ^10.11.1 + chart.js: ^4.4.7 + d3: ^7.9.0 + date-fns: ^2.30.0 + rollup-plugin-copy: ^3.5.0 + typescript: ^5.7.2 + vite: ^4.5.5 + vite-plugin-web-extension: ^4.0.0 + vue: ^3.5.13 + vue-chartjs: ^5.3.2 + vue-i18n: ^9.14.2 + vue-tsc: ^2.2.0 + webextension-polyfill: ^0.10.0 + +dependencies: + '@vueuse/core': 10.11.1_vue@3.5.13 + chart.js: 4.4.7 + d3: 7.9.0 + date-fns: 2.30.0 + rollup-plugin-copy: 3.5.0 + vue: 3.5.13_typescript@5.7.2 + vue-chartjs: 5.3.2_chart.js@4.4.7+vue@3.5.13 + vue-i18n: 9.14.2_vue@3.5.13 + +devDependencies: + '@intlify/unplugin-vue-i18n': 0.12.3_vue-i18n@9.14.2 + '@kyvg/vue3-notification': 2.9.1_vue@3.5.13 + '@types/d3': 7.4.3 + '@types/webextension-polyfill': 0.10.7 + '@vitejs/plugin-vue': 4.6.2_vite@4.5.5+vue@3.5.13 + '@vuepic/vue-datepicker': 5.4.0_vue@3.5.13 + typescript: 5.7.2 + vite: 4.5.5 + vite-plugin-web-extension: 4.3.1 + vue-tsc: 2.2.0_typescript@5.7.2 + webextension-polyfill: 0.10.0 + +packages: + + /@babel/code-frame/7.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/helper-string-parser/7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier/7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + /@babel/parser/7.26.3: + resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.26.3 + + /@babel/runtime/7.24.7: + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true + + /@babel/runtime/7.26.0: + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + + /@babel/types/7.26.3: + resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + /@devicefarmer/adbkit-logcat/2.1.3: + resolution: {integrity: sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw==} + engines: {node: '>= 4'} + dev: true + + /@devicefarmer/adbkit-monkey/1.2.1: + resolution: {integrity: sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==} + engines: {node: '>= 0.10.4'} + dev: true + + /@devicefarmer/adbkit/3.2.6: + resolution: {integrity: sha512-8lO1hSeTgtxcOHhp4tTWq/JaOysp5KNbbyFoxNEBnwkCDZu/Bji3ZfOaG++Riv9jN6c9bgdLBOZqJTC5VJPRKQ==} + engines: {node: '>= 0.10.4'} + hasBin: true + dependencies: + '@devicefarmer/adbkit-logcat': 2.1.3 + '@devicefarmer/adbkit-monkey': 1.2.1 + bluebird: 3.7.2 + commander: 9.5.0 + debug: 4.3.7 + node-forge: 1.3.1 + split: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@esbuild/android-arm/0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@intlify/bundle-utils/7.5.1_vue-i18n@9.14.2: + resolution: {integrity: sha512-UovJl10oBIlmYEcWw+VIHdKY5Uv5sdPG0b/b6bOYxGLln3UwB75+2dlc0F3Fsa0RhoznQ5Rp589/BZpABpE4Xw==} + engines: {node: '>= 14.16'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + dependencies: + '@intlify/message-compiler': 9.14.2 + '@intlify/shared': 9.14.2 + acorn: 8.14.0 + escodegen: 2.1.0 + estree-walker: 2.0.2 + jsonc-eslint-parser: 2.4.0 + magic-string: 0.30.17 + mlly: 1.7.3 + source-map-js: 1.2.1 + vue-i18n: 9.14.2_vue@3.5.13 + yaml-eslint-parser: 1.2.3 + dev: true + + /@intlify/core-base/9.14.2: + resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==} + engines: {node: '>= 16'} + dependencies: + '@intlify/message-compiler': 9.14.2 + '@intlify/shared': 9.14.2 + + /@intlify/message-compiler/9.14.2: + resolution: {integrity: sha512-YsKKuV4Qv4wrLNsvgWbTf0E40uRv+Qiw1BeLQ0LAxifQuhiMe+hfTIzOMdWj/ZpnTDj4RSZtkXjJM7JDiiB5LQ==} + engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.14.2 + source-map-js: 1.2.1 + + /@intlify/shared/9.14.2: + resolution: {integrity: sha512-uRAHAxYPeF+G5DBIboKpPgC/Waecd4Jz8ihtkpJQD5ycb5PwXp0k/+hBGl5dAjwF7w+l74kz/PKA8r8OK//RUw==} + engines: {node: '>= 16'} + + /@intlify/shared/9.3.0-beta.24: + resolution: {integrity: sha512-AKxJ8s7eKIQWkNaf4wyyoLRwf4puCuQgjSChlDJm5JBEt6T8HGgnYTJLRXu6LD/JACn3Qwu6hM/XRX1c9yvjmQ==} + engines: {node: '>= 16'} + dev: true + + /@intlify/unplugin-vue-i18n/0.12.3_vue-i18n@9.14.2: + resolution: {integrity: sha512-0riPtSfTM58JmGNMmJho/aHD2z3K24BESYAmkLvKlo61/LbaPvnjYU1DbSbJEm6bSjE2oEjUj+di3QaYxXei/w==} + engines: {node: '>= 14.16'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + vue-i18n-bridge: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + vue-i18n-bridge: + optional: true + dependencies: + '@intlify/bundle-utils': 7.5.1_vue-i18n@9.14.2 + '@intlify/shared': 9.3.0-beta.24 + '@rollup/pluginutils': 5.1.4 + '@vue/compiler-sfc': 3.5.13 + debug: 4.4.0 + fast-glob: 3.3.2 + js-yaml: 4.1.0 + json5: 2.2.3 + pathe: 1.1.2 + picocolors: 1.1.1 + source-map-js: 1.2.1 + unplugin: 1.16.0 + vue-i18n: 9.14.2_vue@3.5.13 + transitivePeerDependencies: + - rollup + - supports-color + dev: true + + /@jridgewell/sourcemap-codec/1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + /@kurkle/color/0.3.4: + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + dev: false + + /@kyvg/vue3-notification/2.9.1_vue@3.5.13: + resolution: {integrity: sha512-FsY8g25tQetr3etnarxHtCeNFKssH8sheFu13LyL2JJmOOel437QqKV5n4RBDDDTIo55iKgIVYXeojliXYdEhw==} + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + /@pnpm/config.env-replace/1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + dev: true + + /@pnpm/network.ca-file/1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + dependencies: + graceful-fs: 4.2.10 + dev: true + + /@pnpm/npm-conf/2.3.1: + resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + engines: {node: '>=12'} + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + dev: true + + /@rollup/pluginutils/5.1.4: + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + dev: true + + /@sindresorhus/is/5.6.0: + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + dev: true + + /@szmarczak/http-timer/5.0.1: + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + dependencies: + defer-to-connect: 2.0.1 + dev: true + + /@types/d3-array/3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: true + + /@types/d3-axis/3.0.6: + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-brush/3.0.6: + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-chord/3.0.6: + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + dev: true + + /@types/d3-color/3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: true + + /@types/d3-contour/3.0.6: + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.15 + dev: true + + /@types/d3-delaunay/6.0.4: + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + dev: true + + /@types/d3-dispatch/3.0.6: + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + dev: true + + /@types/d3-drag/3.0.7: + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-dsv/3.0.7: + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + dev: true + + /@types/d3-ease/3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: true + + /@types/d3-fetch/3.0.7: + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + dependencies: + '@types/d3-dsv': 3.0.7 + dev: true + + /@types/d3-force/3.0.10: + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + dev: true + + /@types/d3-format/3.0.4: + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + dev: true + + /@types/d3-geo/3.1.0: + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + dependencies: + '@types/geojson': 7946.0.15 + dev: true + + /@types/d3-hierarchy/3.1.7: + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + dev: true + + /@types/d3-interpolate/3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: true + + /@types/d3-path/3.1.0: + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + dev: true + + /@types/d3-polygon/3.0.2: + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + dev: true + + /@types/d3-quadtree/3.0.6: + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + dev: true + + /@types/d3-random/3.0.3: + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + dev: true + + /@types/d3-scale-chromatic/3.1.0: + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + dev: true + + /@types/d3-scale/4.0.8: + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + dependencies: + '@types/d3-time': 3.0.4 + dev: true + + /@types/d3-selection/3.0.11: + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + dev: true + + /@types/d3-shape/3.1.6: + resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + dependencies: + '@types/d3-path': 3.1.0 + dev: true + + /@types/d3-time-format/4.0.3: + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + dev: true + + /@types/d3-time/3.0.4: + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + dev: true + + /@types/d3-timer/3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: true + + /@types/d3-transition/3.0.9: + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-zoom/3.0.8: + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3/7.4.3: + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.0 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.8 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.6 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + dev: true + + /@types/estree/1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + + /@types/fs-extra/8.1.5: + resolution: {integrity: sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==} + dependencies: + '@types/node': 22.10.2 + dev: false + + /@types/geojson/7946.0.15: + resolution: {integrity: sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==} + dev: true + + /@types/glob/7.2.0: + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 22.10.2 + dev: false + + /@types/http-cache-semantics/4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + dev: true + + /@types/minimatch/3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + + /@types/minimatch/5.1.2: + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + dev: false + + /@types/node/22.10.2: + resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} + dependencies: + undici-types: 6.20.0 + + /@types/web-bluetooth/0.0.20: + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + dev: false + + /@types/webextension-polyfill/0.10.7: + resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==} + dev: true + + /@vitejs/plugin-vue/4.6.2_vite@4.5.5+vue@3.5.13: + resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 || ^5.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.5.5 + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@volar/language-core/2.4.11: + resolution: {integrity: sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==} + dependencies: + '@volar/source-map': 2.4.11 + dev: true + + /@volar/source-map/2.4.11: + resolution: {integrity: sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==} + dev: true + + /@volar/typescript/2.4.11: + resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==} + dependencies: + '@volar/language-core': 2.4.11 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + dev: true + + /@vue/compiler-core/3.5.13: + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + dependencies: + '@babel/parser': 7.26.3 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + /@vue/compiler-dom/3.5.13: + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/compiler-sfc/3.5.13: + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + dependencies: + '@babel/parser': 7.26.3 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.4.49 + source-map-js: 1.2.1 + + /@vue/compiler-ssr/3.5.13: + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/compiler-vue2/2.7.16: + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /@vue/devtools-api/6.6.4: + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + /@vue/language-core/2.2.0_typescript@5.7.2: + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.10 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.7.2 + dev: true + + /@vue/reactivity/3.5.13: + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + dependencies: + '@vue/shared': 3.5.13 + + /@vue/runtime-core/3.5.13: + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/runtime-dom/3.5.13: + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + /@vue/server-renderer/3.5.13_vue@3.5.13: + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13_typescript@5.7.2 + + /@vue/shared/3.5.13: + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + /@vuepic/vue-datepicker/5.4.0_vue@3.5.13: + resolution: {integrity: sha512-9f1ZqRDfak/UmBbD81BdqMDpUku2YphTwQXG8DF6hsrjIXsq5sX7BWJB6LhyVgvX9QFrSyFIp4fsHE3UFofZ7A==} + engines: {node: '>=14'} + peerDependencies: + vue: '>=3.2.0' + dependencies: + date-fns: 2.30.0 + date-fns-tz: 1.3.8_date-fns@2.30.0 + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@vueuse/core/10.11.1_vue@3.5.13: + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1_vue@3.5.13 + vue-demi: 0.14.10_vue@3.5.13 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/metadata/10.11.1: + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + dev: false + + /@vueuse/shared/10.11.1_vue@3.5.13: + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + dependencies: + vue-demi: 0.14.10_vue@3.5.13 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /acorn-jsx/5.3.2_acorn@8.14.0: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + dev: true + + /acorn/8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /adm-zip/0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + dev: true + + /ajv/8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: true + + /alien-signals/0.4.10: + resolution: {integrity: sha512-7S60rz/mMjz0Djq1VI9rd4bGqKNgxTUGE6k7kwrRO6tF95qt1S3ohz1qaQisvUsfbGh7yXnm6DPRrOhOl1ho1A==} + dev: true + + /ansi-align/3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + dependencies: + string-width: 4.2.3 + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex/6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles/6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /any-promise/1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-differ/4.0.0: + resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: false + + /array-union/3.0.1: + resolution: {integrity: sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==} + engines: {node: '>=12'} + dev: true + + /async-lock/1.4.1: + resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} + dev: true + + /async/3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + dev: true + + /at-least-node/1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /bluebird/3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /boolbase/1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /boxen/7.1.1: + resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} + engines: {node: '>=14.16'} + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.4.1 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion/2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces/3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /bunyan/1.8.15: + resolution: {integrity: sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==} + engines: {'0': node >=0.10.0} + hasBin: true + optionalDependencies: + dtrace-provider: 0.8.8 + moment: 2.30.1 + mv: 2.1.1 + safe-json-stringify: 1.2.0 + dev: true + + /cacheable-lookup/7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + dev: true + + /cacheable-request/10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + dev: true + + /camelcase/7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + + /chalk/5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /charenc/0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + dev: true + + /chart.js/4.4.7: + resolution: {integrity: sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==} + engines: {pnpm: '>=8'} + dependencies: + '@kurkle/color': 0.3.4 + dev: false + + /chrome-launcher/1.1.0: + resolution: {integrity: sha512-rJYWeEAERwWIr3c3mEVXwNiODPEdMRlRxHc47B1qHPOolHZnkj7rMv1QSUfPoG6MgatWj5AxSpnKKR4QEwEQIQ==} + engines: {node: '>=12.13.0'} + hasBin: true + dependencies: + '@types/node': 22.10.2 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /ci-info/3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /cli-boxes/3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + dev: true + + /colorette/1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + dev: false + + /commander/2.9.0: + resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==} + engines: {node: '>= 0.6.x'} + dependencies: + graceful-readlink: 1.0.1 + dev: true + + /commander/7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /concat-stream/1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + dev: true + + /confbox/0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + dev: true + + /config-chain/1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: true + + /configstore/6.0.0: + resolution: {integrity: sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==} + engines: {node: '>=12'} + dependencies: + dot-prop: 6.0.1 + graceful-fs: 4.2.11 + unique-string: 3.0.0 + write-file-atomic: 3.0.3 + xdg-basedir: 5.1.0 + dev: true + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /crypt/0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + dev: true + + /crypto-random-string/4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /css-select/5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.1 + nth-check: 2.1.1 + dev: true + + /css-what/6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: true + + /cssom/0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + dev: true + + /csstype/3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + /d3-array/3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + dependencies: + internmap: 2.0.3 + dev: false + + /d3-axis/3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + dev: false + + /d3-brush/3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1_d3-selection@3.0.0 + dev: false + + /d3-chord/3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-color/3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + dev: false + + /d3-contour/4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-delaunay/6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + dependencies: + delaunator: 5.0.1 + dev: false + + /d3-dispatch/3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + dev: false + + /d3-drag/3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + dev: false + + /d3-dsv/3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + dev: false + + /d3-ease/3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + dev: false + + /d3-fetch/3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + dependencies: + d3-dsv: 3.0.1 + dev: false + + /d3-force/3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + dev: false + + /d3-format/3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + dev: false + + /d3-geo/3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-hierarchy/3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + dev: false + + /d3-interpolate/3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false + + /d3-path/3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + dev: false + + /d3-polygon/3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + dev: false + + /d3-quadtree/3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + dev: false + + /d3-random/3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + dev: false + + /d3-scale-chromatic/3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + dev: false + + /d3-scale/4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + dev: false + + /d3-selection/3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + dev: false + + /d3-shape/3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-time-format/4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + dependencies: + d3-time: 3.1.0 + dev: false + + /d3-time/3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-timer/3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + dev: false + + /d3-transition/3.0.1_d3-selection@3.0.0: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + dev: false + + /d3-zoom/3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1_d3-selection@3.0.0 + dev: false + + /d3/7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1_d3-selection@3.0.0 + d3-zoom: 3.0.0 + dev: false + + /date-fns-tz/1.3.8_date-fns@2.30.0: + resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==} + peerDependencies: + date-fns: '>=2.0.0' + dependencies: + date-fns: 2.30.0 + dev: true + + /date-fns/2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.26.0 + + /de-indent/1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + dev: true + + /debounce/1.2.1: + resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} + dev: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: true + + /debug/4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /debug/4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: true + + /deep-extend/0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: true + + /defer-to-connect/2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: true + + /delaunator/5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + dependencies: + robust-predicates: 3.0.2 + dev: false + + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: false + + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: true + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils/3.2.1: + resolution: {integrity: sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: true + + /dot-prop/6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + dependencies: + is-obj: 2.0.0 + dev: true + + /dtrace-provider/0.8.8: + resolution: {integrity: sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==} + engines: {node: '>=0.10'} + requiresBuild: true + dependencies: + nan: 2.22.0 + dev: true + optional: true + + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /entities/4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es6-error/4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + dev: true + + /esbuild/0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /escape-goat/4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escodegen/2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + + /eslint-visitor-keys/3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /espree/9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2_acorn@8.14.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker/2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob/3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + /fast-uri/3.0.3: + resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + dev: true + + /fastq/1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + dependencies: + reusify: 1.0.4 + + /fill-range/7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /firefox-profile/4.6.0: + resolution: {integrity: sha512-I9rAm1w8U3CdhgO4EzTJsCvgcbvynZn9lOySkZf78wUdUIQH2w9QOKf3pAX+THt2XMSSR3kJSuM8P7bYux9j8g==} + hasBin: true + dependencies: + adm-zip: 0.5.16 + fs-extra: 9.0.1 + ini: 2.0.0 + minimist: 1.2.8 + xml2js: 0.5.0 + dev: true + + /form-data-encoder/2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + dev: true + + /fs-extra/10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra/11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-extra/9.0.1: + resolution: {integrity: sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 1.0.0 + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: false + + /fsevents/2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /fx-runner/1.4.0: + resolution: {integrity: sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==} + hasBin: true + dependencies: + commander: 2.9.0 + shell-quote: 1.7.3 + spawn-sync: 1.0.15 + when: 3.7.7 + which: 1.2.4 + winreg: 0.0.12 + dev: true + + /get-stream/6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-to-regexp/0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + + /glob/6.0.4: + resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + optional: true + + /glob/7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /global-dirs/3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /globby/10.0.1: + resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} + engines: {node: '>=8'} + dependencies: + '@types/glob': 7.2.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + glob: 7.2.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + dev: false + + /got/12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: true + + /graceful-fs/4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + dev: true + + /graceful-fs/4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graceful-readlink/1.0.1: + resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==} + dev: true + + /growly/1.3.0: + resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} + dev: true + + /has-yarn/3.0.0: + resolution: {integrity: sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /he/1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /html-escaper/3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + dev: true + + /htmlparser2/8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.1 + entities: 4.5.0 + dev: true + + /http-cache-semantics/4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: true + + /http2-wrapper/2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: true + + /iconv-lite/0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /ignore/5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + dev: false + + /immediate/3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + dev: true + + /import-lazy/4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /ini/2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /internmap/2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + dev: false + + /is-absolute/0.1.7: + resolution: {integrity: sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==} + engines: {node: '>=0.10.0'} + dependencies: + is-relative: 0.1.3 + dev: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-buffer/1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: true + + /is-ci/3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.9.0 + dev: true + + /is-docker/2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-installed-globally/0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-npm/6.0.0: + resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-obj/2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: true + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-object/2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: true + + /is-plain-object/3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + dev: false + + /is-primitive/3.0.1: + resolution: {integrity: sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==} + engines: {node: '>=0.10.0'} + dev: true + + /is-relative/0.1.3: + resolution: {integrity: sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==} + engines: {node: '>=0.10.0'} + dev: true + + /is-typedarray/1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: true + + /is-wsl/2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /is-yarn-global/0.4.1: + resolution: {integrity: sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==} + engines: {node: '>=12'} + dev: true + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + + /isexe/1.1.2: + resolution: {integrity: sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw==} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isobject/3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors/3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /json-schema-traverse/1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + + /json5/2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonc-eslint-parser/2.4.0: + resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.14.0 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + semver: 7.6.3 + dev: true + + /jsonfile/4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: false + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + + /jszip/3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + dev: true + + /keyv/4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /latest-version/7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} + dependencies: + package-json: 8.1.1 + dev: true + + /lie/3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + dependencies: + immediate: 3.0.6 + dev: true + + /lighthouse-logger/2.0.1: + resolution: {integrity: sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==} + dependencies: + debug: 2.6.9 + marky: 1.2.5 + transitivePeerDependencies: + - supports-color + dev: true + + /lines-and-columns/2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /linkedom/0.14.26: + resolution: {integrity: sha512-mK6TrydfFA7phrnp+1j57ycBwFI5bGSW6YXlw9acHoqF+mP/y+FooEYYyniOt5Ot57FSKB3iwmnuQ1UUyNLm5A==} + dependencies: + css-select: 5.1.0 + cssom: 0.5.0 + html-escaper: 3.0.3 + htmlparser2: 8.0.2 + uhyphen: 0.2.0 + dev: true + + /lodash.uniq/4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: true + + /lodash.uniqby/4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + dev: true + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /lowercase-keys/3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /magic-string/0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /marky/1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + dev: true + + /md5/2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + dev: true + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromatch/4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: true + + /mimic-response/4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch/9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /mkdirp/0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + optional: true + + /mkdirp/3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /mlly/1.7.3: + resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + dev: true + + /moment/2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + requiresBuild: true + dev: true + optional: true + + /ms/2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /muggle-string/0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + dev: true + + /multimatch/6.0.0: + resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 4.0.0 + array-union: 3.0.1 + minimatch: 3.1.2 + dev: true + + /mv/2.1.1: + resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} + engines: {node: '>=0.8.0'} + requiresBuild: true + dependencies: + mkdirp: 0.5.6 + ncp: 2.0.0 + rimraf: 2.4.5 + dev: true + optional: true + + /mz/2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nan/2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + dev: true + optional: true + + /nanoid/3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /ncp/2.0.0: + resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} + hasBin: true + dev: true + optional: true + + /node-forge/1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: true + + /node-notifier/10.0.1: + resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==} + dependencies: + growly: 1.3.0 + is-wsl: 2.2.0 + semver: 7.6.3 + shellwords: 0.1.1 + uuid: 8.3.2 + which: 2.0.2 + dev: true + + /normalize-url/8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + dev: true + + /nth-check/2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /os-shim/0.1.3: + resolution: {integrity: sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==} + engines: {node: '>= 0.4.0'} + dev: true + + /p-cancelable/3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + dev: true + + /package-json/8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + dependencies: + got: 12.6.1 + registry-auth-token: 5.0.3 + registry-url: 6.0.1 + semver: 7.6.3 + dev: true + + /pako/1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + + /parse-json/7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + dev: true + + /path-browserify/1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + + /pathe/1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true + + /picocolors/1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /picomatch/4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + + /pkg-types/1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.3 + pathe: 1.1.2 + dev: true + + /postcss/8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /promise-toolbox/0.21.0: + resolution: {integrity: sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==} + engines: {node: '>=6'} + dependencies: + make-error: 1.3.6 + dev: true + + /proto-list/1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true + + /pupa/3.1.0: + resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} + engines: {node: '>=12.20'} + dependencies: + escape-goat: 4.0.0 + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /rc/1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: true + + /readable-stream/2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /regenerator-runtime/0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + /registry-auth-token/5.0.3: + resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==} + engines: {node: '>=14'} + dependencies: + '@pnpm/npm-conf': 2.3.1 + dev: true + + /registry-url/6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + dependencies: + rc: 1.2.8 + dev: true + + /require-from-string/2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-alpn/1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: true + + /responselike/3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + dependencies: + lowercase-keys: 3.0.0 + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf/2.4.5: + resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + dependencies: + glob: 6.0.4 + dev: true + optional: true + + /robust-predicates/3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + dev: false + + /rollup-plugin-copy/3.5.0: + resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} + engines: {node: '>=8.3'} + dependencies: + '@types/fs-extra': 8.1.5 + colorette: 1.4.0 + fs-extra: 8.1.0 + globby: 10.0.1 + is-plain-object: 3.0.1 + dev: false + + /rollup/3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /rw/1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + dev: false + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-json-stringify/1.2.0: + resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==} + requiresBuild: true + dev: true + optional: true + + /safer-buffer/2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /sax/1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + dev: true + + /semver-diff/4.0.0: + resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} + engines: {node: '>=12'} + dependencies: + semver: 7.6.3 + dev: true + + /semver/7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /set-value/4.1.0: + resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} + engines: {node: '>=11.0'} + dependencies: + is-plain-object: 2.0.4 + is-primitive: 3.0.1 + dev: true + + /setimmediate/1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: true + + /shell-quote/1.7.3: + resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} + dev: true + + /shellwords/0.1.1: + resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} + dev: true + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /slash/3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: false + + /source-map-js/1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /spawn-sync/1.0.15: + resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} + requiresBuild: true + dependencies: + concat-stream: 1.6.2 + os-shim: 0.1.3 + dev: true + + /split/1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + dependencies: + through: 2.3.8 + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width/5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi/7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.1.0 + dev: true + + /strip-bom/5.0.0: + resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==} + engines: {node: '>=12'} + dev: true + + /strip-json-comments/2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: true + + /strip-json-comments/5.0.1: + resolution: {integrity: sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==} + engines: {node: '>=14.16'} + dev: true + + /thenify-all/1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify/3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /through/2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /tmp/0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /type-fest/2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + + /type-fest/3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: true + + /typedarray-to-buffer/3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: true + + /typedarray/0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + dev: true + + /typescript/5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + /ufo/1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + dev: true + + /uhyphen/0.2.0: + resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} + dev: true + + /undici-types/6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + /unique-string/3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + dependencies: + crypto-random-string: 4.0.0 + dev: true + + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + + /universalify/1.0.0: + resolution: {integrity: sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==} + engines: {node: '>= 10.0.0'} + dev: true + + /universalify/2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + dev: true + + /unplugin/1.16.0: + resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==} + engines: {node: '>=14.0.0'} + dependencies: + acorn: 8.14.0 + webpack-virtual-modules: 0.6.2 + dev: true + + /update-notifier/6.0.2: + resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} + engines: {node: '>=14.16'} + dependencies: + boxen: 7.1.1 + chalk: 5.4.1 + configstore: 6.0.0 + has-yarn: 3.0.0 + import-lazy: 4.0.0 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + is-npm: 6.0.0 + is-yarn-global: 0.4.1 + latest-version: 7.0.0 + pupa: 3.1.0 + semver: 7.6.3 + semver-diff: 4.0.0 + xdg-basedir: 5.1.0 + dev: true + + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /vite-plugin-web-extension/4.3.1: + resolution: {integrity: sha512-yG/07Rzk70SxLUQIfZMbNm0472gbFPkoPCAJvcGhyblTrg0FPSKfkQJ4yug0//IxoYCaTv5WIcNJCuVntUz4rQ==} + engines: {node: '>=16'} + dependencies: + ajv: 8.17.1 + async-lock: 1.4.1 + fs-extra: 10.1.0 + json5: 2.2.3 + linkedom: 0.14.26 + lodash.uniq: 4.5.0 + lodash.uniqby: 4.7.0 + md5: 2.3.0 + vite: 4.5.5 + web-ext-run: 0.2.2 + webextension-polyfill: 0.10.0 + yaml: 2.6.1 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + - utf-8-validate + dev: true + + /vite/4.5.5: + resolution: {integrity: sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.18.20 + postcss: 8.4.49 + rollup: 3.29.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vscode-uri/3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + dev: true + + /vue-chartjs/5.3.2_chart.js@4.4.7+vue@3.5.13: + resolution: {integrity: sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==} + peerDependencies: + chart.js: ^4.1.1 + vue: ^3.0.0-0 || ^2.7.0 + dependencies: + chart.js: 4.4.7 + vue: 3.5.13_typescript@5.7.2 + dev: false + + /vue-demi/0.14.10_vue@3.5.13: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.5.13_typescript@5.7.2 + dev: false + + /vue-i18n/9.14.2_vue@3.5.13: + resolution: {integrity: sha512-JK9Pm80OqssGJU2Y6F7DcM8RFHqVG4WkuCqOZTVsXkEzZME7ABejAUqUdA931zEBedc4thBgSUWxeQh4uocJAQ==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@intlify/core-base': 9.14.2 + '@intlify/shared': 9.14.2 + '@vue/devtools-api': 6.6.4 + vue: 3.5.13_typescript@5.7.2 + + /vue-tsc/2.2.0_typescript@5.7.2: + resolution: {integrity: sha512-gtmM1sUuJ8aSb0KoAFmK9yMxb8TxjewmxqTJ1aKphD5Cbu0rULFY6+UQT51zW7SpUcenfPUuflKyVwyx9Qdnxg==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + dependencies: + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.0_typescript@5.7.2 + typescript: 5.7.2 + dev: true + + /vue/3.5.13_typescript@5.7.2: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13_vue@3.5.13 + '@vue/shared': 3.5.13 + typescript: 5.7.2 + + /watchpack/2.4.1: + resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + dev: true + + /web-ext-run/0.2.2: + resolution: {integrity: sha512-GD59q5/1wYQJXTHrljMZaBa3cCz+Jj3FMDLYgKyAa34TPcHSuMaGqp7TcLJ66PCe43C3hmbEAZd8QCpAB34eiw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + dependencies: + '@babel/runtime': 7.24.7 + '@devicefarmer/adbkit': 3.2.6 + bunyan: 1.8.15 + chrome-launcher: 1.1.0 + debounce: 1.2.1 + es6-error: 4.1.1 + firefox-profile: 4.6.0 + fs-extra: 11.2.0 + fx-runner: 1.4.0 + mkdirp: 3.0.1 + multimatch: 6.0.0 + mz: 2.7.0 + node-notifier: 10.0.1 + parse-json: 7.1.1 + promise-toolbox: 0.21.0 + set-value: 4.1.0 + source-map-support: 0.5.21 + strip-bom: 5.0.0 + strip-json-comments: 5.0.1 + tmp: 0.2.3 + update-notifier: 6.0.2 + watchpack: 2.4.1 + ws: 8.18.0 + zip-dir: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /webextension-polyfill/0.10.0: + resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} + dev: true + + /webpack-virtual-modules/0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + dev: true + + /when/3.7.7: + resolution: {integrity: sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw==} + dev: true + + /which/1.2.4: + resolution: {integrity: sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA==} + hasBin: true + dependencies: + is-absolute: 0.1.7 + isexe: 1.1.2 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /widest-line/4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + dev: true + + /winreg/0.0.12: + resolution: {integrity: sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ==} + dev: true + + /wrap-ansi/8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic/3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + dev: true + + /ws/8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + + /xdg-basedir/5.1.0: + resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} + engines: {node: '>=12'} + dev: true + + /xml2js/0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.4.1 + xmlbuilder: 11.0.1 + dev: true + + /xmlbuilder/11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: true + + /yaml-eslint-parser/1.2.3: + resolution: {integrity: sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==} + engines: {node: ^14.17.0 || >=16.0.0} + dependencies: + eslint-visitor-keys: 3.4.3 + lodash: 4.17.21 + yaml: 2.6.1 + dev: true + + /yaml/2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + + /zip-dir/2.0.0: + resolution: {integrity: sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==} + dependencies: + async: 3.2.6 + jszip: 3.10.1 + dev: true diff --git a/src/icons/128x128.png b/public/128x128.png similarity index 100% rename from src/icons/128x128.png rename to public/128x128.png diff --git a/src/icons/16x16.png b/public/16x16.png similarity index 100% rename from src/icons/16x16.png rename to public/16x16.png diff --git a/src/icons/32x32.png b/public/32x32.png similarity index 100% rename from src/icons/32x32.png rename to public/32x32.png diff --git a/src/icons/48x48.png b/public/48x48.png similarity index 100% rename from src/icons/48x48.png rename to public/48x48.png diff --git a/scripts/zip.ps1 b/scripts/zip.ps1 new file mode 100644 index 0000000..3e258e5 --- /dev/null +++ b/scripts/zip.ps1 @@ -0,0 +1,7 @@ +$sourceFolder = ".\dist\*" +$targetFolder = ".\artifacts" +If (!(test-path -PathType container $targetFolder)) { + New-Item -ItemType Directory -Path $targetFolder +} +$version = $(node -pe "require('./src/manifest.json').version") +Compress-Archive -Path $sourceFolder -DestinationPath $targetFolder/web-activity-time-tracker-$version.zip \ No newline at end of file diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json new file mode 100644 index 0000000..c9f366d --- /dev/null +++ b/src/_locales/de/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Websites sperren, Pomodoro & Webanalyse" + }, + "extDescription": { + "message": "Verfolgen und begrenzen Sie die Zeit Ihrer Webaktivitäten und blockieren Sie den Zugang zu den Websites." + }, + "settings": { + "message": "Einstellungen" + }, + "today": { + "message": "Heute" + }, + "allTime": { + "message": "Gesamte Zeit" + }, + "byDays": { + "message": "Täglich" + }, + "noData": { + "message": "Keine Daten verfügbar" + }, + "noDataForPeriod": { + "message": "Keine Daten für den ausgewählten Zeitraum" + }, + "showAll": { + "message": "Alle Websites anzeigen" + }, + "sortBy": { + "message": "Sortieren nach" + }, + "usageTime": { + "message": "Verwendungszeit" + }, + "session": { + "message": "Sitzung" + }, + "someSession": { + "message": "Sitzungen" + }, + "sessions": { + "message": "Sitzungen" + }, + "days": { + "message": "Tage" + }, + "aggregate": { + "message": "Gesammelte Daten seit" + }, + "websites": { + "message": "Webseiten" + }, + "cannotOpenFile": { + "message": "Aufgrund des Sicherheitsprotokolls können Sie eine lokale Datei nicht öffnen" + }, + "document": { + "message": "Dokument" + }, + "limit": { + "message": "Limit" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "Der erste aktive Tag" + }, + "numberOfActiveDays": { + "message": "Gesamtzahl der aktiven Tage" + }, + "totalNumberOfDays": { + "message": "Alle Tage" + }, + "todayTime": { + "message": "Gesamtzeit heute" + }, + "averageTime": { + "message": "Durchschnittliche Zeit an aktiven Tagen" + }, + "averageDailyUsage": { + "message": "Durchschnittliche tägliche Nutzung" + }, + "mostActiveDay": { + "message": "Der aktivste Tag" + }, + "mostInactiveDay": { + "message": "Der inaktivste Tag" + }, + "todayInclude": { + "message": "Der heutige Tag ist in der Statistik enthalten. Aus der Statistik ausschließen." + }, + "todayEcclude": { + "message": "Der heutige Tag ist aus der Statistik ausgeschlossen. In die Statistik einbeziehen." + }, + "averageTimeByDays": { + "message": "Durchschnittliche Zeit für ausgewählte Tage" + }, + "exportToCsv": { + "message": "Als CSV exportieren" + }, + "week": { + "message": "Diese Woche" + }, + "month": { + "message": "Diesen Monat" + }, + "lastMonth": { + "message": "Letzter Monat" + }, + "generalSettings": { + "message": "Einstellungen" + }, + "whiteListSettings": { + "message": "Weiße Liste" + }, + "limitsSettings": { + "message": "Beschränkungen" + }, + "notificationsSettings": { + "message": "Benachrichtigungen" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro Einstellungen" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Die Pomodoro-Methode ist eine Zeitmanagementtechnik, die auf dem Wechsel von konzentrierten Arbeits- und Ruhephasen basiert. Bei der klassischen Pomodoro-Methode dauert die Arbeitsphase 25 Minuten und die Ruhephase 5 Minuten." + }, + "pomodoroExplanationIcon": { + "message": "Wenn der Pomodoro-Modus aktiviert ist und der Betriebsmodus aktiv ist, sehen Sie dieses Symbol", + "description": "Während der Ruhezeiten sehen Sie dieses Erweiterungssymbol" + }, + "pomodoroExplanationTime": { + "message": "Während des Pomodoro-Modus berücksichtigt die Erweiterung weiterhin die Zeit, die Sie auf den Seiten verbracht haben, alle Grenzen und Benachrichtigungen funktionieren." + }, + "pomodoroExplanationStop": { + "message": "Nach dem Drücken von 'Stop' werden die Betriebs- und Ruhezeiten auf Null zurückgesetzt." + }, + "pomodoroWork": { + "message": "Zeitraum der Arbeit" + }, + "pomodoroRest": { + "message": "Ruhezeit" + }, + "pomodoroFrequency": { + "message": "Anzahl der Wiederholungen" + }, + "start": { + "message": "Starten Sie" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Der Pomodoro-Modus ist aktiviert" + }, + "pomodoroSoundAfter": { + "message": "Ton nach vollständiger Periode" + }, + "clickToPreview": { + "message": "Zum Anhören klicken" + }, + "sound": { + "message": "Ton" + }, + "aboutSettings": { + "message": "Über die Erweiterung" + }, + "viewTimeInBadge": { + "message": "Zeitindikator anzeigen", + "description": "Die aktuellen Informationen zur \"verbrauchten Zeit\" im Kurzformat anzeigen" + }, + "deferringDescription": { + "message": "Die Sperre kann nur einmal pro Tag um 5 Minuten verschoben werden" + }, + "allowDeferringBlock": { + "message": "Verzögerung der Sperre um 5 Minuten zulassen", + "description": "Nachdem die Site gesperrt wurde, können Sie die Sperrung einmal täglich um 5 Minuten verschieben" + }, + "intervalInactivity": { + "message": "Zeiterfassung stoppen, bei Inaktivität für:", + "description": "Betrifft alle Aktionen mit der Maus oder der Tastatur" + }, + "exportToCsvSetting": { + "message": "Ihre Webaktivitätsdaten als CSV-Datei exportieren", + "description": "Ihre Webaktivitäten für einen beliebigen Zeitraum exportieren" + }, + "sec": { + "message": "Sekunden" + }, + "min": { + "message": "Minute" + }, + "2min": { + "message": "Minuten" + }, + "mins": { + "message": "Minuten" + }, + "whiteList": { + "message": "Aktivität und Zeit für diese Websites werden nicht erfasst." + }, + "addWebsite": { + "message": "Website hinzufügen" + }, + "enterWebsite": { + "message": "Namen der Website eingeben..." + }, + "enterNotification": { + "message": "Text für die Benachrichtigung eingeben..." + }, + "limits": { + "message": "Tägliche Zugriffsbeschränkungen für Websites", + "description": "Legen Sie die maximale Zeit fest, die pro Tag für den Besuch der Website zulässig ist. Nach dieser Zeit wird die Website gesperrt." + }, + "limitsTip": { + "message": "Setzen Sie die Blockierungszeit auf 0 Stunden 0 Minuten, um die Website sofort zu blockieren." + }, + "save": { + "message": "Speichern" + }, + "showDailyNotification": { + "message": "Tägliche Zusammenfassung als Benachrichtigung", + "description": "Am Ende jedes Tages erhalten Sie eine Benachrichtigung mit einer Zusammenfassung Ihrer täglichen Nutzung." + }, + "notificationTime": { + "message": "Benachrichtigungen für Websites", + "description": "Jedes Mal eine Benachrichtigung anzeigen, wenn Sie den angegebenen Zeitraum auf einer Website verbringen." + }, + "notificationMessage": { + "message": "Benachrichtigungstext", + "description": "Dieser Text wird in der Benachrichtigung für Websites angezeigt" + }, + "notificationTimeSetting": { + "message": "Tägliche Zusammenfassung um folgende Uhrzeit anzeigen:" + }, + "github": { + "message": "Feedback zur Erweiterung geben oder ein Problem melden: " + }, + "question": { + "message": "Eine Frage stellen oder Verbesserungen vorschlagen: " + }, + "supportForm": { + "message": "Unterstützungsformular" + }, + "doYouEnjoy": { + "message": "Gefällt Ihnen diese Erweiterung?" + }, + "review": { + "message": "Schreiben Sie eine Bewertung!" + }, + "block": { + "message": "Sie haben Ihr tägliches Nutzungslimit erreicht für " + }, + "5mins": { + "message": "+ 5 Minuten" + }, + "todayUsageTime": { + "message": "Bisherige Gesamtnutzungszeit " + }, + "comparedToYesterday": { + "message": " im Vergleich zu gestern " + }, + "mostVisited": { + "message": "Die meistbesuchte Website " + }, + "dashboard": { + "message": "Übersicht" + }, + "timeChartDescription": { + "message": "Dies ist eine stundenweise Zeitleiste für den Tag" + }, + "enjoyAndReview": { + "message": "Gefällt Ihnen diese Erweiterung?", + "description": "Web Activity Time Tracker bewerten" + }, + "removeAllData": { + "message": "Alle Daten entfernen", + "description": "Alle Daten und Statistiken der besuchten Websites für immer löschen." + }, + "remove": { + "message": "Löschen" + }, + "removeAllDataConfirm": { + "message": "Sind Sie sicher, dass Sie alle Daten löschen möchten?" + }, + "cancel": { + "message": "Abbrechen" + }, + "backupAndRestore": { + "message": "Sicherung und Wiederherstellen", + "description": "Sie können eine Sicherungskopie aller Daten für alle besuchten Websites herunterladen" + }, + "backup": { + "message": "Sicherung" + }, + "restore": { + "message": "Wiederherstellen" + }, + "welcome": { + "message": "Willkommen bei Web Activity Time Tracker", + "description": "Web Activity Time Tracker ist eine open-source, kostenlose und werbefreie Erweiterung, mit der Sie die Zeit, die Sie für das Durchsuchen von Websites aufgewendet haben, und die Anzahl der Besuche nachverfolgen können." + }, + "getStarted": { + "message": "Anleitung" + }, + "welcomeStart": { + "message": "Sie können die Erweiterung in nur 3 einfachen Schritten schnell verwenden" + }, + "pinIcon": { + "message": "Pin das Symbol" + }, + "pinIconPart1": { + "message": "Um diese Erweiterung bequemer zu verwenden, können Sie das Symbol an die Symbolleiste anheften. Klicken Sie auf das Symbol" + }, + "pinIconPart2": { + "message": "und klicken Sie dann auf das Pin-Symbol" + }, + "browse": { + "message": "Durchsuchen Sie alle Websites", + "description": "Wenn Sie eine Website besuchen, werden Sie sehen, dass die Uhrzeit auf dem Symbol angezeigt wird, genau wie hier" + }, + "seeData": { + "message": "Zeigen Sie Ihre Daten auf der Popup-Seite und im Dashboard an", + "description": "Klicken Sie auf das Erweiterungssymbol, um eine Popup-Seite zu öffnen, und Sie können die mit einem Kreisdiagramm gerenderten Daten für heute, für alle Zeiten oder für Tage lesen. In einem Popup-Fenster können Sie das Dashboard öffnen, und es zeigt Ihnen die heutige Zeit nach Stunden an. Und Sie können ein tägliches Zeitlimit für alle Websites festlegen, Benachrichtigungen für Websites festlegen oder Daten in CSV exportieren." + }, + "close": { + "message": "Schließen" + }, + "useExtension": { + "message": "Verwenden Sie die Erweiterung" + }, + "next": { + "message": "Weiter" + }, + "showChangelog": { + "message": "Änderungsliste anzeigen", + "description": "Zeigen Sie die Liste der Änderungen nach dem Aktualisieren der Erweiterung an" + }, + "byHours": { + "message": "Stundenweise" + }, + "intervals": { + "message": "Intervalle" + }, + "intervalsChart": { + "message": "Nur Zeitintervalle größer als", + "description": "werden angezeigt" + }, + "promoClearYoutube": { + "message": "Möchten Sie Kurzfilme, Kommentare, empfohlene Videos, Abonnements und andere YouTube-Ablenkungen blockieren? Wir haben eine weitere Erweiterung erstellt, mit der Sie YouTube ohne Ablenkung ansehen können.", + "description": "Versuchen Clean YouTube" + }, + "completelyBlocked": { + "message": "Vollständig blockiert", + "description": "Vollständig blockieren" + }, + "tryMyOtherApps": { + "message": "Probieren Sie meine anderen Apps aus" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome-Erweiterung, die YouTube-Shorts, empfohlene Videos, Kommentare, Feeds, Homepage-Empfehlungen und andere Ablenkungen ausblenden kann. Sieh dir YouTube ohne Ablenkungen an." + }, + "darkTheme": { + "message": "Dunkles Thema" + }, + "cleanYoutube_promo": { + "message": "Probieren Sie unsere neue Erweiterung Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Möchten Sie Kurzfilme, empfohlene Videos und Kommentare auf YouTube ausblenden?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube ist ein YouTube™-Inhaltsblocker." + }, + "cleanYoutube_features": { + "message": "Unsere Funktionen:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - Nur Videoplayer auf der Seite anzeigen" + }, + "cleanYoutube_features2": { + "message": "Kurze Videos, Kommentare und verwandte Videos ausblenden. 15+ Optionen." + }, + "cleanYoutube_features3": { + "message": "AutoPlay deaktivieren" + }, + "cleanYoutube_features4": { + "message": "Endscreen-Karten deaktivieren" + }, + "cleanYoutube_features5": { + "message": "Schwarz/Weiß-Modus" + }, + "try": { + "message": "Testen Sie" + }, + "donate":{ + "message": "Spende" + }, + "enjoy":{ + "message": "Haben Sie Spaß an Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker ist eine kostenlose Erweiterung. Sie können mich für die weitere Entwicklung mit Kryptowährung unterstützen." + }, + "thanks":{ + "message": "Vielen Dank dafür! 🙏" + }, + "coin":{ + "message": "Münze" + }, + "chain":{ + "message": "Kette" + }, + "address":{ + "message": "Adresse" + } +} \ No newline at end of file diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json new file mode 100644 index 0000000..216b4c1 --- /dev/null +++ b/src/_locales/en/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Block Websites, Pomodoro & Web Analytics" + }, + "extDescription": { + "message": "Track time of your web activity, limit and block distracting websites. Monitor your web usage." + }, + "settings": { + "message": "Settings" + }, + "today": { + "message": "Today" + }, + "allTime": { + "message": "Total time" + }, + "byDays": { + "message": "Daily" + }, + "noData": { + "message": "No data" + }, + "noDataForPeriod": { + "message": "No data for the selected period" + }, + "showAll": { + "message": "Show all the websites" + }, + "sortBy": { + "message": "Sorting by" + }, + "usageTime": { + "message": "Usage Time" + }, + "session": { + "message": "session" + }, + "someSession": { + "message": "sessions" + }, + "sessions": { + "message": "Sessions" + }, + "days": { + "message": "days" + }, + "aggregate": { + "message": "Aggregate data since" + }, + "websites": { + "message": "websites" + }, + "cannotOpenFile": { + "message": "You cannot open a local file due to security protocol" + }, + "document": { + "message": "Document" + }, + "limit": { + "message": "Limit" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "The first active day" + }, + "numberOfActiveDays": { + "message": "Number of active days" + }, + "totalNumberOfDays": { + "message": "Total number of days" + }, + "todayTime": { + "message": "All the time today" + }, + "averageTime": { + "message": "Average time for active days" + }, + "averageDailyUsage": { + "message": "Average daily usage" + }, + "mostActiveDay": { + "message": "The most active day" + }, + "mostInactiveDay": { + "message": "The most inactive day" + }, + "todayInclude": { + "message": "Today is included in the statistics. Click to exclude." + }, + "todayEcclude": { + "message": "Today is excluded from the statistics. Click to include." + }, + "averageTimeByDays": { + "message": "Average time on selected days" + }, + "exportToCsv": { + "message": "Export to CSV" + }, + "week": { + "message": "This week" + }, + "month": { + "message": "This month" + }, + "lastMonth": { + "message": "Last month" + }, + "generalSettings": { + "message": "Settings" + }, + "whiteListSettings": { + "message": "Whitelist" + }, + "limitsSettings": { + "message": "Limits" + }, + "notificationsSettings": { + "message": "Notifications" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro Settings" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "The Pomodoro method is a time management technique based on alternating periods of focused work and rest. According to the classics of the Pomodoro method, the work period lasts 25 minutes, the rest period is 5 minutes." + }, + "pomodoroExplanationIcon": { + "message": "When Pomodoro mode is on and operation mode is active, you will see this icon", + "description": "During rest periods, you will see this extension icon" + }, + "pomodoroExplanationTime": { + "message": "During Pomodoro mode, the extension continues to take into account the time you spent on the sites, all limits and notifications work." + }, + "pomodoroExplanationStop": { + "message": "After clicking 'Stop', work and rest time is reset to zero." + }, + "pomodoroWork": { + "message": "Period of work" + }, + "pomodoroRest": { + "message": "Period of rest" + }, + "pomodoroFrequency": { + "message": "Number of repetitions" + }, + "start": { + "message": "Run" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Pomodoro Mode is enabled" + }, + "pomodoroSoundAfter": { + "message": "Sound after complete period" + }, + "clickToPreview": { + "message": "Click to listen" + }, + "sound": { + "message": "Sound" + }, + "aboutSettings": { + "message": "About" + }, + "viewTimeInBadge": { + "message": "Display time tracker in icon", + "description": "You are able to see current 'spent time' information in short format on the extension icon" + }, + "deferringDescription": { + "message": "You can postpone the blocking for 5 minutes only once during the day" + }, + "allowDeferringBlock": { + "message": "Allow deferring block for 5 minutes", + "description": "After the site is blocked, you can postpone the blocking for 5 minutes during the day only once" + }, + "intervalInactivity": { + "message": "Stop the tracker if there is no action for", + "description": "These are any actions with the mouse or keyboard" + }, + "exportToCsvSetting": { + "message": "Exporting your web activity data to CSV", + "description": "You can export your web activity for any date range" + }, + "sec": { + "message": "seconds" + }, + "min": { + "message": "minute" + }, + "2min": { + "message": "minutes" + }, + "mins": { + "message": "minutes" + }, + "whiteList": { + "message": "Activity and spent time for these websites will not be tracked" + }, + "addWebsite": { + "message": "Add Website" + }, + "enterWebsite": { + "message": "Enter website name..." + }, + "enterNotification": { + "message": "Enter notification message..." + }, + "limits": { + "message": "Daily access restrictions for the websites", + "description": "Set the maximum time allowed to visit the website per day. After this time, the site will be blocked." + }, + "limitsTip": { + "message": "If you set the blocking time to 0 hours 0 minutes, the website will be blocked immediately" + }, + "save": { + "message": "Save" + }, + "showDailyNotification": { + "message": "Daily Summary Notifications", + "description": "At the end of each day, you will receive a notification with a summary of your daily usage" + }, + "notificationTime": { + "message": "Notifications for websites", + "description": "Show notifications every time you spend a selected period of time on the website" + }, + "notificationMessage": { + "message": "Notification message", + "description": "You will see this message in notification for websites every time" + }, + "notificationTimeSetting": { + "message": "Notification time with summary information about your daily usage" + }, + "github": { + "message": "Leave your feedback or report an issue on " + }, + "question": { + "message": "You can also ask questions and leave your suggestions" + }, + "supportForm": { + "message": "support form" + }, + "doYouEnjoy": { + "message": "Do you enjoy Web Activity Time Tracker?" + }, + "review": { + "message": "Leave a review!" + }, + "promoClearYoutube": { + "message": "Would you like to block shorts, comments, recommended videos, subscriptions, and other YouTube distractions? We've created another extension that will help you watch YouTube without distractions.", + "description": "Try Clean Youtube" + }, + "block": { + "message": "You've reached your limit for today on " + }, + "5mins": { + "message": "+ 5 minutes" + }, + "todayUsageTime": { + "message": "Total usage time for today " + }, + "comparedToYesterday": { + "message": " compared to yesterday " + }, + "mostVisited": { + "message": "Most visited website " + }, + "dashboard": { + "message": "Dashboard" + }, + "timeChartDescription": { + "message": "This is a chart of time during the day by the hour" + }, + "enjoyAndReview": { + "message": "Enjoying the extension?", + "description": "Rate Web Activity Time Tracker" + }, + "removeAllData": { + "message": "Remove all data", + "description": "You can delete all data and statistics of visited websites for all time" + }, + "remove": { + "message": "Remove" + }, + "removeAllDataConfirm": { + "message": "Are you sure you want to delete all data?" + }, + "cancel": { + "message": "Cancel" + }, + "backupAndRestore": { + "message": "Backup and restore", + "description": "You can download a backup copy of all data for all visited sites" + }, + "backup": { + "message": "Backup" + }, + "restore": { + "message": "Restore" + }, + "welcome": { + "message": "Welcome to Web Activity Time Tracker", + "description": "Web Activity Time Tracker is open-source, free and no ads extension, which can help you track the time you spent on browsing websites and the count of visit." + }, + "getStarted": { + "message": "Get started" + }, + "welcomeStart": { + "message": "You can quickly start using the extension in just 3 easy steps" + }, + "pinIcon": { + "message": "Pin the icon" + }, + "pinIconPart1": { + "message": "To use this extension more conveniently, you can pin the icon to toolbar. Click the icon" + }, + "pinIconPart2": { + "message": "and then click the pin icon" + }, + "browse": { + "message": "Browse any websites", + "description": "When you visit any website, you will see that the time is displayed on the icon, just like here" + }, + "seeData": { + "message": "View your data on the popup page and on the dashboard", + "description": "Click on the extension icon to open a popup page and you will be able to read the data visualized using a pie chart, for today, for all time or by day. In the popup window, you can open the dashboard and it will show you today's time by the clock. And you can set a daily time limit for any websites, notifications for websites, or export data to CSV." + }, + "close": { + "message": "Close" + }, + "useExtension": { + "message": "Use the extension" + }, + "next": { + "message": "Next" + }, + "showChangelog": { + "message": "Show changelog", + "description": "Show the list of changes after updating extension" + }, + "byHours": { + "message": "Hourly" + }, + "intervals": { + "message": "Intervals" + }, + "intervalsChart": { + "message": "Only time intervals greater than", + "description": "are shown" + }, + "completelyBlocked": { + "message": "Completely Blocked", + "description": "Completely Block" + }, + "tryMyOtherApps": { + "message": "Try my other apps" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome extension that can hide YouTube shorts, recomended videos, comments, feed, homepage recommendations and other distractions. Watch YouTube free of distractions." + }, + "darkTheme": { + "message": "Dark theme" + }, + "cleanYoutube_promo": { + "message": "Try our new extension Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Would you like to hide shorts, recommended videos, comments on YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube is a YouTube™ content blocker." + }, + "cleanYoutube_features": { + "message": "Our features:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - Show only Video Player on Page" + }, + "cleanYoutube_features2": { + "message": "Hide Shorts, Comments, Related Videos. 15+ options." + }, + "cleanYoutube_features3": { + "message": "Disable AutoPlay" + }, + "cleanYoutube_features4": { + "message": "Disable End Screen Cards" + }, + "cleanYoutube_features5": { + "message": "Black and White Mode" + }, + "try": { + "message": "Try" + }, + "donate": { + "message": "Donate" + }, + "enjoy":{ + "message": "Do you enjoy Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker is free extension. You can support me for the further development with cryptocurrency." + }, + "thanks":{ + "message": "Thank you! 🙏" + }, + "coin":{ + "message": "Coin" + }, + "chain":{ + "message": "Chain" + }, + "address":{ + "message": "Address" + } +} diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json new file mode 100644 index 0000000..c607eb2 --- /dev/null +++ b/src/_locales/es/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Sitios bloqueados, Pomodoro y análisis web" + }, + "extDescription": { + "message": "Controla el tiempo de tu actividad web, limita y bloquea los sitios web que te distraen. Monitoriza tu uso de la web." + }, + "settings": { + "message": "Ajustes" + }, + "today": { + "message": "Hoy" + }, + "allTime": { + "message": "Tiempo total" + }, + "byDays": { + "message": "Diario" + }, + "noData": { + "message": "Sin datos" + }, + "noDataForPeriod": { + "message": "No hay datos para el periodo seleccionado" + }, + "showAll": { + "message": "Mostrar todos los sitios web" + }, + "sortBy": { + "message": "Clasificación por" + }, + "usageTime": { + "message": "Tiempo de uso" + }, + "session": { + "message": "sesión" + }, + "someSession": { + "message": "sesiones" + }, + "sessions": { + "message": "Sesiones" + }, + "days": { + "message": "días" + }, + "aggregate": { + "message": "Datos agregados desde" + }, + "websites": { + "message": "sitios web" + }, + "cannotOpenFile": { + "message": "No se puede abrir un archivo local debido al protocolo de seguridad" + }, + "document": { + "message": "Documento" + }, + "limit": { + "message": "Límite" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "El primer día activo" + }, + "numberOfActiveDays": { + "message": "Número de días activos" + }, + "totalNumberOfDays": { + "message": "Número total de días" + }, + "todayTime": { + "message": "Todo el tiempo hoy" + }, + "averageTime": { + "message": "Tiempo medio de los días activos" + }, + "averageDailyUsage": { + "message": "Uso medio diario" + }, + "mostActiveDay": { + "message": "El día más activo" + }, + "mostInactiveDay": { + "message": "El día más inactivo" + }, + "todayInclude": { + "message": "Hoy está incluido en las estadísticas. Haga clic para excluir." + }, + "todayEcclude": { + "message": "El día de hoy está excluido de las estadísticas. Haga clic para incluir." + }, + "averageTimeByDays": { + "message": "Tiempo medio en los días seleccionados" + }, + "exportToCsv": { + "message": "Exportar a CSV" + }, + "week": { + "message": "Esta semana" + }, + "month": { + "message": "Este mes" + }, + "lastMonth": { + "message": "El mes pasado" + }, + "generalSettings": { + "message": "Ajustes" + }, + "whiteListSettings": { + "message": "ListaBlanca" + }, + "limitsSettings": { + "message": "Límites" + }, + "notificationsSettings": { + "message": "Notificaciones" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Ajustes Pomodoro" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "El método Pomodoro es una técnica de gestión del tiempo basada en la alternancia de periodos de trabajo concentrado y de descanso. Según los clásicos del método Pomodoro, el periodo de trabajo dura 25 minutos, el de descanso 5 minutos." + }, + "pomodoroExplanationIcon": { + "message": "Cuando el modo Pomodoro está activado y el modo de funcionamiento está activo, verá este icono", + "description": "Durante los periodos de descanso, verá este icono de extensión" + }, + "pomodoroExplanationTime": { + "message": "Durante el modo Pomodoro, la extensión sigue teniendo en cuenta el tiempo que pasó en los sitios, todos los límites y las notificaciones de trabajo." + }, + "pomodoroExplanationStop": { + "message": "Tras pulsar 'Parar', el tiempo de trabajo y de descanso se pone a cero." + }, + "pomodoroWork": { + "message": "Período de trabajo" + }, + "pomodoroRest": { + "message": "Periodo de descanso" + }, + "pomodoroFrequency": { + "message": "Número de repeticiones" + }, + "start": { + "message": "Ejecutar" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Modo Pomodoro activado" + }, + "pomodoroSoundAfter": { + "message": "Sonido tras periodo completo" + }, + "clickToPreview": { + "message": "Haga clic para escuchar" + }, + "sound": { + "message": "Sonido" + }, + "aboutSettings": { + "message": "Acerca de" + }, + "viewTimeInBadge": { + "message": "Mostrar el cronómetro en un icono", + "description": "En el icono de extensión puede ver la información actual sobre el 'tiempo transcurrido' en formato abreviado" + }, + "deferringDescription": { + "message": "Puedes posponer el bloqueo durante 5 minutos sólo una vez al día" + }, + "allowDeferringBlock": { + "message": "Permitir el bloqueo diferido durante 5 minutos", + "description": "Una vez bloqueado el sitio, puede posponer el bloqueo durante 5 minutos a lo largo del día una sola vez" + }, + "intervalInactivity": { + "message": "Detener el rastreador si no hay ninguna acción para", + "description": "Se trata de cualquier acción con el ratón o el teclado" + }, + "exportToCsvSetting": { + "message": "Exportación de los datos de actividad web a CSV", + "description": "Puede exportar su actividad web para cualquier intervalo de fechas" + }, + "sec": { + "message": "segundos" + }, + "min": { + "message": "minuto" + }, + "2min": { + "message": "minutos" + }, + "mins": { + "message": "minutos" + }, + "whiteList": { + "message": "La actividad y el tiempo de permanencia en estos sitios web no se rastrearán." + }, + "addWebsite": { + "message": "Añadir sitio web" + }, + "enterWebsite": { + "message": "Introduzca el nombre del sitio web..." + }, + "enterNotification": { + "message": "Introducir mensaje de notificación..." + }, + "limits": { + "message": "Restricciones diarias de acceso a los sitios web", + "description": "Establezca el tiempo máximo permitido para visitar el sitio web al día. Transcurrido este tiempo, el sitio se bloqueará." + }, + "limitsTip": { + "message": "Si establece el tiempo de bloqueo en 0 horas 0 minutos, el sitio web se bloqueará inmediatamente" + }, + "save": { + "message": "Guardar" + }, + "showDailyNotification": { + "message": "Notificaciones diarias resumidas", + "description": "Al final de cada día, recibirás una notificación con un resumen de tu uso diario" + }, + "notificationTime": { + "message": "Notificaciones para sitios web", + "description": "Mostrar notificaciones cada vez que pase un periodo de tiempo seleccionado en el sitio web." + }, + "notificationMessage": { + "message": "Mensaje de notificación", + "description": "Verás este mensaje en la notificación de sitios web cada vez que" + }, + "notificationTimeSetting": { + "message": "Hora de notificación con información resumida sobre su uso diario" + }, + "github": { + "message": "Deje su opinión o informe de un problema en" + }, + "question": { + "message": "También puede hacer preguntas y dejar sus sugerencias" + }, + "supportForm": { + "message": "formulario de asistencia" + }, + "doYouEnjoy": { + "message": "¿Te gusta Web Activity Time Tracker?" + }, + "review": { + "message": "Deja tu opinión" + }, + "promoClearYoutube": { + "message": "¿Te gustaría bloquear los cortos, los comentarios, los vídeos recomendados, las suscripciones y otras distracciones de YouTube? Hemos creado otra extensión que te ayudará a ver YouTube sin distracciones.", + "description": "Prueba Clean YouTube" + }, + "block": { + "message": "Has alcanzado tu límite por hoy en" + }, + "5mins": { + "message": "+ 5 minutos" + }, + "todayUsageTime": { + "message": "Tiempo total de uso para hoy " + }, + "comparedToYesterday": { + "message": " en comparación con ayer " + }, + "mostVisited": { + "message": "Sitio web más visitado " + }, + "dashboard": { + "message": "Cuadro de mandos" + }, + "timeChartDescription": { + "message": "Este es un gráfico del tiempo durante el día por horas" + }, + "enjoyAndReview": { + "message": "¿Disfrutando de la ampliación?", + "description": "Valora Web Activity Time Tracker" + }, + "removeAllData": { + "message": "Eliminar todos los datos", + "description": "Puede borrar todos los datos y estadísticas de los sitios web visitados para siempre" + }, + "remove": { + "message": "Eliminar" + }, + "removeAllDataConfirm": { + "message": "¿Estás seguro de que quieres borrar todos los datos?" + }, + "cancel": { + "message": "Cancelar" + }, + "backupAndRestore": { + "message": "Copia de seguridad y restauración", + "description": "Puedes descargar una copia de seguridad de todos los datos de todos los sitios visitados" + }, + "backup": { + "message": "Copia de seguridad" + }, + "restore": { + "message": "Restaurar" + }, + "welcome": { + "message": "Bienvenido a Web Activity Time Tracker", + "description": "Web Activity Time Tracker es una extensión de código abierto, gratuita y sin publicidad, que puede ayudarte a controlar el tiempo que pasas navegando por páginas web y el recuento de visitas." + }, + "getStarted": { + "message": "Empezar" + }, + "welcomeStart": { + "message": "Puede empezar a utilizar rápidamente la extensión en sólo 3 sencillos pasos" + }, + "pinIcon": { + "message": "Anclar el icono" + }, + "pinIconPart1": { + "message": "Para utilizar esta extensión más cómodamente, puede fijar el icono a la barra de herramientas. Haga clic en el icono" + }, + "pinIconPart2": { + "message": "y, a continuación, haga clic en el icono de la chincheta" + }, + "browse": { + "message": "Navegar por cualquier sitio web", + "description": "Cuando visite cualquier sitio web, verá que la hora aparece en el icono, como aquí" + }, + "seeData": { + "message": "Visualiza tus datos en la página emergente y en el cuadro de mandos", + "description": "Haz clic en el icono de la extensión para abrir una página emergente y podrás leer los datos visualizados mediante un gráfico circular, para hoy, para todo el tiempo o por día. En la ventana emergente, puedes abrir el panel de control y te mostrará el tiempo de hoy según el reloj. Y puedes establecer un límite de tiempo diario para cualquier sitio web, notificaciones para sitios web o exportar los datos a CSV." + }, + "close": { + "message": "Cerrar" + }, + "useExtension": { + "message": "Utilizar la extensión" + }, + "next": { + "message": "Siguiente" + }, + "showChangelog": { + "message": "Mostrar el registro de cambios", + "description": "Mostrar la lista de cambios tras actualizar la extensión" + }, + "byHours": { + "message": "Por hora" + }, + "intervals": { + "message": "Intervalos" + }, + "intervalsChart": { + "message": "Sólo los intervalos de tiempo superiores a", + "description": "se muestran" + }, + "completelyBlocked": { + "message": "Completamente bloqueado", + "description": "Completamente bloqueado" + }, + "tryMyOtherApps": { + "message": "Pruebe mis otras aplicaciones" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Extensión de Chrome que puede ocultar los cortos de YouTube, los vídeos recomendados, los comentarios, el feed, las recomendaciones de la página de inicio y otras distracciones. Vea YouTube sin distracciones." + }, + "darkTheme": { + "message": "Tema oscuro" + }, + "cleanYoutube_promo": { + "message": "Prueba nuestra nueva extensión Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Te gustaría ocultar cortos, vídeos recomendados, comentarios en YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube es un bloqueador de contenido de YouTube™." + }, + "cleanYoutube_features": { + "message": "Nuestras características:" + }, + "cleanYoutube_features1": { + "message": "Modo Limpio - Muestra sólo el reproductor de vídeo en la página" + }, + "cleanYoutube_features2": { + "message": "Ocultar cortos, comentarios, vídeos relacionados. Más de 15 opciones." + }, + "cleanYoutube_features3": { + "message": "Desactivar reproducción automática" + }, + "cleanYoutube_features4": { + "message": "Desactivar tarjetas de fin de pantalla" + }, + "cleanYoutube_features5": { + "message": "Modo Blanco y Negro" + }, + "try": { + "message": "Pruebe" + }, + "donate":{ + "message": "Donación" + }, + "enjoy":{ + "message": "¿Te gusta Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker es una extensión gratuita. Usted me puede apoyar para el desarrollo futuro con cryptocurrency." + }, + "thanks":{ + "message": "Muchas gracias! 🙏" + }, + "coin":{ + "message": "Moneda" + }, + "chain":{ + "message": "Cadena" + }, + "address":{ + "message": "Dirección" + } +} diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json new file mode 100644 index 0000000..86f408f --- /dev/null +++ b/src/_locales/ja/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "ウェブ活動時間トラッカー - ブロックウェブサイト,ポモドーロ&ウ:ェブ分析" + }, + "extDescription": { + "message": "あなたのウェブ活動の時間を追跡し,制限し,気が散るウェブサイトをブロックします。あなたのウェブ利用を監視します。" + }, + "settings": { + "message": "設定" + }, + "today": { + "message": "今日" + }, + "allTime": { + "message": "合計時間" + }, + "byDays": { + "message": "毎日" + }, + "noData": { + "message": "データなし" + }, + "noDataForPeriod": { + "message": "選択された期間のデータがありません" + }, + "showAll": { + "message": "すべてのウェブサイトを表示" + }, + "sortBy": { + "message": "ソート順" + }, + "usageTime": { + "message": "使用時間" + }, + "session": { + "message": "セッション" + }, + "someSession": { + "message": "セッション" + }, + "sessions": { + "message": "セッション" + }, + "days": { + "message": "日数" + }, + "aggregate": { + "message": "からの集計データ" + }, + "websites": { + "message": "ウェブサイト" + }, + "cannotOpenFile": { + "message": "セキュリティ・プロトコルのため,ローカル・ファイルを開けません。" + }, + "docmument": { + "message": "ドキュメント" + }, + "limit": { + "message": "リミット" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "最初の活動日" + }, + "numberOfActiveDays": { + "message": "アクティブな日数" + }, + "totalNumberOfDays": { + "message": "合計日数" + }, + "todayTime": { + "message": "今日のすべての時間" + }, + "averageTime": { + "message": "アクティブな日の平均時間" + }, + "averageDailyUsage": { + "message": "1日の平均使用量" + }, + "mostActiveDay": { + "message": "最もアクティブな日" + }, + "mostInactiveDay": { + "message": "最もアクティブでない日" + }, + "todayInclude": { + "message": "今日は統計に含まれます。除外するにはクリックしてください。" + }, + "todayEcclude": { + "message": "今日は統計から除外されています。クリックすると含まれます。" + }, + "averageTimeByDays": { + "message": "選択した日の平均時間" + }, + "exportToCsv": { + "message": "CSVにエクスポート" + }, + "week": { + "message": "今週" + }, + "month": { + "message": "今月" + }, + "lastMonth": { + "message": "今月" + }, + "generalSettings": { + "message": "設定" + }, + "whiteListSettings": { + "message": "ホワイトリスト" + }, + "limitsSettings": { + "message": "制限" + }, + "notificationsSettings": { + "message": "通知" + }, + "pomodoroMode": { + "message": "ポモドーロ" + }, + "pomodoroSettings": { + "message": "ポモドーロ設定" + }, + "pomodoro": { + "message": "ポモドーロ", + "description": "ポモドーロ法は,集中した作業と休息を交互に繰り返すことに基づく時間管理手法である。ポモドーロ法の古典によれば,作業時間は25分,休憩時間は5分である。" + }, + "pomodoroExplanationIcon": { + "message": "ポモドーロモードがオンで,操作モードがアクティブなとき,このアイコンを見ることができます,", + "description": "休憩時間中は,この拡張アイコンが表示されます" + }, + "pomodoroExplanationTime": { + "message": "ポモドーロモードの間,エクステンションはサイトに費やした時間を考慮し続け,すべての制限と通知作業を行います。" + }, + "pomodoroExplanationStop": { + "message": "停止」をクリックすると、作業時間と休憩時間はゼロにリセットされる。" + }, + "pomodoroWork": { + "message": "仕事の期間" + }, + "pomodoroRest": { + "message": "休息期間" + }, + "pomodoroFrequency": { + "message": "繰り返し回数" + }, + "start": { + "message": "実行" + }, + "stop": { + "message": "停止" + }, + "pomodoroIsEnabled": { + "message": "ポモドーロモードは有効です" + }, + "pomodoroSoundAfter": { + "message": "期間終了後の音" + }, + "clickToPreview": { + "message": "クリックで試聴" + }, + "sound": { + "message": "サウンド" + }, + "aboutSettings": { + "message": "について" + }, + "viewTimeInBadge": { + "message": "アイコンにタイムトラッカーを表示する,", + "description": "拡張機能アイコンをクリックすると、現在の「滞在時間」情報を短いフォーマットで見ることができます。" + }, + "deferringDescription": { + "message": "一日のうち一度だけ,5分間だけブロック時間を延期することができます。" + }, + "allowDeferringBlock": { + "message": "5分間のブロック延期を許可", + "description": "サイトがブロックされた後,一度だけ日中5分間ブロックを延期できる" + }, + "intervalInactivity": { + "message": "のアクションがない場合,トラッカーを停止します,", + "description": "マウスやキーボードによるアクション" + }, + "exportToCsvSetting": { + "message": "WebアクティビティデータをCSVにエクスポートします,", + "説明": "任意の日付範囲のウェブ活動をエクスポートできます。" + }, + "sec": { + "message": "秒" + }, + "min": { + "message": "分" + }, + "2min": { + "message": "分" + }, + "mins": { + "message": "分" + }, + "whiteList": { + "message": "これらのウェブサイトのアクティビティと滞在時間は追跡されません。" + }, + "addWebsite": { + "message": "ウェブサイトを追加" + }, + "enterWebsite": { + "message": "ウェブサイト名を入力してください..." + }, + "enterNotification": { + "message": "通知messageを入力..." + }, + "limits": { + "message": "ウェブサイトの毎日のアクセス制限", + "description": "1日にウェブサイトにアクセスできる最大時間を設定します。この時間を過ぎると,サイトはブロックされます。" + }, + "limitsTip": { + "message": "ブロック時間を0時間0分に設定した場合,ウェブサイトは直ちにブロックされます。" + }, + "save": { + "message": "保存" + }, + "showDailyNotification": { + "message": "デイリーサマリー通知", + "description": "一日の終わりに,一日の使用量を要約した通知を受け取ります" + }, + "notificationTime": { + "message": "ウェブサイトの通知", + "description": "選択した時間をウェブサイトに費やすたびに通知を表示する" + }, + "notificationMessage": { + "message": "通知メッセージ", + "description": "ウェブサイトの通知で毎回このmessageが表示されます" + }, + "notificationTimeSetting": { + "message": "1日の利用状況についてのサマリー情報を通知時間に表示" + }, + "github": { + "message": "ご意見をお寄せください。" + }, + "question": { + "message": "質問や提案を残すこともできます。" + }, + "supportForm": { + "message": "サポートフォーム" + }, + "doYouEnjoy": { + "message": "Web Activity Time Trackerを楽しんでいますか?" + }, + "review": { + "message": "レビューを書く" + }, + "promoClearYoutube": { + "message": "ショートフィルム,コメント,おすすめ動画,購読,その他のYouTubeの邪魔なものをブロックしたいですか?気晴らしにYouTubeを見るのに役立つ別の拡張機能を作りました。", + "description": "クリーンユーチューブを試す" + }, + "block": { + "message": "で今日の制限に達した。" + }, + "5mins": { + "message": "+5分" + }, + "todayUsageTime": { + "message": "今日の総使用時間" + }, + "comparedToYesterday": { + "message": " 昨日との比較 " + }, + "mostVisited": { + "message": "最も訪問されたウェブサイト" + }, + "dashboard": { + "message": "ダッシュボード" + }, + "timeChartDescription": { + "message": "日中の時間を時間単位で表したチャートです" + }, + "enjoyAndReview": { + "message": "エクステンションを楽しんでいますか?", + "description": "ウェブ活動時間トラッカーを評価する" + }, + "removeAllData": { + "message": "すべてのデータを削除する,", + "description": "訪問したウェブサイトのすべてのデータと統計情報を削除することができます。" + }, + "remove": { + "message": "削除" + }, + "removeAllDataConfirm": { + "message": "本当に全データを削除しますか?" + }, + "cancel": { + "message": "キャンセル" + }, + "backupAndRestore": { + "message": "バックアップとリストア", + "説明": "訪問したすべてのサイトのすべてのデータのバックアップコピーをダウンロードすることができます。" + }, + "backup": { + "message": "バックアップ" + }, + "restore": { + "message": "リストア" + }, + "welcome": { + "message": "Web Activity Time Trackerへようこそ", + "description": "Web Activity Time Trackerは、オープンソース、無料広告なしの拡張機能で、ウェブサイトの閲覧に費やした時間や訪問回数を記録することができます。" + }, + "getStarted": { + "message": "スタート" + }, + "welcomeStart": { + "message": "簡単な3ステップで、すぐに拡張機能を使い始めることができます。" + }, + "pinIcon": { + "message": "アイコンをピン留めする" + }, + "pinIconPart1": { + "message": "この拡張機能をより便利に使用するには、アイコンをツールバーに固定します。アイコンをクリック" + }, + "pinIconPart2": { + "message": "をクリックし、ピンのアイコンをクリックします。" + }, + "browse": { + "message": "任意のウェブサイトをブラウズする,", + "description": "ウェブサイトにアクセスすると,アイコンに時刻が表示されます。" + }, + "seeData": { + "message": "ポップアップページとダッシュボードでデータを見る", + "description": "拡張機能のアイコンをクリックすると,ポップアップページが開き,円グラフを使って視覚化されたデータを,今日,すべての時間,または日ごとに読むことができます。ポップアップウィンドウでは,ダッシュボードを開くことができ,時計で今日の時間を表示します。また,任意のウェブサイトに対して1日の時間制限を設定したり,ウェブサイトに対する通知を設定したり,データをCSVにエクスポートしたりすることができます。" + }, + "close": { + "message": "閉じる" + }, + "useExtension": { + "message": "拡張機能を使用する" + }, + "next": { + "message": "次" + }, + "showChangelog": { + "message": "変更履歴を表示", + "description": "エクステンションの更新後に変更点の一覧を表示する" + }, + "byHours": { + "message": "時間単位" + }, + "interval": { + "message": "間隔" + }, + "intervalsChart": { + "message": "より大きい時間間隔のみ", + "description": "が表示される。" + }, + "completelyBlocked": { + "message": "完全にブロックされました,", + "description": "完全にブロック" + }, + "tryMyOtherApps": { + "message": "他のアプリを試す" + }, + "clearYoutube": { + "message": "YouTubeをクリーン", + "description": "YouTubeのショートムービー,おすすめビデオ,コメント,フィード,ホームページのおすすめやその他の邪魔なものを隠すことができるChrome拡張機能です。気晴らしにYouTubeを見よう。" + }, + "darkTheme": { + "message": "ダークテーマ" + }, + "cleanYoutube_promo": { + "message": "新しい拡張機能Clean Youtubeをお試しください" + }, + "cleanYoutube_description": { + "message": "YouTubeのショートフィルム,おすすめ動画,コメントを非表示にしますか?" + }, + "cleanYoutube_description2": { + "message": "クリーンYoutubeはYouTube™コンテンツブロッカーです。" + }, + "cleanYoutube_features": { + "message": "私たちの機能:" + }, + "cleanYoutube_features1": { + "message": "クリーンモード - ページに動画プレーヤーのみを表示" + }, + "cleanYoutube_features2": { + "message": "ショートカット、コメント、関連ビデオを隠す。15以上のオプション" + }, + "cleanYoutube_features3": { + "message": "自動再生を無効にする" + }, + "cleanYoutube_features4": { + "message": "終了画面カードを無効にする" + }, + "cleanYoutube_features5": { + "message": "白黒モード" + }, + "try": { + "message": "トライ" + }, + "donate": { + "message": "寄付する" + }, + "enjoy":{ + "message": "Web Activity Time Trackerを楽しんでいますか?" + }, + "canDonate":{ + "message": "Web Activity Time Trackerは無料の拡張機能です。さらなる開発のために、暗号通貨でご支援ください。" + }, + "thanks":{ + "message": "ありがとうございます! 🙏" + }, + "coin":{ + "message": "コイン" + }, + "chain":{ + "message": "チェーン" + }, + "address":{ + "message": "アドレス" + } +} diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json new file mode 100644 index 0000000..29768c3 --- /dev/null +++ b/src/_locales/ru/messages.json @@ -0,0 +1,432 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Блокировка сайтов, Pomodoro и \u0412\u0435\u0431 аналитика" + }, + "extDescription": { + "message": "Отслеживайте время вашей веб-активности и блокируйте отвлекающие сайты. Следите за тем, сколько времени вы проводите на сайтах." + }, + "settings": { + "message": "Настройки" + }, + "today": { + "message": "Сегодня" + }, + "allTime": { + "message": "\u0417\u0430 все время" + }, + "byDays": { + "message": "По дням" + }, + "noData": { + "message": "Нет данных" + }, + "noDataForPeriod": { + "message": "Нет данных за выбранный период" + }, + "showAll": { + "message": "Показать все сайты" + }, + "sortBy": { + "message": "Сортировать по" + }, + "usageTime": { + "message": "Время использования" + }, + "session": { + "message": "сессия" + }, + "someSession": { + "message": "сессий" + }, + "sessions": { + "message": "Сессии" + }, + "days": { + "message": "дней" + }, + "aggregate": { + "message": "Данные \u0441 " + }, + "websites": { + "message": "сайтов" + }, + "cannotOpenFile": { + "message": "Вы не можете открыть локальный файл из-за правил безопасности" + }, + "document": { + "message": "Документ" + }, + "limit": { + "message": "Лимит" + }, + "d": { + "message": "д" + }, + "h": { + "message": "ч" + }, + "m": { + "message": "мин" + }, + "s": { + "message": "\u0441\u0435к" + }, + "firstActiveDay": { + "message": "Первый активный день" + }, + "numberOfActiveDays": { + "message": "\u0412\u0441\u0435\u0433\u043E активных дней" + }, + "totalNumberOfDays": { + "message": "\u0412\u0441\u0435\u0433\u043E дней" + }, + "todayTime": { + "message": "Общее время сегодня" + }, + "averageTime": { + "message": "Среднее время по активным дням" + }, + "averageDailyUsage": { + "message": "Среднее ежедневное использование" + }, + "mostActiveDay": { + "message": "Самый активный день" + }, + "mostInactiveDay": { + "message": "Самый неактивный день" + }, + "todayInclude": { + "message": "Сегодняшний день включен в статистику. Нажмите, если хотите исключить из статистики." + }, + "todayEcclude": { + "message": "Сегодняшний день исключен из статистику. Нажмите, если хотите включить в статистику." + }, + "averageTimeByDays": { + "message": "Среднее время по выбранным дням" + }, + "exportToCsv": { + "message": "Экспортировать в CSV" + }, + "week": { + "message": "Эта неделя" + }, + "month": { + "message": "Этот месяц" + }, + "lastMonth": { + "message": "Последний месяц" + }, + "generalSettings": { + "message": "Настройки" + }, + "whiteListSettings": { + "message": "Белый список" + }, + "limitsSettings": { + "message": "Лимиты" + }, + "notificationsSettings": { + "message": "Уведомления" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Настройки Pomodoro" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Метод Pomodoro — это техника тайм-менеджмента, завязанная на чередовании периодов сфокусированной работы и отдыха. По классике метода помодоро период работы длится 25 минут, период отдыха 5 минут." + }, + "pomodoroExplanationIcon": { + "message": "Когда режим Pomodoro включен и активен режим работы, то вы будете видеть эту иконку", + "description": "В периоды отдыха вы будете видеть эту иконку расширения" + }, + "pomodoroExplanationTime": { + "message": "Во время режима Pomodoro, расширение продолжает учитывать время, которые вы провели на сайтах,работают все лимиты и уведомления." + }, + "pomodoroExplanationStop": { + "message": "После нажатия 'Остановить', время работы и отдыха обнуляется." + }, + "pomodoroWork": { + "message": "Период работы" + }, + "pomodoroRest": { + "message": "Период отдыха" + }, + "pomodoroFrequency": { + "message": "Количество повторов" + }, + "start": { + "message": "Запустить" + }, + "stop": { + "message": "Остановить" + }, + "pomodoroIsEnabled": { + "message": "Режим Pomodoro включен" + }, + "pomodoroSoundAfter": { + "message": "Воспроизведение после завершения периода" + }, + "clickToPreview": { + "message": "Нажмите для прослушивания" + }, + "sound": { + "message": "Мелодия" + }, + "aboutSettings": { + "message": "\u041E программе" + }, + "viewTimeInBadge": { + "message": "Показывать индикатор времени", + "description": "Вы можете увидеть текущее затраченное время в сокращенном формате на значке расширения" + }, + "deferringDescription": { + "message": "Вы можете отложить блокировку на 5 минут только один раз в течение дня" + }, + "allowDeferringBlock": { + "message": "Разрешить отсрочку блокировки на 5 минут", + "description": "После того, как сайт будет заблокирован, вы можете один раз в течение дня отложить блокировку на 5 минут" + }, + "intervalInactivity": { + "message": "Остановить трекер, если нет никаких действий в течение:", + "description": "Это любые действия \u0441 помощью мыши или клавиатуры" + }, + "exportToCsvSetting": { + "message": "Экспорт данных вашей веб-активности в формат CSV", + "description": "Вы можете экспортировать свою веб-активность для любого диапазона дат" + }, + "sec": { + "message": "секунд" + }, + "min": { + "message": "минута" + }, + "2min": { + "message": "минуты" + }, + "mins": { + "message": "минут" + }, + "whiteList": { + "message": "Активность и время для этих сайтов отслеживаться не будут" + }, + "addWebsite": { + "message": "Добавить сайт" + }, + "enterWebsite": { + "message": "Введите сайт..." + }, + "enterNotification": { + "message": "Введите текст уведомления..." + }, + "limits": { + "message": "Ежедневные ограничения доступа к сайтам", + "description": "Установите максимальное время, разрешенное для посещения сайта в день. По истечении этого времени сайт будет заблокирован." + }, + "limitsTip": { + "message": "Если вы установите время блокировки на 0 часов 0 минут, сайт будет немедленно заблокирован" + }, + "save": { + "message": "Сохранить" + }, + "showDailyNotification": { + "message": "Ежедневные итоговые уведомления", + "description": "\u0412 конце каждого дня вы будете получать уведомление \u0441 краткой информацией \u043E вашем ежедневном использовании" + }, + "notificationTimeSetting": { + "message": "Время показа уведомления \u0441 краткой информацией \u043E вашем ежедневном использовании" + }, + "notificationTime": { + "message": "Уведомления для сайтов", + "description": "Показывать уведомления каждый раз, когда вы проводите указанный период времени на сайте" + }, + "notificationMessage": { + "message": "Текст уведомления", + "description": "Вы будете видеть это сообщение в уведомлении для сайтов" + }, + "github": { + "message": "Если \u0443 вас есть вопрос или вы хотели бы сообщить \u043E проблеме, вы можете сделать это на" + }, + "question": { + "message": "Также вы можете задать вопросы или оставить свои предложения " + }, + "supportForm": { + "message": "поддержка" + }, + "doYouEnjoy": { + "message": "Вам нравится Web Activity Time Tracker?" + }, + "review": { + "message": "Оставьте отзыв!" + }, + "block": { + "message": "Вы достигли лимита использования сегодня на " + }, + "5mins": { + "message": "+ 5 минут" + }, + "todayUsageTime": { + "message": "Общее время использования на сегодняшний день " + }, + "comparedToYesterday": { + "message": " по сравнению \u0441\u043e вчерашним днем " + }, + "mostVisited": { + "message": "Самый посещаемый сайт " + }, + "dashboard": { + "message": "Дашборд" + }, + "timeChartDescription": { + "message": "Это график времени в течение дня по часам" + }, + "enjoyAndReview": { + "message": "Вам нравится расширение?", + "description": "Оцените Web Activity Time Tracker" + }, + "promoClearYoutube": { + "message": "Хотели бы вы блокировать шортсы, комментарии, рекомендованные видео, подписки и другие отвлекающие элементы YouTube? Мы создали еще одно расширение, которое поможет вам смотреть YouTube без отвлекающих факторов.", + "description": "Попробовать Clean YouTube" + }, + "removeAllData": { + "message": "Удалить все данные", + "description": "Вы можете удалить все данные и статистику посещенных сайтов за все время" + }, + "remove": { + "message": "Удалить" + }, + "removeAllDataConfirm": { + "message": "Вы уверены, что хотите удалить все данные, включая статистику посещенных сайтов?" + }, + "cancel": { + "message": "Отмена" + }, + "backupAndRestore": { + "message": "Резервное копирование и восстановление", + "description": "Вы можете скачать резервную копию всех данных по всем посещенным сайтам" + }, + "backup": { + "message": "Скачать резервную копию" + }, + "restore": { + "message": "Восстановить из резервной копиии" + }, + "welcome": { + "message": "Добро пожаловать в Web Activity Time Tracker", + "description": "Web Activity Time Tracker это бесплатное, без рекламы и \u0441 открытым исходным кодом расширение, которое поможем вам отслеживать время, потраченное вами на просмотр веб-сайтов, и покажет количество посещений." + }, + "getStarted": { + "message": "Руководство" + }, + "welcomeStart": { + "message": "Вы можете быстро начать использовать расширение всего за 3 простых шага" + }, + "pinIcon": { + "message": "Закрепите значок" + }, + "pinIconPart1": { + "message": "Чтобы более удобно использовать это расширение, вы можете прикрепить значок к панели инструментов. Нажмите на значок" + }, + "pinIconPart2": { + "message": "и затем нажмите на значок закрепления" + }, + "browse": { + "message": "Просматривайте любые веб-сайты", + "description": "При посещении любого веб-сайта вы увидите, что время отображается на значке, точно так же, как здесь" + }, + "seeData": { + "message": "Просматривайте ваши данные на всплывающей странице и на панели мониторинга", + "description": "Нажмите на значок расширения, чтобы открыть всплывающую страницу, и вы сможете увидеть данные посещения сайтов за сегодня, за все время и по дням. Во всплывающем окне вы можете открыть панель мониторинга, и вы увидите сегодняшнее время по часам. Там же вы можете установить ежедневное ограничение по времени для любых веб-сайтов, уведомления для веб-сайтов или экспортировать данные в CSV." + }, + "close": { + "message": "Закрыть" + }, + "useExtension": { + "message": "Начать пользоваться" + }, + "next": { + "message": "Продолжить" + }, + "showChangelog": { + "message": "Показывать список изменений", + "description": "Показывать список изменений после обновления расширения" + }, + "byHours": { + "message": "По часам" + }, + "intervals": { + "message": "Интервалы", + "description": "Отображаются только временные интервалы, превышающие 5 секунд" + }, + "intervalsChart": { + "message": "Отображаются только временные интервалы, превышающие", + "description": "" + }, + "completelyBlocked": { + "message": "Полностью заблокирован", + "description": "Полностью заблокировать" + }, + "tryMyOtherApps": { + "message": "Попробуйте другие мои приложения" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Расширение для Chrome, которое может скрывать шортс YouTube, рекомендуемые видео, комментарии, ленту новостей, рекомендации по домашней странице и другие отвлекающие факторы. Смотрите YouTube без отвлекающих факторов." + }, + "darkTheme": { + "message": "Темная тема" + }, + "cleanYoutube_promo": { + "message": "Попробуйте наше новое расширение Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Хотите скрыть шортсы, рекомендуемые видео, комментарии на YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube - это блокировщик контента YouTube™." + }, + "cleanYoutube_features": { + "message": "Наши возможности:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - покажите только видеоплеер на странице" + }, + "cleanYoutube_features2": { + "message": "Скрыть шортсы, комментарии, связанные видео. 15+ опций." + }, + "cleanYoutube_features3": { + "message": "Отключить автовоспроизведение" + }, + "cleanYoutube_features4": { + "message": "Отключить карточки в конце видео" + }, + "cleanYoutube_features5": { + "message": "Черно-белый режим" + }, + "try": { + "message": "Попробовать" + }, + "donate":{ + "message": "Donate" + }, + "enjoy":{ + "message": "Нравится ли вам Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker - это бесплатное расширение. Вы можете поддержать меня для дальнейшего развития с помощью криптовалюты." + }, + "thanks":{ + "message": "Спасибо! 🙏" + }, + "coin":{ + "message": "Монета" + }, + "chain":{ + "message": "Цепочка" + }, + "address":{ + "message": "Адрес" + } +} diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json new file mode 100644 index 0000000..673e348 --- /dev/null +++ b/src/_locales/zh_CN/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - 封鎖網站、Pomodoro 與網頁分析" + }, + "extDescription": { + "message": "追踪和限制您的网站活动时间,并阻止访问网站。监控您的网站使用情况" + }, + "settings": { + "message": "设置" + }, + "today": { + "message": "今天" + }, + "allTime": { + "message": "总时间" + }, + "byDays": { + "message": "每天" + }, + "noData": { + "message": "无数据" + }, + "noDataForPeriod": { + "message": "所选时间段内无数据" + }, + "showAll": { + "message": "显示所有网站" + }, + "sortBy": { + "message": "排序" + }, + "usageTime": { + "message": "使用时间" + }, + "session": { + "message": "会话" + }, + "someSession": { + "message": "会话" + }, + "sessions": { + "message": "会话" + }, + "days": { + "message": "天" + }, + "aggregate": { + "message": "汇总数据自" + }, + "websites": { + "message": "网站" + }, + "cannotOpenFile": { + "message": "由于安全协议,您无法打开本地文件" + }, + "document": { + "message": "文件" + }, + "limit": { + "message": "限制" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "第一个活动日" + }, + "numberOfActiveDays": { + "message": "活动天数" + }, + "totalNumberOfDays": { + "message": "总天数" + }, + "todayTime": { + "message": "今天所有的时间" + }, + "averageTime": { + "message": "活动日的平均时间" + }, + "averageDailyUsage": { + "message": "平均每日使用量" + }, + "mostActiveDay": { + "message": "最活跃的一天" + }, + "mostInactiveDay": { + "message": "最不活跃的一天" + }, + "todayInclude": { + "message": "今天包含在统计数据中。点击以排除。" + }, + "todayEcclude": { + "message": "今天不包含在统计数据中。点击以包含。" + }, + "averageTimeByDays": { + "message": "所选日期的平均时间" + }, + "exportToCsv": { + "message": "导出 CSV" + }, + "week": { + "message": "本周" + }, + "month": { + "message": "本月" + }, + "lastMonth": { + "message": "上月" + }, + "generalSettings": { + "message": "设置" + }, + "whiteListSettings": { + "message": "白名单" + }, + "limitsSettings": { + "message": "限制" + }, + "notificationsSettings": { + "message": "通知" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro 设置" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Pomodoro 工作法是一种时间管理技术,以交替集中工作和休息为基础。根据经典的 Pomodoro 方法,工作时间为 25 分钟,休息时间为 5 分钟。" + }, + "pomodoroExplanationIcon": { + "message": "启用 Pomodoro 模式并激活操作模式后,您将看到以下图标", + "description": "在休息时间,您会看到这个扩展图标" + }, + "pomodoroExplanationTime": { + "message": "在 Pomodoro 模式下,扩展会继续考虑你在网站上花费的时间、所有限制和通知。" + }, + "pomodoroExplanationStop": { + "message": "按下 '停止' 键后,运行时间和休息时间将重置为零" + }, + "pomodoroWork": { + "message": "工作期限" + }, + "pomodoroRest": { + "message": "休息时间" + }, + "pomodoroFrequency": { + "message": "重复次数" + }, + "start": { + "message": "启动" + }, + "stop": { + "message": "停止" + }, + "pomodoroIsEnabled": { + "message": "番茄钟模式已启用" + }, + "pomodoroSoundAfter": { + "message": "完整时段后的声音" + }, + "clickToPreview": { + "message": "点击收听" + }, + "sound": { + "message": "声音" + }, + "aboutSettings": { + "message": "关于" + }, + "viewTimeInBadge": { + "message": "在图标中显示时间跟踪器", + "description": "您可以在扩展程序图标上以简短格式查看当前的“花费时间”信息。" + }, + "deferringDescription": { + "message": "您一天只能将拦截推迟 5 分钟一次。" + }, + "allowDeferringBlock": { + "message": "允许推迟拦截 5 分钟", + "description": "站点被拦截后,您一天中只能将拦截推迟 5 分钟一次。" + }, + "intervalInactivity": { + "message": "如果没有操作,则停止跟踪器:", + "description": "可以是使用鼠标或键盘进行的任何操作" + }, + "exportToCsvSetting": { + "message": "将您的网站活动数据导出为 CSV 格式", + "description": "您可以导出任何日期范围内的网站活动。" + }, + "sec": { + "message": "秒" + }, + "min": { + "message": "分钟" + }, + "2min": { + "message": "分钟" + }, + "mins": { + "message": "分钟" + }, + "whiteList": { + "message": "这些网站的活动和花费时间将不会被跟踪。" + }, + "addWebsite": { + "message": "添加网站" + }, + "enterWebsite": { + "message": "输入网站名称..." + }, + "enterNotification": { + "message": "输入通知消息..." + }, + "limits": { + "message": "网站的每日访问限制", + "description": "设置每天允许访问网站的最长时间。超过此时间后,该网站将被拦截。" + }, + "limitsTip": { + "message": "如果您将拦截时间设置为 0 小时 0 分钟,那么该网站将立即被拦截。" + }, + "save": { + "message": "保存" + }, + "showDailyNotification": { + "message": "每日摘要通知", + "description": "每天结束时,您将收到一条通知,其中包含您的每日使用情况摘要。" + }, + "notificationTime": { + "message": "网站通知", + "description": "每次在网站上花费特定时间时显示通知。" + }, + "notificationMessage": { + "message": "通知消息", + "description": "每次在网站通知中,您都会看到这条消息。" + }, + "notificationTimeSetting": { + "message": "包含有关您日常使用情况的摘要信息的通知时间:" + }, + "github": { + "message": "在以下位置留下您的反馈或报告问题:" + }, + "question": { + "message": "您还可以提问并留下您的建议。" + }, + "supportForm": { + "message": "支持表单" + }, + "doYouEnjoy": { + "message": "您喜欢 Web Activity Time Tracker 吗?" + }, + "review": { + "message": "留下评论吧!" + }, + "block": { + "message": "您今天已达到限制在 " + }, + "5mins": { + "message": "再加 5 分钟" + }, + "todayUsageTime": { + "message": "今天的总使用时间" + }, + "comparedToYesterday": { + "message": " 与昨天相比 " + }, + "mostVisited": { + "message": "访问最多的网站 " + }, + "dashboard": { + "message": "仪表板" + }, + "timeChartDescription": { + "message": "这是按小时显示一天时间的图表。" + }, + "enjoyAndReview": { + "message": "喜欢这个扩展程序吗?", + "description": "给 Web Activity Time Tracker 评分" + }, + "removeAllData": { + "message": "删除所有数据", + "description": "您可以删除所有访问过网站的所有数据和统计信息。" + }, + "remove": { + "message": "删除" + }, + "removeAllDataConfirm": { + "message": "您确定要删除所有数据吗?" + }, + "cancel": { + "message": "取消" + }, + "backupAndRestore": { + "message": "备份和恢复", + "description": "您可以下载所有访问过网站的所有数据的备份副本。" + }, + "backup": { + "message": "备份" + }, + "restore": { + "message": "恢复" + }, + "welcome": { + "message": "欢迎使用 Web Activity Time Tracker", + "description": "Web Activity Time Tracker 是一款开源免费无广告的扩展程序,它可以帮助您跟踪在浏览网站上花费的时间和访问次数。" + }, + "getStarted": { + "message": "开始使用" + }, + "welcomeStart": { + "message": "您可以通过三个简单的步骤快速开始使用扩展程序:" + }, + "pinIcon": { + "message": "固定图标" + }, + "pinIconPart1": { + "message": "为了更方便地使用此扩展程序,您可以将图标固定到工具栏上。点击图标:" + }, + "pinIconPart2": { + "message": "然后点击固定图标。" + }, + "browse": { + "message": "浏览任何网站", + "description": "当您访问任何网站时,您会看到时间显示在图标上,就像这里一样:" + }, + "seeData": { + "message": "在弹出页面和仪表板上查看您的数据", + "description": "点击扩展图标以打开弹出页面,您将能够使用饼图读取数据可视化信息,包括今天、所有时间或按天分类。在弹出窗口中,您可以打开仪表板,它将按时钟显示您今天的时间。您还可以为任何网站设置每日时间限制、网站通知或导出数据到 CSV。" + }, + "close": { + "message": "关闭" + }, + "useExtension": { + "message": "使用扩展程序" + }, + "next": { + "message": "接下来" + }, + "showChangelog": { + "message": "显示更新日志", + "description": "显示更新扩展程序后的更改列表" + }, + "byHours": { + "message": "每小时" + }, + "intervals": { + "message": "时间间隔" + }, + "intervalsChart": { + "message": "只有时间间隔大于", + "description": "展示" + }, + "promoClearYoutube": { + "message": "您想屏蔽短片、评论、推荐视频、订阅和其他 YouTube 干扰内容吗? 我们创建了另一个扩展程序,可帮助您不受干扰地观看 YouTube", + "description": "嘗試 Clean YouTube" + }, + "completelyBlocked": { + "message": "完全封锁", + "description": "完全封锁" + }, + "tryMyOtherApps": { + "message": "试试我的其他应用程序" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome扩展程序,可以隐藏YouTube短片,推荐视频,评论,feed,主页推荐和其他分心。 观看YouTube免费分心。" + }, + "darkTheme": { + "message": "黑暗主题" + }, + "cleanYoutube_promo": { + "message": "试试我们的新扩展 Clean Youtube" + }, + "cleanYoutube_description": { + "message": "想隐藏 YouTube 上的短片、推荐视频和评论?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube 是一款 YouTube™ 内容拦截器。" + }, + "cleanYoutube_features": { + "message": "我们的特色" + }, + "cleanYoutube_features1": { + "message": "清洁模式--只显示页面上的视频播放器" + }, + "cleanYoutube_features2": { + "message": "隐藏短片、评论和相关视频。15+ 个选项。" + }, + "cleanYoutube_features3": { + "message": "禁用自动播放" + }, + "cleanYoutube_features4": { + "message": "禁用结束屏幕卡片" + }, + "cleanYoutube_features5": { + "message": "黑白模式" + }, + "try": { + "message": "试用" + }, + "donate":{ + "message": "捐赠" + }, + "enjoy":{ + "message": "您喜欢 Web Activity Time Tracker 吗" + }, + "canDonate":{ + "message": "Web Activity Time Tracker 是永久免费的扩展。您可以使用加密货币支持我进一步开发。" + }, + "thanks":{ + "message": "谢谢! 🙏" + }, + "coin":{ + "message": "币" + }, + "chain":{ + "message": "链" + }, + "address":{ + "message": "币链地址" + } +} diff --git a/src/assets/clear-youtube-promo.png b/src/assets/clear-youtube-promo.png new file mode 100644 index 0000000..e0f07e8 Binary files /dev/null and b/src/assets/clear-youtube-promo.png differ diff --git a/src/assets/css/dark.css b/src/assets/css/dark.css new file mode 100644 index 0000000..b976124 --- /dev/null +++ b/src/assets/css/dark.css @@ -0,0 +1,91 @@ +.dark{ + background-color: #303030; + color: white; +} +.dark .headerBlock .header { + color: #ffffff !important; +} +.dark .headerBlock .icons-block a:hover{ + filter: invert(40%) sepia(94%) saturate(3371%) hue-rotate(227deg) brightness(99%) contrast(92%); +} +.dark .headerBlock .icons-block a.filter img { + filter: invert(100%) sepia(17%) saturate(0%) hue-rotate(24deg) brightness(103%) contrast(102%); +} +.dark .header-block { + background-color: #616161; +} +.dark .tab-item .progress-bar{ + border: 1.5px rgb(107 107 107) solid; +} +.dark .tab-item:hover{ + border: 1px rgb(107 107 107) solid; +} +.dark .tab-item .links .link{ + filter: invert(100%) sepia(17%) saturate(0%) hue-rotate(24deg) brightness(103%) contrast(102%); +} +.dark .stats-block .block p{ + color: #b9b9b9 !important; +} +.dark .stats-block .block .header { + background-color: #595959; + color: rgb(255 255 255); +} +.dark .stats-block.block .header{ + background-color: #595959; + color: rgb(255 255 255); +} +.dark .stats-block.block p{ + color: #b9b9b9 !important; +} +.dark .expander-body{ + background-color: #595959 !important; +} +.dark .expander .header span{ + color: #b9b9b9 !important; +} +.dark .expander.total { + background-color: #6f6f6f !important; +} +.dark .url-list{ + border: 1px solid #494949 !important; +} +.dark .header span{ + color: rgb(255 255 255); +} +.dark .settings-tab label[name="tabName"] img{ + background-color: grey; + border-radius: 10px; + padding: 5px; +} +.dark .settings-tab label[name="tabName"]{ + background-color: #303030 !important; + color: #f7f7f7; +} +.dark .settings-content{ + background-color: #303030 !important; + border-left: 1px solid #494949 !important; +} +.dark .app-block{ + background-color: #919191 !important; +} +.dark .app-block .title{ + color: rgb(255, 255, 255); +} +.dark .app-block .description{ + color: white !important; +} +.dark .settings-tab label[name="tabName"]:hover, .dark [type='radio']:checked ~ label{ + background-color: #666666 !important; +} +.dark .container p.value{ + color: black; +} +.dark .review-block p{ + color:#303030; +} +.dark .pomodoro-popup-block p{ + color:#303030; +} +.dark .promo{ + color: black !important; +} \ No newline at end of file diff --git a/src/assets/css/dashboard.css b/src/assets/css/dashboard.css new file mode 100644 index 0000000..daaebce --- /dev/null +++ b/src/assets/css/dashboard.css @@ -0,0 +1,327 @@ +body { + font-family: 'Segoe UI', Tahoma, sans-serif !important; + color: #262626; + background-color: #eee; + margin: 0; +} + +.container { + width: 850px; + margin: 10px auto; +} + +.title { + font-size: 18px; + font-weight: 600; +} + +.setting-header { + font-weight: 600; + font-size: 16px; +} + +.description { + font-size: 14px; + color: grey; + margin: 7px 0 15px 0; + font-weight: normal; +} + +.url-list { + border-radius: 3px; + border: 1px solid #ccc; + width: 655px; + min-height: 300px; + cursor: pointer; + list-style: none; + padding-left: 10px; + max-height: 600px; + overflow: auto; +} + +.url-list li { + font-size: 14px; +} + +.url-list li span{ + font-weight: 600; + margin-left: 10px; +} + +input[type='number'],input[type='text'] { + height: 36px; + padding: 0 0 0 5px; + width: 400px; + border-radius: 3px; + border: 1px solid #ccc; +} + +input[type='button'].small-btn { + padding: 0 5px; + width: 120px; +} + +.option { + min-width: 170px; + color: #444; + background: #fff; + border-radius: 3px; + margin: 0; + padding: 10px 30px 10px 15px; + font-size: 14px; + border-color: #ccc; + position: relative; + cursor: pointer; +} + +.header { + grid-area: h; + margin: 0 0 10px; + font-size: 20px; +} + +a { + color: #3477db; + text-decoration: none; + cursor: pointer; +} + +label { + font-size: 14px; +} + +[type='checkbox']:not(:checked), +[type='checkbox']:checked { + position: absolute; + opacity: 0; + pointer-events: none; +} + +[type='checkbox'] + span { + position: relative; + padding-left: 30px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 14px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +[type='checkbox'] + span:before, +[type='checkbox']:not(.filled-in) + span:after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; + z-index: 0; + border: 2px solid #5a5a5a; + border-radius: 1px; + margin-top: 3px; +} + +[type='checkbox']:not(:checked):disabled + span:before { + border: none; + background-color: rgba(0, 0, 0, 0.42); +} + +[type='checkbox']:checked:disabled + span:before { + border-right: 2px solid rgba(0, 0, 0, 0.42); + border-bottom: 2px solid rgba(0, 0, 0, 0.42); +} + +[type='checkbox'].filled-in + span:after { + border-radius: 2px; +} + +[type='checkbox'].filled-in + span:before, +[type='checkbox'].filled-in + span:after { + content: ''; + left: 0; + position: absolute; + z-index: 1; +} + +[type='checkbox'].filled-in:not(:checked) + span:before { + width: 0; + height: 0; + border: 3px solid transparent; + left: 6px; + top: 10px; + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type='checkbox'].filled-in:not(:checked) + span:after { + height: 17px; + width: 17px; + background-color: transparent; + border: 2px solid #5a5a5a; + top: 0px; + z-index: 0; +} + +[type='checkbox'].filled-in:checked + span:before { + top: -3px; + left: -2px; + width: 7px; + height: 12px; + border-top: 3px solid transparent; + border-left: 3px solid transparent; + border-right: 3px solid #fff; + border-bottom: 3px solid #fff; + -webkit-transform: rotateZ(35deg); + transform: rotateZ(35deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type='checkbox'].filled-in:checked + span:after { + top: 0; + width: 17px; + height: 17px; + border: 2px solid #3477db; + background-color: #3477db; + z-index: 0; +} + +.hidden { + display: none !important; +} + +.notify { + width: 220px; + height: 27px; + margin: auto; + background-color: rgb(21, 104, 0); + color: rgb(255, 255, 255); + text-align: center; + font-weight: 600; + border-radius: 5px; + position: fixed; + z-index: 1; + top: 10px; + right: 20px; + font-size: 15px; + white-space: nowrap; + padding: 10px; +} + +.block { + display: block; +} + +.readonly-input { + cursor: default; + border: 0; + display: block; +} + +.setting-notify-block { + width: 450px; + height: 100px; + margin-top: 15px; + background-color: rgb(175, 175, 175); + border-radius: 10px; +} + +.setting-notify-block .setting-notify-title { + padding: 15px 20px 5px 0; + font-weight: 700; + color: #ffffff; + font-size: 15px; + text-align: left; + display: block; +} + +.setting-notify-block .setting-notify-message { + padding: 3px 20px 5px 0; + font-size: 14px; + display: block; + width: 320px; +} +.setting-notify-block .setting-notify-message-g { + padding: 0 30px 5px 0; + color: rgb(199, 199, 199); + font-size: 11px; + display: block; +} + +.setting-notify-block .setting-notify-img { + height: 50px; + padding: 25px 15px 25px 25px; +} + +.setting-notify-block .setting-notify-message-block { + display: inline-block; + position: absolute; +} + +.settings-tabs { +} +.settings-tab { + clear: both; + width: 286px; +} +.settings-tab label[name='tabName'] { + background: #eee; + padding: 5px 0 5px 20px; + font-size: 16px; + vertical-align: middle; + width: 266px; + height: 40px; + display: table-cell; + cursor: pointer; +} +.settings-tab label[name='tabName']:hover { + background-color: #cccccc !important; +} +.settings-tab [type='radio'] { + display: none; +} +.settings-tab img{ + vertical-align: middle; + margin-right: 10px; +} +.settings-content { + position: absolute; + top: 0; + left: 286px; + background: white; + right: 0; + bottom: 0; + padding: 50px; + border-left: 1px solid #ccc; + overflow-y: auto; +} +.settings-content span { + animation: 0.5s ease-out 0s 1 slideInFromTop; +} +[type='radio']:checked ~ label { + background: white; + border-bottom: 2px solid #8bc34a; + z-index: 2; +} +[type='radio']:checked ~ label ~ .settings-content { + z-index: 1; +} +.settings-item { + margin-bottom: 30px; +} +.url-list img { + vertical-align: middle; + margin-right: 10px; + cursor: pointer; +} + +.url-list .time-value { + margin-top: 5px; + margin-left: 55px; +} diff --git a/src/assets/css/general.css b/src/assets/css/general.css new file mode 100644 index 0000000..d15af6b --- /dev/null +++ b/src/assets/css/general.css @@ -0,0 +1,168 @@ +:root { + --main-color: #6ebf5d; + --popup-header: #efefef; + --progress-bar: #428bff; +} + +.no-data { + text-align: center; + font-size: 16px; + font-weight: 600; + margin-top: 30%; +} + +.float-right { + float: right; +} +.d-inline-block { + display: inline-block; +} +.mt-0 { + margin-top: 0; +} +.mt-20 { + margin-top: 20px; +} +.mt-30 { + margin-top: 30px; +} +.mb-20 { + margin-bottom: 20px; +} +.ml-5 { + margin-left: 5px; +} +.ml-10 { + margin-left: 10px; +} +.mr-10 { + margin-right: 10px; +} +.ml-20 { + margin-left: 20px; +} +.mr-20 { + margin-right: 20px; +} +.mr-5 { + margin-right: 5px; +} +.pr-5 { + padding-right: 5px; +} +.p-5 { + padding: 5px; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} + +.mt-10 { + margin-top: 10px; +} + +.mt-15 { + margin-top: 15px; +} +select { + border-color: #ccc; + border-radius: 5px; +} +.w-100 { + width: 100%; +} +input[type='button'] { + background: #5377af; + color: #fff; + border-radius: 7px; + height: 36px; + line-height: 35px; + padding: 0 20px; + border: 0; + font-size: 14px; + font-weight: 500; + cursor: pointer; + min-width: 80px; + text-align: center; + width: 200px; +} + +input[type='button']:hover { + background: #314158; + text-decoration: none; +} + +input[type='button'].alert { + background: #fe5c5c !important; +} + +input[type='button'].info { + background: #ffffff !important; + color: black; + border: 1px solid rgb(151, 151, 151); +} + +input[type='button'][disabled] { + border: 1px solid #999999; + background-color: #cccccc; + color: #666666; +} +.modal { + display: block; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.4); +} + +.modal-content { + background-color: #fefefe; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 40%; + border-radius: 10px; +} + +.modal-content p{ + font-size: 18px; + font-weight: 600; +} + +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} +.no-data .date-picker { + font-weight: normal; + text-align: center; + width: 250px; + margin: auto; + margin-top: 15px; +} +.date-block .date-picker { + width: 250px; +} +.font-bold{ + font-weight: 600; +} +.font-16{ + font-size: 16px; +} \ No newline at end of file diff --git a/src/assets/css/main.css b/src/assets/css/main.css new file mode 100644 index 0000000..955b6c4 --- /dev/null +++ b/src/assets/css/main.css @@ -0,0 +1,223 @@ +::-webkit-scrollbar-track { + border-radius: 10px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar { + width: 7px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: #7c7c7c; +} +html, +body { + width: 600px; + height: 590px; + padding: 0; + margin: 0; +} +.tabs { +} +.tabs input[name='tab-control'] { + display: none; +} +.tabs .content section h2, +.tabs ul li label { + + font-size: 15px; + color: #428bff; +} +.tabs ul { + list-style-type: none; + padding-left: 0; + display: flex; + flex-direction: row; + margin-bottom: 10px; + justify-content: space-between; + align-items: flex-end; + flex-wrap: wrap; +} +.tabs ul li { + box-sizing: border-box; + flex: 1; + width: 25%; + padding: 0 10px; + text-align: center; +} +.tabs ul li label { + transition: all 0.3s ease-in-out; + color: #929daf; + padding: 5px auto; + overflow: hidden; + display: block; + cursor: pointer; + transition: all 0.2s ease-in-out; + white-space: nowrap; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.tabs ul li label br { + display: none; +} +.tabs ul li label img { + filter: brightness(0) saturate(100%) invert(67%) sepia(15%) saturate(342%) hue-rotate(178deg) + brightness(91%) contrast(89%); + vertical-align: bottom; + margin-right: 0.2em; + transition: all 0.2s ease-in-out; +} +.tabs ul li label:hover, +.tabs ul li label:focus, +.tabs ul li label:active { + outline: 0; + color: #bec5cf; +} +.tabs ul li label:hover img, +.tabs ul li label:focus img, +.tabs ul li label:active img { + filter: #bec5cf; +} +.tabs .slider { + position: relative; + width: 25%; + transition: all 0.33s cubic-bezier(0.38, 0.8, 0.32, 1.07); +} +.tabs .slider .indicator { + position: relative; + width: 50px; + max-width: 100%; + margin: 0 auto; + height: 4px; + background: #428bff; + border-radius: 1px; +} +.tabs .content { + margin-top: 10px; +} +.tabs .content section { + display: none; + -webkit-animation-name: content; + animation-name: content; + -webkit-animation-direction: normal; + animation-direction: normal; + -webkit-animation-duration: 0.3s; + animation-duration: 0.3s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + line-height: 1.4; +} +.tabs .content section h2 { + color: #428bff; + display: none; +} +.tabs .content section h2::after { + content: ''; + position: relative; + display: block; + width: 30px; + height: 3px; + background: #428bff; + margin-top: 5px; + left: 1px; +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ ul > li:nth-child(1) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ ul > li:nth-child(1) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ .slider { + transform: translateX(17%); +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ .content > section:nth-child(1) { + display: block; +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ ul > li:nth-child(2) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ ul > li:nth-child(2) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ .slider { + transform: translateX(150%); +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ .content > section:nth-child(2) { + display: block; +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ ul > li:nth-child(3) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ ul > li:nth-child(3) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ .slider { + transform: translateX(290%); +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ .content > section:nth-child(3) { + display: block; +} +@-webkit-keyframes content { + from { + opacity: 0; + transform: translateY(5%); + } + to { + opacity: 1; + transform: translateY(0%); + } +} +@keyframes content { + from { + opacity: 0; + transform: translateY(5%); + } + to { + opacity: 1; + transform: translateY(0%); + } +} +.tabs ul li label { + white-space: initial; +} +.tabs ul li label img { + height: 1.2em; +} +.tooltip { + position: relative; + display: inline-block; + vertical-align: middle; +} +.tooltip .tooltiptext { + font-size: 11px; + font-weight: 500; + visibility: hidden; + width: 180px; + background-color: #555; + color: #fff; + text-align: center; + padding: 10px 10px; + border-radius: 6px; + position: absolute; + z-index: 1; + transform: translate(-55%) translateY(-125%); + opacity: 0; + transition: opacity 0.3s; +} +.tooltip:hover .tooltiptext { + visibility: visible; + opacity: 1; +} diff --git a/src/assets/icons/128x128.png b/src/assets/icons/128x128.png new file mode 100644 index 0000000..8915f31 Binary files /dev/null and b/src/assets/icons/128x128.png differ diff --git a/src/assets/icons/16x16.png b/src/assets/icons/16x16.png new file mode 100644 index 0000000..4916da6 Binary files /dev/null and b/src/assets/icons/16x16.png differ diff --git a/src/assets/icons/32x32.png b/src/assets/icons/32x32.png new file mode 100644 index 0000000..f6812bb Binary files /dev/null and b/src/assets/icons/32x32.png differ diff --git a/src/assets/icons/48x48.png b/src/assets/icons/48x48.png new file mode 100644 index 0000000..336d1ef Binary files /dev/null and b/src/assets/icons/48x48.png differ diff --git a/src/assets/icons/by-hours.svg b/src/assets/icons/by-hours.svg new file mode 100644 index 0000000..da7c058 --- /dev/null +++ b/src/assets/icons/by-hours.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/by-intervals.svg b/src/assets/icons/by-intervals.svg new file mode 100644 index 0000000..9c151bd --- /dev/null +++ b/src/assets/icons/by-intervals.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/assets/icons/clear-youtube-logo.svg b/src/assets/icons/clear-youtube-logo.svg new file mode 100644 index 0000000..5854613 --- /dev/null +++ b/src/assets/icons/clear-youtube-logo.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/close.svg b/src/assets/icons/close.svg new file mode 100644 index 0000000..79b0d2f --- /dev/null +++ b/src/assets/icons/close.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/dark-mode.svg b/src/assets/icons/dark-mode.svg new file mode 100644 index 0000000..c2f0dce --- /dev/null +++ b/src/assets/icons/dark-mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/dashboard.svg b/src/assets/icons/dashboard.svg new file mode 100644 index 0000000..099ec8c --- /dev/null +++ b/src/assets/icons/dashboard.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/delete.png b/src/assets/icons/delete.png new file mode 100644 index 0000000..1899aff Binary files /dev/null and b/src/assets/icons/delete.png differ diff --git a/src/assets/icons/details-link.svg b/src/assets/icons/details-link.svg new file mode 100644 index 0000000..339e00b --- /dev/null +++ b/src/assets/icons/details-link.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/donate.png b/src/assets/icons/donate.png new file mode 100644 index 0000000..8f90408 Binary files /dev/null and b/src/assets/icons/donate.png differ diff --git a/src/assets/icons/donation-qr.png b/src/assets/icons/donation-qr.png new file mode 100644 index 0000000..06f400e Binary files /dev/null and b/src/assets/icons/donation-qr.png differ diff --git a/src/assets/icons/edit.svg b/src/assets/icons/edit.svg new file mode 100644 index 0000000..c06b44d --- /dev/null +++ b/src/assets/icons/edit.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/icons/empty.png b/src/assets/icons/empty.png similarity index 100% rename from src/icons/empty.png rename to src/assets/icons/empty.png diff --git a/src/assets/icons/extension.svg b/src/assets/icons/extension.svg new file mode 100644 index 0000000..0897782 --- /dev/null +++ b/src/assets/icons/extension.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/icon.png b/src/assets/icons/icon.png new file mode 100644 index 0000000..9c86246 Binary files /dev/null and b/src/assets/icons/icon.png differ diff --git a/src/assets/icons/light-mode.svg b/src/assets/icons/light-mode.svg new file mode 100644 index 0000000..cff0d6f --- /dev/null +++ b/src/assets/icons/light-mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/no-today.svg b/src/assets/icons/no-today.svg new file mode 100644 index 0000000..9933b25 --- /dev/null +++ b/src/assets/icons/no-today.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/open-link.svg b/src/assets/icons/open-link.svg new file mode 100644 index 0000000..ad17a47 --- /dev/null +++ b/src/assets/icons/open-link.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/pin.svg b/src/assets/icons/pin.svg new file mode 100644 index 0000000..2a91ad0 --- /dev/null +++ b/src/assets/icons/pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/pomodoro-rest.png b/src/assets/icons/pomodoro-rest.png new file mode 100644 index 0000000..5c8a25e Binary files /dev/null and b/src/assets/icons/pomodoro-rest.png differ diff --git a/src/assets/icons/pomodoro.png b/src/assets/icons/pomodoro.png new file mode 100644 index 0000000..1bca502 Binary files /dev/null and b/src/assets/icons/pomodoro.png differ diff --git a/src/assets/icons/pomodoro.svg b/src/assets/icons/pomodoro.svg new file mode 100644 index 0000000..d3ec461 --- /dev/null +++ b/src/assets/icons/pomodoro.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/preloader.gif b/src/assets/icons/preloader.gif new file mode 100644 index 0000000..32ac2b4 Binary files /dev/null and b/src/assets/icons/preloader.gif differ diff --git a/src/assets/icons/s-about.svg b/src/assets/icons/s-about.svg new file mode 100644 index 0000000..bb28eac --- /dev/null +++ b/src/assets/icons/s-about.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-dashboard.svg b/src/assets/icons/s-dashboard.svg new file mode 100644 index 0000000..fc057b7 --- /dev/null +++ b/src/assets/icons/s-dashboard.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-limits.svg b/src/assets/icons/s-limits.svg new file mode 100644 index 0000000..3b0ce8d --- /dev/null +++ b/src/assets/icons/s-limits.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-notifications.svg b/src/assets/icons/s-notifications.svg new file mode 100644 index 0000000..1303469 --- /dev/null +++ b/src/assets/icons/s-notifications.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-settings.svg b/src/assets/icons/s-settings.svg new file mode 100644 index 0000000..1734f08 --- /dev/null +++ b/src/assets/icons/s-settings.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-whitelist.svg b/src/assets/icons/s-whitelist.svg new file mode 100644 index 0000000..0774698 --- /dev/null +++ b/src/assets/icons/s-whitelist.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/settings.svg b/src/assets/icons/settings.svg new file mode 100644 index 0000000..4096f43 --- /dev/null +++ b/src/assets/icons/settings.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/assets/icons/start.svg b/src/assets/icons/start.svg new file mode 100644 index 0000000..144f821 --- /dev/null +++ b/src/assets/icons/start.svg @@ -0,0 +1,17 @@ + + + + + play + Created with Sketch Beta. + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/stop.svg b/src/assets/icons/stop.svg new file mode 100644 index 0000000..8d35481 --- /dev/null +++ b/src/assets/icons/stop.svg @@ -0,0 +1,17 @@ + + + + + stop + Created with Sketch Beta. + + + + + + + + + + + \ No newline at end of file diff --git a/src/icons/success.png b/src/assets/icons/success.png similarity index 100% rename from src/icons/success.png rename to src/assets/icons/success.png diff --git a/src/icons/today.svg b/src/assets/icons/today.svg similarity index 100% rename from src/icons/today.svg rename to src/assets/icons/today.svg diff --git a/src/assets/icons/trackerjam-logo.png b/src/assets/icons/trackerjam-logo.png new file mode 100644 index 0000000..dc6d052 Binary files /dev/null and b/src/assets/icons/trackerjam-logo.png differ diff --git a/src/assets/initial.jpg b/src/assets/initial.jpg new file mode 100644 index 0000000..d70547a Binary files /dev/null and b/src/assets/initial.jpg differ diff --git a/src/assets/pin-tutorial.png b/src/assets/pin-tutorial.png new file mode 100644 index 0000000..ebece96 Binary files /dev/null and b/src/assets/pin-tutorial.png differ diff --git a/src/assets/pomodoro-sounds/1.mp3 b/src/assets/pomodoro-sounds/1.mp3 new file mode 100644 index 0000000..2c4babb Binary files /dev/null and b/src/assets/pomodoro-sounds/1.mp3 differ diff --git a/src/assets/pomodoro-sounds/10.mp3 b/src/assets/pomodoro-sounds/10.mp3 new file mode 100644 index 0000000..371a5b8 Binary files /dev/null and b/src/assets/pomodoro-sounds/10.mp3 differ diff --git a/src/assets/pomodoro-sounds/11.mp3 b/src/assets/pomodoro-sounds/11.mp3 new file mode 100644 index 0000000..e000b73 Binary files /dev/null and b/src/assets/pomodoro-sounds/11.mp3 differ diff --git a/src/assets/pomodoro-sounds/12.mp3 b/src/assets/pomodoro-sounds/12.mp3 new file mode 100644 index 0000000..b949f38 Binary files /dev/null and b/src/assets/pomodoro-sounds/12.mp3 differ diff --git a/src/assets/pomodoro-sounds/13.mp3 b/src/assets/pomodoro-sounds/13.mp3 new file mode 100644 index 0000000..a255ca5 Binary files /dev/null and b/src/assets/pomodoro-sounds/13.mp3 differ diff --git a/src/assets/pomodoro-sounds/2.mp3 b/src/assets/pomodoro-sounds/2.mp3 new file mode 100644 index 0000000..2e526e3 Binary files /dev/null and b/src/assets/pomodoro-sounds/2.mp3 differ diff --git a/src/assets/pomodoro-sounds/3.mp3 b/src/assets/pomodoro-sounds/3.mp3 new file mode 100644 index 0000000..185ddb4 Binary files /dev/null and b/src/assets/pomodoro-sounds/3.mp3 differ diff --git a/src/assets/pomodoro-sounds/4.mp3 b/src/assets/pomodoro-sounds/4.mp3 new file mode 100644 index 0000000..4fcab3f Binary files /dev/null and b/src/assets/pomodoro-sounds/4.mp3 differ diff --git a/src/assets/pomodoro-sounds/5.mp3 b/src/assets/pomodoro-sounds/5.mp3 new file mode 100644 index 0000000..8009774 Binary files /dev/null and b/src/assets/pomodoro-sounds/5.mp3 differ diff --git a/src/assets/pomodoro-sounds/6.mp3 b/src/assets/pomodoro-sounds/6.mp3 new file mode 100644 index 0000000..21d0827 Binary files /dev/null and b/src/assets/pomodoro-sounds/6.mp3 differ diff --git a/src/assets/pomodoro-sounds/7.mp3 b/src/assets/pomodoro-sounds/7.mp3 new file mode 100644 index 0000000..901fc3d Binary files /dev/null and b/src/assets/pomodoro-sounds/7.mp3 differ diff --git a/src/assets/pomodoro-sounds/8.mp3 b/src/assets/pomodoro-sounds/8.mp3 new file mode 100644 index 0000000..8843950 Binary files /dev/null and b/src/assets/pomodoro-sounds/8.mp3 differ diff --git a/src/assets/pomodoro-sounds/9.mp3 b/src/assets/pomodoro-sounds/9.mp3 new file mode 100644 index 0000000..59845ea Binary files /dev/null and b/src/assets/pomodoro-sounds/9.mp3 differ diff --git a/src/background.ts b/src/background.ts new file mode 100644 index 0000000..88ffeb1 --- /dev/null +++ b/src/background.ts @@ -0,0 +1,92 @@ +import Browser from 'webextension-polyfill'; +import { initTracker } from './tracker'; +import { logger } from './utils/logger'; +import { scheduleJobs } from './jobs/sheduler'; +import { Settings } from './functions/settings'; +import { StorageParams } from './storage/storage-params'; +import { injectStorage } from './storage/inject-storage'; +import { todayLocalDate } from './utils/date'; +import { checkPomodoro } from './functions/pomodoro'; +import { Messages } from './utils/messages'; +import { injectTabsRepositorySingleton } from './repository/inject-tabs-repository'; + +logger.log('Start background script'); +let pomodoroTimer: number; + +self.onerror = err => { + console.error('Unhandled error:', err); +}; + +Browser.storage.onChanged.addListener(async (changes, namespace) => { + for (var key in changes) { + if (Object.values(StorageParams).includes(key as StorageParams)) + await Settings.getInstance().reloadSetting(key as StorageParams); + + if (key == StorageParams.IS_POMODORO_ENABLED) { + const value = changes[StorageParams.IS_POMODORO_ENABLED].newValue; + pomodoro(value); + } + } +}); + +Browser.runtime.setUninstallURL('https://webtracker.online/goodbye.html'); + +Browser.runtime.onInstalled.addListener(async details => { + if (details.reason == 'install') { + logger.log('Extension installed:', details); + const settingsStorage = injectStorage(); + await settingsStorage.saveValue(StorageParams.INSTALL_DATE, todayLocalDate()); + + const initialPageUrl = Browser.runtime.getURL('src/welcome.html'); + await Browser.tabs.create({ + url: initialPageUrl, + active: true, + }); + } + if (details.reason == 'update' && !details.previousVersion) { + const showChangelog = (await Settings.getInstance().getSetting( + StorageParams.SHOW_CHANGELOG, + )) as boolean; + if (showChangelog) + await Browser.tabs.create({ + url: 'https://webtracker.online/releasenotes.html', + active: true, + }); + } +}); + +Browser.runtime.onStartup.addListener(() => { + logger.log(`onStartup event`); +}); + +Browser.windows.onFocusChanged.addListener(() => { + logger.log('onFocusChanged'); +}); + +async function pomodoro(value?: boolean) { + if (value == undefined) { + const settingsStorage = injectStorage(); + value = await settingsStorage.getValue(StorageParams.IS_POMODORO_ENABLED); + } + if (value == true) pomodoroTimer = setInterval(checkPomodoro, 1000); + else clearInterval(pomodoroTimer); +} + +pomodoro(); +scheduleJobs(); +initTracker(); + +Browser.runtime.onMessage.addListener(async message => { + if (message == Messages.ClearAllData) { + const storage = injectStorage(); + const repo = await injectTabsRepositorySingleton(); + repo.removeAllTabs(); + await storage.saveTabs([]); + } + if (message.message == Messages.Restore) { + const storage = injectStorage(); + await storage.saveTabs(message.data); + const repo = await injectTabsRepositorySingleton(); + repo.initAsync(); + } +}); diff --git a/src/block.html b/src/block.html index e4c2d86..1b72d23 100644 --- a/src/block.html +++ b/src/block.html @@ -1,29 +1,15 @@ - - - - - Access to the site is limited - - - - - - - -
- -

Time limit

-
You've reached your limit today on
-
Your current daily limit is
- -
You have already been here - times for a total duration of - today ! -
-
Set aside for 5 minutes
-
-

Web Activity Time Tracker

- - - \ No newline at end of file + + + + + + Access to the site is limited - Web Activity Time Tracker + + + + + + + + diff --git a/src/block.ts b/src/block.ts new file mode 100644 index 0000000..fd1c16d --- /dev/null +++ b/src/block.ts @@ -0,0 +1,7 @@ +import Block from './pages/Block.vue'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Block); +app.use(i18n); +app.mount('body'); diff --git a/src/components/About.vue b/src/components/About.vue new file mode 100644 index 0000000..0938fe8 --- /dev/null +++ b/src/components/About.vue @@ -0,0 +1,47 @@ + + + + + + + diff --git a/src/components/BadgeIcons.vue b/src/components/BadgeIcons.vue new file mode 100644 index 0000000..16d920d --- /dev/null +++ b/src/components/BadgeIcons.vue @@ -0,0 +1,58 @@ + + + + + + + diff --git a/src/components/ByDays.vue b/src/components/ByDays.vue new file mode 100644 index 0000000..fc9e607 --- /dev/null +++ b/src/components/ByDays.vue @@ -0,0 +1,206 @@ + + + + + + + diff --git a/src/components/ByDaysChart.vue b/src/components/ByDaysChart.vue new file mode 100644 index 0000000..1e6d699 --- /dev/null +++ b/src/components/ByDaysChart.vue @@ -0,0 +1,103 @@ + + + + + + + diff --git a/src/components/Dashboad.vue b/src/components/Dashboad.vue new file mode 100644 index 0000000..b386e74 --- /dev/null +++ b/src/components/Dashboad.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/src/components/DashboadContainer.vue b/src/components/DashboadContainer.vue new file mode 100644 index 0000000..c56c334 --- /dev/null +++ b/src/components/DashboadContainer.vue @@ -0,0 +1,30 @@ + + + + + + + diff --git a/src/components/Donation.vue b/src/components/Donation.vue new file mode 100644 index 0000000..f3eed24 --- /dev/null +++ b/src/components/Donation.vue @@ -0,0 +1,46 @@ + + + + + + + diff --git a/src/components/DonutChart.vue b/src/components/DonutChart.vue new file mode 100644 index 0000000..fe8b9b8 --- /dev/null +++ b/src/components/DonutChart.vue @@ -0,0 +1,97 @@ + + + + + + + diff --git a/src/components/Expander.vue b/src/components/Expander.vue new file mode 100644 index 0000000..b66e900 --- /dev/null +++ b/src/components/Expander.vue @@ -0,0 +1,108 @@ + + + + + + + diff --git a/src/components/Favicon.vue b/src/components/Favicon.vue new file mode 100644 index 0000000..f3a54b4 --- /dev/null +++ b/src/components/Favicon.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/components/GeneralSettings.vue b/src/components/GeneralSettings.vue new file mode 100644 index 0000000..d76ce8c --- /dev/null +++ b/src/components/GeneralSettings.vue @@ -0,0 +1,298 @@ + + + + + + + diff --git a/src/components/HourlyChart.vue b/src/components/HourlyChart.vue new file mode 100644 index 0000000..b2dbcb5 --- /dev/null +++ b/src/components/HourlyChart.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/components/Limits.vue b/src/components/Limits.vue new file mode 100644 index 0000000..79900b0 --- /dev/null +++ b/src/components/Limits.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/src/components/ListWithTime.vue b/src/components/ListWithTime.vue new file mode 100644 index 0000000..bf9fda8 --- /dev/null +++ b/src/components/ListWithTime.vue @@ -0,0 +1,218 @@ + + + + + + + diff --git a/src/components/MyApps.vue b/src/components/MyApps.vue new file mode 100644 index 0000000..28da6ea --- /dev/null +++ b/src/components/MyApps.vue @@ -0,0 +1,78 @@ + + + + + + + diff --git a/src/components/NoDataByDays.vue b/src/components/NoDataByDays.vue new file mode 100644 index 0000000..836d1bd --- /dev/null +++ b/src/components/NoDataByDays.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/components/Notifications.vue b/src/components/Notifications.vue new file mode 100644 index 0000000..e334edd --- /dev/null +++ b/src/components/Notifications.vue @@ -0,0 +1,142 @@ + + + + + + + diff --git a/src/components/OverallStatistics.vue b/src/components/OverallStatistics.vue new file mode 100644 index 0000000..e968f2b --- /dev/null +++ b/src/components/OverallStatistics.vue @@ -0,0 +1,192 @@ + + + + + + + diff --git a/src/components/Pomodoro.vue b/src/components/Pomodoro.vue new file mode 100644 index 0000000..be9a086 --- /dev/null +++ b/src/components/Pomodoro.vue @@ -0,0 +1,254 @@ + + + + + + + diff --git a/src/components/PomodoroInfo.vue b/src/components/PomodoroInfo.vue new file mode 100644 index 0000000..a3b24df --- /dev/null +++ b/src/components/PomodoroInfo.vue @@ -0,0 +1,72 @@ + + + + + + + diff --git a/src/components/PomodoroSoundsSelector.vue b/src/components/PomodoroSoundsSelector.vue new file mode 100644 index 0000000..1527172 --- /dev/null +++ b/src/components/PomodoroSoundsSelector.vue @@ -0,0 +1,69 @@ + + + + + + + diff --git a/src/components/PromoCleanYoutubeModal.vue b/src/components/PromoCleanYoutubeModal.vue new file mode 100644 index 0000000..abb0511 --- /dev/null +++ b/src/components/PromoCleanYoutubeModal.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/components/PromoClearYouTube.vue b/src/components/PromoClearYouTube.vue new file mode 100644 index 0000000..6bba3f5 --- /dev/null +++ b/src/components/PromoClearYouTube.vue @@ -0,0 +1,82 @@ + + + + + + + diff --git a/src/components/Review.vue b/src/components/Review.vue new file mode 100644 index 0000000..45cfebe --- /dev/null +++ b/src/components/Review.vue @@ -0,0 +1,90 @@ + + + + + + + diff --git a/src/components/TabItem.vue b/src/components/TabItem.vue new file mode 100644 index 0000000..a543f89 --- /dev/null +++ b/src/components/TabItem.vue @@ -0,0 +1,179 @@ + + + + + + + diff --git a/src/components/TabItemHeader.vue b/src/components/TabItemHeader.vue new file mode 100644 index 0000000..d2c6311 --- /dev/null +++ b/src/components/TabItemHeader.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/src/components/TabList.vue b/src/components/TabList.vue new file mode 100644 index 0000000..b9dfd5f --- /dev/null +++ b/src/components/TabList.vue @@ -0,0 +1,167 @@ + + + + + + + diff --git a/src/components/TimeIntervalChart.vue b/src/components/TimeIntervalChart.vue new file mode 100644 index 0000000..f10c3ed --- /dev/null +++ b/src/components/TimeIntervalChart.vue @@ -0,0 +1,248 @@ + + + + + + + diff --git a/src/components/WebsiteStats.vue b/src/components/WebsiteStats.vue new file mode 100644 index 0000000..5412730 --- /dev/null +++ b/src/components/WebsiteStats.vue @@ -0,0 +1,144 @@ + + + + + + + diff --git a/src/components/WebsiteStatsDetails.vue b/src/components/WebsiteStatsDetails.vue new file mode 100644 index 0000000..e205021 --- /dev/null +++ b/src/components/WebsiteStatsDetails.vue @@ -0,0 +1,67 @@ + + + + + + + diff --git a/src/components/WhiteList.vue b/src/components/WhiteList.vue new file mode 100644 index 0000000..b58a6ec --- /dev/null +++ b/src/components/WhiteList.vue @@ -0,0 +1,99 @@ + + + + + + + diff --git a/src/compositions/useExtensionPage.ts b/src/compositions/useExtensionPage.ts new file mode 100644 index 0000000..70ff3b1 --- /dev/null +++ b/src/compositions/useExtensionPage.ts @@ -0,0 +1,48 @@ +import { computed, ref } from 'vue'; +import { SettingsTab } from '../utils/enums'; +import { getStringTab } from '../utils/extension-tabs'; + +export const QUERY_PARAMS_DASHBOARD = 'dashboard.html'; +export const QUERY_PARAMS_TAB = 'tab'; +export const QUERY_PARAMS_TAB_LIMITS = 'limits'; +export const QUERY_PARAMS_BLOCK = 'block.html'; +export const QUERY_PARAMS_BLOCK_DOMAIN = 'domain'; + +export function useExtensionPage() { + const urlObj = ref(new URL(location.href)); + + const isLimitPage = computed( + () => + urlObj.value.hostname == __APP_ID__ && + urlObj.value.pathname.includes(QUERY_PARAMS_DASHBOARD) && + urlObj.value.searchParams.get(QUERY_PARAMS_TAB) == QUERY_PARAMS_TAB_LIMITS, + ); + + const isBlockPage = computed( + () => + urlObj.value.hostname == __APP_ID__ && + urlObj.value.pathname.includes(QUERY_PARAMS_BLOCK) && + urlObj.value.searchParams.get(QUERY_PARAMS_BLOCK_DOMAIN)?.includes('youtube.com'), + ); + + function updateTab(tab: SettingsTab) { + let targetTab = getStringTab(tab); + const currentTab = urlObj.value.searchParams.get(QUERY_PARAMS_TAB); + if (window.history.replaceState && currentTab) { + const sourceUrl = `tab=${currentTab}`; + const targetUrl = `tab=${targetTab}`; + window.history.replaceState( + location.href, + document.title, + location.href.replace(sourceUrl, targetUrl), + ); + urlObj.value = new URL(location.href); + } + } + + return { + isLimitPage, + isBlockPage, + updateTab, + }; +} diff --git a/src/compositions/usePromoExtension.ts b/src/compositions/usePromoExtension.ts new file mode 100644 index 0000000..b96ca5b --- /dev/null +++ b/src/compositions/usePromoExtension.ts @@ -0,0 +1,45 @@ +import { computed } from 'vue'; +import { Restriction } from '../entity/restriction'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams } from '../storage/storage-params'; +import { useExtensionPage } from './useExtensionPage'; + +export const QUERY_PARAMS_DASHBOARD = 'dashboard.html'; +export const QUERY_PARAMS_DASHBOARD_TAB = 'tab'; +export const QUERY_PARAMS_DASHBOARD_TAB_SETTINGS = 'settings'; +export const QUERY_PARAMS_BLOCK = 'block.html'; +export const QUERY_PARAMS_BLOCK_DOMAIN = 'domain'; + +export async function usePromoExtension() { + const settingsStorage = injectStorage(); + const extensionPage = useExtensionPage(); + + const hasReviewOnLimits = await settingsStorage.getValue( + StorageParams.PROMO_CLEAR_YOUTUBE_ON_LIMITS, + ); + const hasReviewOnBlock = await settingsStorage.getValue( + StorageParams.PROMO_CLEAR_YOUTUBE_ON_BLOCK, + ); + + const whitelist = Object.values( + await settingsStorage.getValue(StorageParams.RESTRICTION_LIST, []), + ) as Restriction[]; + + const isIncludeYoutube = computed( + () => whitelist.find(x => x.domain == 'youtube.com') != undefined, + ); + + const showOnLimitPage = computed( + () => + (hasReviewOnLimits == undefined || hasReviewOnLimits == false) && + extensionPage.isLimitPage.value && + isIncludeYoutube.value, + ); + const showOnBlockPage = computed( + () => + (hasReviewOnBlock == undefined || hasReviewOnBlock == false) && + extensionPage.isBlockPage.value, + ); + + return showOnLimitPage.value || showOnBlockPage.value; +} diff --git a/src/dashboard.html b/src/dashboard.html new file mode 100644 index 0000000..b0deec1 --- /dev/null +++ b/src/dashboard.html @@ -0,0 +1,17 @@ + + + + + + + Web Activity Time Tracker - Dashboard + + + + + + + + + + diff --git a/src/dashboard.ts b/src/dashboard.ts new file mode 100644 index 0000000..1d55780 --- /dev/null +++ b/src/dashboard.ts @@ -0,0 +1,12 @@ +import Settings from './pages/Dashboard.vue'; +import Notifications from '@kyvg/vue3-notification'; +import VueDatePicker from '@vuepic/vue-datepicker'; +import '@vuepic/vue-datepicker/dist/main.css'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Settings); +app.use(Notifications); +app.use(i18n); +app.component('VueDatePicker', VueDatePicker); +app.mount('body'); diff --git a/src/dto/currentTabItem.ts b/src/dto/currentTabItem.ts new file mode 100644 index 0000000..eeed770 --- /dev/null +++ b/src/dto/currentTabItem.ts @@ -0,0 +1,6 @@ +export interface CurrentTabItem { + url: string; + favicon: string | undefined; + summaryTime: number; + sessions: number; +} diff --git a/src/dto/daySummary.ts b/src/dto/daySummary.ts new file mode 100644 index 0000000..29c136e --- /dev/null +++ b/src/dto/daySummary.ts @@ -0,0 +1,7 @@ +export type DaySummary = { + time: number | undefined; + timeYesterDay: number | undefined; + percentageFromYesterday: string | undefined; + mostVisitedSite: string | undefined; + mostVisitedSiteTime: number | undefined; +}; diff --git a/src/dto/tabListSummary.ts b/src/dto/tabListSummary.ts new file mode 100644 index 0000000..400fa39 --- /dev/null +++ b/src/dto/tabListSummary.ts @@ -0,0 +1,44 @@ +import { Tab } from '../entity/tab'; +import { CurrentTabItem } from './currentTabItem'; + +export interface OverallStats extends TabListSummary { + firstDay: Date; + activeDaysTotal: number; + daysTotal: number; + todaySummaryTime: number; + averageTimeByActiveDays: number; + mostActiveDay: ActiveDay; + mostInactiveDay: ActiveDay; + mostActiveDayExceptToday: ActiveDay | null; + mostInactiveDayExceptToday: ActiveDay | null; +} + +export interface ActiveDay { + date: Date; + summaryTime: number; +} + +export interface TabListSummary { + tabs: Tab[]; + summaryTime: number; + chart: DataForChart; +} + +export interface DataForChart { + timeForChart: number[]; + sitesForChart: string[]; +} + +export interface TabListByDays { + days: DayTabs[]; + averageTime: number; + summaryTime: number; + sessions: number; +} + +export interface DayTabs { + day: string; + tabs: CurrentTabItem[]; + time: number; + sessions: number; +} diff --git a/src/entity/baseTimeList.ts b/src/entity/baseTimeList.ts new file mode 100644 index 0000000..42dfe28 --- /dev/null +++ b/src/entity/baseTimeList.ts @@ -0,0 +1,4 @@ +export interface BaseTimeList { + domain: string; + time: number; +} diff --git a/src/entity/deffering.ts b/src/entity/deffering.ts new file mode 100644 index 0000000..0e58c8e --- /dev/null +++ b/src/entity/deffering.ts @@ -0,0 +1,12 @@ +import { MINUTE } from '../utils/time'; +import { BaseTimeList } from './baseTimeList'; + +export class Deffering implements BaseTimeList { + domain: string; + time: number; + + constructor(domain: string, minutes: number) { + this.domain = domain; + this.time = Date.now() + minutes * MINUTE; + } +} diff --git a/src/entity/notification.ts b/src/entity/notification.ts new file mode 100644 index 0000000..c3ab1d2 --- /dev/null +++ b/src/entity/notification.ts @@ -0,0 +1,12 @@ +import { convertHHMMToSeconds } from '../utils/converter'; +import { BaseTimeList } from './baseTimeList'; + +export class Notifications implements BaseTimeList { + domain: string; + time: number; + + constructor(domain: string, hours: number, minutes: number) { + this.domain = domain; + this.time = convertHHMMToSeconds(hours, minutes); + } +} diff --git a/src/entity/restriction.ts b/src/entity/restriction.ts new file mode 100644 index 0000000..7fe84ae --- /dev/null +++ b/src/entity/restriction.ts @@ -0,0 +1,11 @@ +import { convertHHMMToSeconds } from '../utils/converter'; + +export class Restriction { + domain: string; + time: number; + + constructor(domain: string, hours: number, minutes: number) { + this.domain = domain; + this.time = convertHHMMToSeconds(hours, minutes); + } +} diff --git a/src/entity/tab.ts b/src/entity/tab.ts new file mode 100644 index 0000000..bd674da --- /dev/null +++ b/src/entity/tab.ts @@ -0,0 +1,81 @@ +import { todayLocalDate } from '../utils/date'; +import { logger } from '../utils/logger'; + +export class Tab implements ISerializable { + url: string = ''; + favicon: string | undefined = ''; + summaryTime: number = 0; + counter: number = 0; + days: TabDay[] = []; + + init(url: string) { + this.url = url; + } + + incSummaryTime(): void { + this.summaryTime += 1; + + const day = this.days.find(x => x.date == todayLocalDate()); + if (day === undefined) { + const newTab = this.addNewDay(); + newTab.incSummaryTime(); + } else day.incSummaryTime(); + } + + incCounter(): void { + this.counter += 1; + if (__DEV__) logger.log(`Counter ${this.url} - ${this.counter}`); + const day = this.days.find(x => x.date == todayLocalDate()); + if (day === undefined) { + const newTab = this.addNewDay(); + newTab.incCounter(); + } else day.incCounter(); + } + + addNewDay(): TabDay { + const newTabDay = new TabDay(); + newTabDay.init(todayLocalDate()); + this.days.push(newTabDay); + return newTabDay; + } + + deserialize(input: Tab) { + this.url = input.url; + this.counter = input.counter; + this.favicon = input.favicon; + this.summaryTime = input.summaryTime; + if (input.days?.length > 0) this.days = input.days.map(x => new TabDay().deserialize(x)); + + return this; + } + + setFavicon(favicon: string | undefined) { + this.favicon = favicon; + } +} + +export class TabDay implements ISerializable { + counter: number = 0; + date: string = ''; + summary: number = 0; + + init(date: string) { + this.date = date; + } + + incSummaryTime(): void { + this.summary += 1; + } + + incCounter(): void { + this.counter += 1; + } + + deserialize(input: TabDay): TabDay { + this.counter = input.counter; + this.date = input.date; + this.summary = input.summary; + + return this; + } +} diff --git a/src/entity/time-interval.ts b/src/entity/time-interval.ts new file mode 100644 index 0000000..b002443 --- /dev/null +++ b/src/entity/time-interval.ts @@ -0,0 +1,46 @@ +import { logger } from '../utils/logger'; + +export class TimeInterval implements ISerializable { + domain: string = ''; + intervals: string[] = []; + day: string = ''; + + init(day: string, domain: string) { + this.domain = domain; + this.intervals = []; + this.day = day; + } + + addInterval() { + const stringDate = this.getCurrentStringDate(); + this.intervals.push(stringDate + '-' + stringDate); + logger.log(`Add interval ${this.domain} - ${stringDate} - ${stringDate}`); + } + + closeInterval() { + const stringDate = this.getCurrentStringDate(); + const currentInterval = this.intervals[this.intervals.length - 1]; + if (currentInterval != null) { + if (currentInterval.split('-')[0] == currentInterval.split('-')[1]) { + this.intervals.pop(); + this.intervals.push(currentInterval.split('-')[0] + '-' + stringDate); + logger.log( + `Close interval ${this.domain} - ${currentInterval.split('-')[0]} - ${stringDate}`, + ); + } + } + } + + deserialize(input: TimeInterval): TimeInterval { + this.domain = input.domain; + this.day = input.day; + this.intervals = input.intervals; + + return this; + } + + private getCurrentStringDate(): string { + const date = new Date(); + return date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); + } +} diff --git a/src/functions/black-list.ts b/src/functions/black-list.ts new file mode 100644 index 0000000..a06d188 --- /dev/null +++ b/src/functions/black-list.ts @@ -0,0 +1,10 @@ +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { extractHostname } from '../utils/extract-hostname'; +import { Settings } from './settings'; + +export async function isInBlackList(url: string): Promise { + const blackList = (await Settings.getInstance().getSetting(StorageParams.BLACK_LIST)) as string[]; + const array = Object.values(blackList); + return array?.find(x => isDomainEquals(extractHostname(x), extractHostname(url))) !== undefined; +} diff --git a/src/functions/current-tab.ts b/src/functions/current-tab.ts new file mode 100644 index 0000000..079be59 --- /dev/null +++ b/src/functions/current-tab.ts @@ -0,0 +1,8 @@ +import Browser from 'webextension-polyfill'; + +export async function getCurrentTab() { + const tabs = await Browser.tabs.query({ active: true, currentWindow: true }); + // since only one tab should be active and in the current window at once + // the return variable should only have one entry + return tabs[0]; +} diff --git a/src/functions/deferList.ts b/src/functions/deferList.ts new file mode 100644 index 0000000..8bd60b3 --- /dev/null +++ b/src/functions/deferList.ts @@ -0,0 +1,41 @@ +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { Settings } from './settings'; +import { Deffering } from '../entity/deffering'; +import { injectStorage } from '../storage/inject-storage'; +import { MINUTE } from '../utils/time'; +import { log } from '../utils/logger'; +import { millisecondsInHour } from 'date-fns'; + +export async function isInDeferList(url: string): Promise { + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) log(`Deferring time ${url} ${new Date(item.time)}`); + return item != undefined && item.time > Date.now(); +} + +export async function canDefering(url: string): Promise { + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) log(`Deferring time ${url} ${new Date(item.time)}`); + if (item == undefined) return true; + + return item != undefined && Date.now() - new Date(item.time).getTime() > millisecondsInHour * 24; +} + +export async function defering(url: string, timeInMinutes: number): Promise { + const settingsStorage = injectStorage(); + + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) item.time = Date.now() + timeInMinutes * MINUTE; + else deferList.push(new Deffering(url, 5)); + + await settingsStorage.saveValue(StorageParams.BLOCK_DEFERRAL_TIME, deferList); +} diff --git a/src/functions/limit-list.ts b/src/functions/limit-list.ts new file mode 100644 index 0000000..9286ec1 --- /dev/null +++ b/src/functions/limit-list.ts @@ -0,0 +1,55 @@ +import { Restriction } from '../entity/restriction'; +import { Tab } from '../entity/tab'; +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { todayLocalDate } from '../utils/date'; +import { isInDeferList } from './deferList'; +import { log } from '../utils/logger'; +import { Settings } from './settings'; + +export type LimitExceed = { + IsLimitExceeded: boolean; + LimitTime: number | null; +}; + +export async function isLimitExceeded(url: string, tab: Tab): Promise { + const limitList = (await Settings.getInstance().getSetting( + StorageParams.RESTRICTION_LIST, + )) as Restriction[]; + const array = Object.values(limitList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) { + const date = tab.days.find(x => x.date == todayLocalDate()); + if (date != undefined) { + if (date.summary >= item.time) { + log(`Limit Exceeded: website ${url} limit ${item.time} summary time ${date.summary}`); + if (await isInDeferList(url)) { + log(`Page ${url} is in deffering list`); + return { + IsLimitExceeded: false, + LimitTime: null, + }; + } + + return { + IsLimitExceeded: true, + LimitTime: item.time, + }; + } + } + } + + return { + IsLimitExceeded: false, + LimitTime: null, + }; +} + +export async function isDomainInLimits(url: string): Promise { + const limitList = (await Settings.getInstance().getSetting( + StorageParams.RESTRICTION_LIST, + )) as Restriction[]; + const array = Object.values(limitList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + return item != undefined; +} diff --git a/src/functions/playSound.ts b/src/functions/playSound.ts new file mode 100644 index 0000000..61eb7f2 --- /dev/null +++ b/src/functions/playSound.ts @@ -0,0 +1,7 @@ +import Browser from 'webextension-polyfill'; +import { PomodoroSounds } from '../utils/pomodoro'; + +export function playSound(sound: PomodoroSounds) { + const myAudio = new Audio(Browser.runtime.getURL(`assets/pomodoro-sounds/${sound}`)); + myAudio.play(); +} diff --git a/src/functions/pomodoro.ts b/src/functions/pomodoro.ts new file mode 100644 index 0000000..7a1764e --- /dev/null +++ b/src/functions/pomodoro.ts @@ -0,0 +1,145 @@ +import { addSeconds } from 'date-fns'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams } from '../storage/storage-params'; +import { useBadge, BadgeIcon, BadgeColor } from './useBadge'; +import { Settings } from './settings'; +import Browser from 'webextension-polyfill'; +import { logger } from '../utils/logger'; +import { Messages } from '../utils/messages'; +import { isDateEqual } from '../utils/date'; +import { createOffscreen } from '../offscreen/index'; + +export async function checkPomodoro() { + type PomodoroPeriod = { + period: Period; + isTargetPeriod: boolean; + isTargetPeriodFinishedNow: boolean; + }; + + enum Period { + work = 'WORK', + rest = 'REST', + finished = 'FINISH', + } + + function isTargetPeriod(period: Period): PomodoroPeriod { + let isPomodoroTargetPeriodEnd; + for (let index = 1; index <= frequency; index++) { + let ind = period == Period.work ? index - 1 : index; + const plusWorkingTime = workTime * ind; + const plusRestTime = (restTime + 1) * (index - 1); + const isPomodoroTargetPeriodStart = addSeconds(startTime, plusWorkingTime + plusRestTime); + isPomodoroTargetPeriodEnd = addSeconds(startTime, plusWorkingTime + plusRestTime + workTime); + const isTargetPeriod = + now >= isPomodoroTargetPeriodStart && + (addSeconds(now, -1) <= isPomodoroTargetPeriodEnd || now <= isPomodoroTargetPeriodEnd); + + if (isTargetPeriod) { + return { + period: period, + isTargetPeriod: isTargetPeriod, + isTargetPeriodFinishedNow: + isDateEqual(addSeconds(now, -1), isPomodoroTargetPeriodEnd) || + isDateEqual(now, isPomodoroTargetPeriodEnd), + }; + } + } + return { + period: Period.finished, + isTargetPeriod: false, + isTargetPeriodFinishedNow: false, + }; + } + + async function play(period: Period) { + function getSound() { + switch (period) { + case Period.work: + return StorageParams.POMODORO_AUDIO_AFTER_WORK; + case Period.rest: + return StorageParams.POMODORO_AUDIO_AFTER_REST; + case Period.finished: + return StorageParams.POMODORO_AUDIO_AFTER_FINISHED; + } + } + logger.log(`[Pomodoro] ${period}`); + const sound = await storage.getValue(getSound()); + await createOffscreen(); + await Browser.runtime.sendMessage({ + message: Messages.PlayAudio, + sound: sound, + offscreen: true, + }); + } + + const storage = injectStorage(); + const isPomodoroEnabled = (await Settings.getInstance().getSetting( + StorageParams.IS_POMODORO_ENABLED, + )) as boolean; + + if (!isPomodoroEnabled) return; + + const startTime = new Date( + (await Settings.getInstance().getSetting(StorageParams.POMODORO_START_TIME)) as string, + ); + const workTime = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_INTERVAL_WORK, + )) as number; + const restTime = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_INTERVAL_REST, + )) as number; + const frequency = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_FREQUENCY, + )) as number; + + const now = new Date(); + + const pomodoroEndTime = addSeconds(startTime, workTime * frequency + restTime * frequency); + + const activeTab = await Browser.tabs.query({ active: true }); + + if (now >= pomodoroEndTime) { + if (isDateEqual(now, pomodoroEndTime)) { + logger.log(`[Pomodoro] Pomodoro finished`); + await play(Period.finished); + } + + await storage.saveValue(StorageParams.IS_POMODORO_ENABLED, false); + await storage.saveValue(StorageParams.POMODORO_START_TIME, null); + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.default, + }); + return; + } + + let target = isTargetPeriod(Period.work); + const isWork = target.isTargetPeriod; + + if (isWork) { + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.pomodoroWorkingTime, + }); + } else { + target = isTargetPeriod(Period.rest); + if (target.isTargetPeriod) { + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.pomodoroRestTime, + }); + } + } + + if (target.isTargetPeriodFinishedNow) await play(target.period); + + return { + isWork, + }; +} diff --git a/src/functions/settings.ts b/src/functions/settings.ts new file mode 100644 index 0000000..1266c1e --- /dev/null +++ b/src/functions/settings.ts @@ -0,0 +1,34 @@ +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams, getDefaultValue } from '../storage/storage-params'; + +export class Settings { + private static instance: Settings; + private _settings = new Map(); + + constructor() { + if (Settings.instance) { + throw new Error('Error - use Settings.getInstance()'); + } + } + + static getInstance(): Settings { + Settings.instance = Settings.instance || new Settings(); + return Settings.instance; + } + + async getSetting(param: StorageParams) { + if (this._settings.has(param)) return this._settings.get(param); + else return await this.getValue(param); + } + + async reloadSetting(param: StorageParams) { + await this.getValue(param); + } + + private async getValue(param: StorageParams) { + const storage = injectStorage(); + const value = await storage.getValue(param, getDefaultValue(param)); + this._settings.set(param, value); + return value; + } +} diff --git a/src/functions/useAllTabListSummary.ts b/src/functions/useAllTabListSummary.ts new file mode 100644 index 0000000..aee301b --- /dev/null +++ b/src/functions/useAllTabListSummary.ts @@ -0,0 +1,146 @@ +import { ActiveDay, OverallStats } from '../dto/tabListSummary'; +import { Tab, TabDay } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { SortingBy } from '../utils/enums'; +import { daysBetween } from '../utils/time'; +import { todayLocalDate } from '../utils/date'; + +export async function useAllTabListSummary(sortingBy: SortingBy): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTabs(); + let tabs: Tab[] = []; + + if (unSortedTabs.length == 0) return null; + const todayTabs = unSortedTabs?.filter(x => x.days.find(s => s.date === todayLocalDate())); + + const summaryTimeListForToday = todayTabs.map(function (tab) { + return tab.days.find(day => day.date === todayLocalDate())!.summary; + }); + + const todaySummaryTime = + summaryTimeListForToday != undefined && summaryTimeListForToday.length > 0 + ? summaryTimeListForToday.reduce(function (a, b) { + return a + b; + }) + : 0; + + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return b.summaryTime - a.summaryTime; + }); + + let days: TabDay[] = []; + tabs.map(function (tab) { + return tab.days.forEach(function (day) { + const existDay = days.find(x => x.date == day.date); + if (!existDay) days.push(day); + else { + existDay.summary += day.summary; + existDay.counter += day.counter; + } + }); + }); + + days = days.sort(function (a, b) { + return new Date(a.date).valueOf() - new Date(b.date).valueOf(); + }); + + const mostDayExceptToday = fillMostListWithoutToday(days); + + const firstDay = new Date(days[0].date); + const activeDaysTotal = days.length; + + if (sortingBy == SortingBy.Sessions) + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return b.counter - a.counter; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.summaryTime; + }); + const siteList = tabs?.map(function (tab) { + return tab.url; + }); + const timeForChart = summaryTimeList?.slice(0, 10); + const sitesForChart = siteList?.slice(0, 10); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + + const averageTimeByActiveDays = Math.round(summaryTime / activeDaysTotal); + const daysTotal = daysBetween(firstDay, new Date(days[days.length - 1].date)); + + const mostDay = fillMostList(days); + + return { + firstDay: firstDay, + daysTotal: daysTotal, + activeDaysTotal: activeDaysTotal, + todaySummaryTime: todaySummaryTime, + averageTimeByActiveDays: averageTimeByActiveDays, + mostActiveDay: mostDay.mostActiveDayObj, + mostInactiveDay: mostDay.mostInactiveDayObj, + mostActiveDayExceptToday: + mostDayExceptToday != null ? mostDayExceptToday.mostActiveDayObjExceptToday : null, + mostInactiveDayExceptToday: + mostDayExceptToday != null ? mostDayExceptToday.mostInactiveDayObjExceptToday : null, + tabs: tabs, + summaryTime: summaryTime, + chart: { + timeForChart, + sitesForChart, + }, + }; +} + +function fillMostDay(mostDat: TabDay): ActiveDay { + return { + date: new Date(mostDat.date), + summaryTime: mostDat.summary, + }; +} + +function fillMostListWithoutToday(days: TabDay[]) { + const daysWithoutToday = days + .filter(x => x.date != todayLocalDate()) + .sort(function (a, b) { + return new Date(a.date).valueOf() - new Date(b.date).valueOf(); + }); + + const sortedByTimeDaysWithoutToday = daysWithoutToday.sort(function (a, b) { + return a.summary - b.summary; + }); + + if (sortedByTimeDaysWithoutToday.length == 0) return null; + const mostActiveDayExceptToday = + sortedByTimeDaysWithoutToday[sortedByTimeDaysWithoutToday.length - 1]; + const mostActiveDayObjExceptToday = fillMostDay(mostActiveDayExceptToday); + + const mostInactiveDayExceptToday = sortedByTimeDaysWithoutToday[0]; + const mostInactiveDayObjExceptToday = fillMostDay(mostInactiveDayExceptToday); + + return { + mostActiveDayObjExceptToday, + mostInactiveDayObjExceptToday, + }; +} + +function fillMostList(days: TabDay[]) { + const sortedByTimeDays = days.sort(function (a, b) { + return a.summary - b.summary; + }); + + const mostActiveDay = sortedByTimeDays[sortedByTimeDays.length - 1]; + const mostActiveDayObj = fillMostDay(mostActiveDay); + + const mostInactiveDay = sortedByTimeDays[0]; + const mostInactiveDayObj = fillMostDay(mostInactiveDay); + + return { + mostActiveDayObj, + mostInactiveDayObj, + }; +} diff --git a/src/functions/useBadge.ts b/src/functions/useBadge.ts new file mode 100644 index 0000000..8854b25 --- /dev/null +++ b/src/functions/useBadge.ts @@ -0,0 +1,42 @@ +import Browser from 'webextension-polyfill'; + +export interface BadgeState { + text: string | null; + color: BadgeColor; + tabId?: number; + icon?: BadgeIcon; +} + +export enum BadgeIcon { + default = '/128x128.png', + pomodoroWorkingTime = '/assets/icons/pomodoro.png', + pomodoroRestTime = '/assets/icons/pomodoro-rest.png', +} + +export enum BadgeColor { + red = '#fdb8b8', + green = '#6ec05e', + blue = '#1a73e8', + none = '#000', +} + +export async function useBadge(badge: BadgeState): Promise { + if (badge.color != BadgeColor.none) + await Browser.action.setBadgeBackgroundColor({ color: badge.color }); + await Browser.action.setBadgeText({ + tabId: badge.tabId, + text: badge.text, + }); + if (badge.icon) { + await Browser.action.setIcon({ + path: badge.icon, + }); + await Browser.action.setBadgeText({ + tabId: badge.tabId, + text: badge.text, + }); + } else + await Browser.action.setIcon({ + path: BadgeIcon.default, + }); +} diff --git a/src/functions/useBlockPage.ts b/src/functions/useBlockPage.ts new file mode 100644 index 0000000..e209d7c --- /dev/null +++ b/src/functions/useBlockPage.ts @@ -0,0 +1,21 @@ +import Browser from 'webextension-polyfill'; +import { buildBlockQuery } from '../utils/block-page'; +import { NO_FAVICON } from '../utils/consts'; + +export async function useBlockPage( + domain: string, + url: string, + limitTime: number, + summaryCounter: number, + favIconUrl: string | undefined, +): Promise { + const favicon = + favIconUrl == undefined || favIconUrl == '' || favIconUrl.startsWith('chrome://favicon/') + ? NO_FAVICON + : favIconUrl; + const blockUrl = + Browser.runtime.getURL('src/block.html') + + buildBlockQuery(domain, url, limitTime, summaryCounter, favicon); + const tab = await Browser.tabs.query({ currentWindow: true, active: true }); + await Browser.tabs.update(tab[0].id, { url: blockUrl }); +} diff --git a/src/functions/useDailyIntervals.ts b/src/functions/useDailyIntervals.ts new file mode 100644 index 0000000..534c9e6 --- /dev/null +++ b/src/functions/useDailyIntervals.ts @@ -0,0 +1,48 @@ +import { TimeInterval } from '../entity/time-interval'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageDeserializeParam } from '../storage/storage-params'; +import { todayLocalDate } from '../utils/date'; + +export async function useDailyIntervals() { + async function closeInterval(domain: string | null): Promise { + if (domain == null) return; + const storage = injectStorage(); + const timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + const item = timeIntervalList?.find(x => x.domain === domain && x.day == todayLocalDate()); + item?.closeInterval(); + await storage.saveIntervalList(timeIntervalList); + } + + async function addInterval(domain: string | null): Promise { + if (domain == null) return; + + const storage = injectStorage(); + let timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + if (timeIntervalList == undefined) timeIntervalList = []; + const item = timeIntervalList?.find(x => x.domain === domain && x.day == todayLocalDate()); + if (item != undefined) { + if (item.day == todayLocalDate()) item.addInterval(); + else { + const newInterval = new TimeInterval(); + newInterval.init(todayLocalDate(), domain); + newInterval.addInterval(); + timeIntervalList.push(newInterval); + } + } else { + const newInterval = new TimeInterval(); + newInterval.init(todayLocalDate(), domain); + newInterval.addInterval(); + timeIntervalList.push(newInterval); + } + await storage.saveIntervalList(timeIntervalList); + } + + return { + closeInterval, + addInterval, + }; +} diff --git a/src/functions/useFile.ts b/src/functions/useFile.ts new file mode 100644 index 0000000..cf18b01 --- /dev/null +++ b/src/functions/useFile.ts @@ -0,0 +1,15 @@ +export enum FileType { + CSV = 'text/csv', + JSON = 'application/json', +} + +export function useFile(data: string, type: FileType, fileName: string) { + const file = new Blob([data], { type: type }); + let downloadLink; + downloadLink = document.createElement('a'); + downloadLink.download = fileName; + downloadLink.href = window.URL.createObjectURL(file); + downloadLink.style.display = 'none'; + document.body.appendChild(downloadLink); + downloadLink.click(); +} diff --git a/src/functions/useImportToCsv.ts b/src/functions/useImportToCsv.ts new file mode 100644 index 0000000..71c3412 --- /dev/null +++ b/src/functions/useImportToCsv.ts @@ -0,0 +1,35 @@ +import { DayTabs } from '../dto/tabListSummary'; +import { useTabListByDays } from './useTabListByDays'; + +const CSV_HEADER = 'Date,WebSite,Time(sec),Sessions\r\n'; + +export async function useImportToCsvWithData(days: DayTabs[] | undefined): Promise { + return getCsv(days); +} + +export async function useImportToCsv(dateFrom: Date, dateTo: Date): Promise { + const summary = await useTabListByDays(dateFrom, dateTo); + if (summary == null) return CSV_HEADER; + + return getCsv(summary.days); +} + +function getCsv(days: DayTabs[] | undefined) { + let str = CSV_HEADER; + + if (days != undefined && days.length > 0) { + days.forEach(day => { + let newLine = ''; + day.tabs.forEach(tab => { + newLine += day.day + ','; + newLine += tab.url + ','; + newLine += tab.summaryTime + ','; + newLine += tab.sessions; + newLine += '\r\n'; + }); + str += newLine + '\r\n'; + }); + } + + return str; +} diff --git a/src/functions/useNotification.ts b/src/functions/useNotification.ts new file mode 100644 index 0000000..8ccba80 --- /dev/null +++ b/src/functions/useNotification.ts @@ -0,0 +1,23 @@ +import Browser from 'webextension-polyfill'; +import { SECOND } from '../utils/time'; + +export enum NotificationType { + DailySummaryNotification = 'daily-summary-notification', + WebSiteNotification = 'website-notification', +} + +export async function useNotification( + notificationType: NotificationType, + title: string, + message: string, +): Promise { + await Browser.notifications.clear(notificationType); + await new Promise(res => setTimeout(res, 3 * SECOND)); + return Browser.notifications.create(notificationType, { + type: 'basic', + title: title, + message: message, + iconUrl: Browser.runtime.getURL('128x128.png'), + isClickable: false, + }); +} diff --git a/src/functions/useNotificationList.ts b/src/functions/useNotificationList.ts new file mode 100644 index 0000000..c4eb402 --- /dev/null +++ b/src/functions/useNotificationList.ts @@ -0,0 +1,49 @@ +import { Notifications } from '../entity/notification'; +import { Tab } from '../entity/tab'; +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { todayLocalDate } from '../utils/date'; +import { log } from '../utils/logger'; +import { Settings } from './settings'; + +export type LimitExceed = { + IsLimitExceeded: boolean; + LimitTime: number | null; +}; + +export function useNotificationList() { + async function isNeedToShowNotification(url: string, tab: Tab): Promise { + const notificationList = (await Settings.getInstance().getSetting( + StorageParams.NOTIFICATION_LIST, + )) as Notifications[]; + const array = Object.values(notificationList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) { + const date = tab.days.find(x => x.date == todayLocalDate()); + if (date != undefined) { + if (date.summary != 0 && (date.summary == item.time || date.summary % item.time == 0)) { + log( + `Time for notification: website ${url} time ${item.time} summary time ${date.summary}`, + ); + return true; + } + } + } + + return false; + } + + async function isDomainInNotificationsLimit(url: string): Promise { + const notificationList = (await Settings.getInstance().getSetting( + StorageParams.NOTIFICATION_LIST, + )) as Notifications[]; + const array = Object.values(notificationList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + return item != undefined; + } + + return { + isNeedToShowNotification, + isDomainInNotificationsLimit, + }; +} diff --git a/src/functions/useRemoveAllData.ts b/src/functions/useRemoveAllData.ts new file mode 100644 index 0000000..99809ec --- /dev/null +++ b/src/functions/useRemoveAllData.ts @@ -0,0 +1,9 @@ +import Browser from 'webextension-polyfill'; +import { injectStorage } from '../storage/inject-storage'; +import { Messages } from '../utils/messages'; + +export async function useRemoveAllData() { + const storage = injectStorage(); + await storage.saveIntervalList([]); + await Browser.runtime.sendMessage(Messages.ClearAllData); +} diff --git a/src/functions/useRestoreData.ts b/src/functions/useRestoreData.ts new file mode 100644 index 0000000..fe01044 --- /dev/null +++ b/src/functions/useRestoreData.ts @@ -0,0 +1,12 @@ +import Browser from 'webextension-polyfill'; +import { Messages } from '../utils/messages'; + +export async function useRestoreData(json: string) { + if (json != null && json != undefined && json != '') { + const data = JSON.parse(json); + await Browser.runtime.sendMessage({ + message: Messages.Restore, + data: data, + }); + } +} diff --git a/src/functions/useTabListByDays.ts b/src/functions/useTabListByDays.ts new file mode 100644 index 0000000..0e8525c --- /dev/null +++ b/src/functions/useTabListByDays.ts @@ -0,0 +1,97 @@ +import { CurrentTabItem } from '../dto/currentTabItem'; +import { DayTabs, TabListByDays } from '../dto/tabListSummary'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { isSameDay } from 'date-fns'; + +export async function useTabListByDays( + dateFrom: Date, + dateTo: Date, +): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTabs(); + let daysTabs: DayTabs[] = []; + + if (unSortedTabs.length == 0) return null; + + const isTheSameDay = isSameDay(dateFrom, dateTo); + + const unSortedTabsByDays = unSortedTabs.filter(x => + isTheSameDay + ? x.days.find(s => isSameDay(new Date(s.date), dateFrom)) != undefined + : x.days.find(s => new Date(s.date) >= dateFrom && new Date(s.date) <= dateTo) != undefined, + ); + + if (unSortedTabsByDays.length == 0) + return { + days: [], + averageTime: 0, + summaryTime: 0, + sessions: 0, + }; + + unSortedTabsByDays.forEach(tab => { + tab.days.forEach(day => { + if ( + (new Date(day.date) >= dateFrom && new Date(day.date) <= dateTo) || + (isTheSameDay && isSameDay(new Date(day.date), dateFrom)) + ) { + let dayTab = daysTabs.find(x => x.day == day.date); + if (dayTab == undefined) { + dayTab = { + day: day.date, + tabs: [], + time: day.summary, + sessions: day.counter, + }; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: day.counter, + summaryTime: day.summary, + }); + daysTabs.push(dayTab); + } else { + dayTab.time += day.summary; + dayTab.sessions += day.counter; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: day.counter, + summaryTime: day.summary, + }); + } + } + }); + }); + + daysTabs.sort(function (a, b) { + return new Date(a.day).valueOf() - new Date(b.day).valueOf(); + }); + + daysTabs.forEach(dayTab => { + dayTab.tabs.sort(function (a: CurrentTabItem, b: CurrentTabItem) { + return b.summaryTime - a.summaryTime; + }); + }); + + const summaryTime = daysTabs + .map(x => x.time) + .reduce(function (a, b) { + return a + b; + }); + + const totalSessions = daysTabs + .map(x => x.sessions) + .reduce(function (a, b) { + return a + b; + }); + + const averageTime = Math.round(summaryTime / daysTabs.length); + + return { + days: daysTabs, + summaryTime: summaryTime, + averageTime: averageTime, + sessions: totalSessions, + }; +} diff --git a/src/functions/useTabStatsByDays.ts b/src/functions/useTabStatsByDays.ts new file mode 100644 index 0000000..e85b03a --- /dev/null +++ b/src/functions/useTabStatsByDays.ts @@ -0,0 +1,94 @@ +import { CurrentTabItem } from '../dto/currentTabItem'; +import { DayTabs, TabListByDays } from '../dto/tabListSummary'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { isSameDay } from 'date-fns'; + +export async function useTabStatsByDays( + dateFrom: Date, + dateTo: Date, + domain: string, +): Promise { + const repo = await injectTabsRepository(); + const tab = repo.getTab(domain); + let daysTabs: DayTabs[] = []; + + if (tab == undefined) return null; + + const isTheSameDay = isSameDay(dateFrom, dateTo); + + const unSortedTabsByDays = isTheSameDay + ? tab.days.filter(s => isSameDay(new Date(s.date), dateFrom)) + : tab.days.filter(s => new Date(s.date) >= dateFrom && new Date(s.date) <= dateTo); + + if (unSortedTabsByDays.length == 0) + return { + days: [], + averageTime: 0, + summaryTime: 0, + sessions: 0, + }; + + unSortedTabsByDays.forEach(tabDay => { + if ( + (new Date(tabDay.date) >= dateFrom && new Date(tabDay.date) <= dateTo) || + (isTheSameDay && isSameDay(new Date(tabDay.date), dateFrom)) + ) { + let dayTab = daysTabs.find(x => x.day == tabDay.date); + if (dayTab == undefined) { + dayTab = { + day: tabDay.date, + tabs: [], + time: tabDay.summary, + sessions: tabDay.counter, + }; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: tabDay.counter, + summaryTime: tabDay.summary, + }); + daysTabs.push(dayTab); + } else { + dayTab.time += tabDay.summary; + dayTab.sessions += tabDay.counter; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: tabDay.counter, + summaryTime: tabDay.summary, + }); + } + } + }); + + daysTabs.sort(function (a, b) { + return new Date(a.day).valueOf() - new Date(b.day).valueOf(); + }); + + daysTabs.forEach(dayTab => { + dayTab.tabs.sort(function (a: CurrentTabItem, b: CurrentTabItem) { + return b.summaryTime - a.summaryTime; + }); + }); + + const summaryTime = daysTabs + .map(x => x.time) + .reduce(function (a, b) { + return a + b; + }); + + const totalSessions = daysTabs + .map(x => x.sessions) + .reduce(function (a, b) { + return a + b; + }); + + const averageTime = Math.round(summaryTime / daysTabs.length); + + return { + days: daysTabs, + summaryTime: summaryTime, + averageTime: averageTime, + sessions: totalSessions, + }; +} diff --git a/src/functions/useTodayTabListSummary.ts b/src/functions/useTodayTabListSummary.ts new file mode 100644 index 0000000..fcd6afd --- /dev/null +++ b/src/functions/useTodayTabListSummary.ts @@ -0,0 +1,47 @@ +import { TabListSummary } from '../dto/tabListSummary'; +import { Tab } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { SortingBy } from '../utils/enums'; +import { todayLocalDate } from '../utils/date'; + +export async function useTodayTabListSummary(sortingBy: SortingBy): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTodayTabs(); + let tabs: Tab[] = []; + + if (unSortedTabs.length == 0) return null; + + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return sortingBy == SortingBy.UsageTime + ? b.days.find(s => s.date === todayLocalDate())!.summary - + a.days.find(s => s.date === todayLocalDate())!.summary + : b.days.find(s => s.date === todayLocalDate())!.counter - + a.days.find(s => s.date === todayLocalDate())!.counter; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.days.find(day => day.date === todayLocalDate())!.summary; + }); + + const siteList = tabs?.map(function (tab) { + return tab.url; + }); + + const timeForChart = summaryTimeList?.slice(0, 10); + const sitesForChart = siteList?.slice(0, 10); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + return { + tabs, + summaryTime, + chart: { + timeForChart, + sitesForChart, + }, + }; +} diff --git a/src/functions/useWebUsageSummaryForDay.ts b/src/functions/useWebUsageSummaryForDay.ts new file mode 100644 index 0000000..242e0e6 --- /dev/null +++ b/src/functions/useWebUsageSummaryForDay.ts @@ -0,0 +1,63 @@ +import { Tab } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { todayLocalDate } from '../utils/date'; +import { DaySummary } from '../dto/daySummary'; +import { startOfYesterday } from 'date-fns'; +import { getPercentage } from '../utils/common'; +import { ITabsRepository } from '../repository/tabs-repository-interface'; + +export async function useWebUsageSummaryForDay(): Promise { + const repo = await injectTabsRepository(); + + const unSortedTabs = repo.getTabs(); + if (unSortedTabs.length == 0) return null; + + const dataToday = getData(todayLocalDate(), repo); + const dataYesterday = getData(startOfYesterday().toLocaleDateString('en-US'), repo); + + return { + time: dataToday == null ? 0 : dataToday.time, + mostVisitedSite: dataToday?.mostVisitedSite, + mostVisitedSiteTime: dataToday?.mostVisitedSiteTime, + timeYesterDay: dataYesterday == null ? 0 : dataYesterday.time, + percentageFromYesterday: + dataToday == null + ? '0%' + : dataYesterday == null + ? '100%' + : `${getPercentage(dataToday.time, dataYesterday.time)}%`, + }; +} + +function getData(date: string, repo: ITabsRepository) { + const unSortedTabs = repo.getTabs(); + if (unSortedTabs.length == 0) return null; + + const targetTabs = unSortedTabs.filter(x => x.days.find(s => s.date === date)); + if (targetTabs.length == 0) return null; + + const tabs = targetTabs.sort(function (a: Tab, b: Tab) { + return b.days.find(s => s.date === date)!.summary - a.days.find(s => s.date === date)!.summary; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.days.find(day => day.date === date)!.summary; + }); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + + const mostVisitedTab = tabs[0]; + const mostVisitedSite = mostVisitedTab.url; + const mostVisitedSiteTime = mostVisitedTab.days.find(s => s.date === date)?.summary!; + + return { + time: summaryTime, + mostVisitedSite: mostVisitedSite, + mostVisitedSiteTime: mostVisitedSiteTime, + }; +} diff --git a/src/icons/bmc-new-btn-logo.svg b/src/icons/bmc-new-btn-logo.svg deleted file mode 100644 index d7b9b32..0000000 --- a/src/icons/bmc-new-btn-logo.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - \ No newline at end of file diff --git a/src/icons/delete.png b/src/icons/delete.png deleted file mode 100644 index d5160c2..0000000 Binary files a/src/icons/delete.png and /dev/null differ diff --git a/src/icons/edit.png b/src/icons/edit.png deleted file mode 100644 index e80f09d..0000000 Binary files a/src/icons/edit.png and /dev/null differ diff --git a/src/icons/eye.png b/src/icons/eye.png deleted file mode 100644 index 0a358a7..0000000 Binary files a/src/icons/eye.png and /dev/null differ diff --git a/src/icons/heat-map-16.png b/src/icons/heat-map-16.png deleted file mode 100644 index 60afb64..0000000 Binary files a/src/icons/heat-map-16.png and /dev/null differ diff --git a/src/icons/information.svg b/src/icons/information.svg deleted file mode 100644 index 0bd40ae..0000000 --- a/src/icons/information.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/icons/limit.png b/src/icons/limit.png deleted file mode 100644 index b42bb6c..0000000 Binary files a/src/icons/limit.png and /dev/null differ diff --git a/src/icons/no-today.svg b/src/icons/no-today.svg deleted file mode 100644 index 94a6ac5..0000000 --- a/src/icons/no-today.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/icons/pie-chart.png b/src/icons/pie-chart.png deleted file mode 100644 index fa2f378..0000000 Binary files a/src/icons/pie-chart.png and /dev/null differ diff --git a/src/icons/preloader.svg b/src/icons/preloader.svg deleted file mode 100644 index cdd962e..0000000 --- a/src/icons/preloader.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/icons/time.svg b/src/icons/time.svg deleted file mode 100644 index c4f9923..0000000 --- a/src/icons/time.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/index.html b/src/index.html deleted file mode 100644 index fcfc431..0000000 --- a/src/index.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - Web Activity Time Tracker - - - - - -
-
-
Loading...
-
-
- - - - - - - - - - -
-

Web Activity Time Tracker

-
-
- Today - All-time - By days - Settings -
-
-

In Web Activity Time Tracker you can:

-

Set daily limits for sites

-

Set notifications after a certain time has elapsed

-

Set a list of sites with no tracking

-

Enable time tracking on YouTube.com

-

Enable time tracking on Netflix.com

-

Enable dark mode

-
-
-
-

Overall statistics

-
-
-
-
First day
-
-
-
-
Active days
-
-
-
-
Days in total
-
-
-
-
-
-
Today
-
-
-
-
All-time
-
-
-
-
Average by active days
-
-
-
-
-
-
Most active day
Don't include the current day in the calculation of statistics
-
-
-
- -
-
-
-
-
-
Most inactive day
Don't include the current day in the calculation of statistics
-
-
-
- -
-
-
-
-
-
-
- -
-
- -
-
-
-
- - - - - - - - - - - \ No newline at end of file diff --git a/src/jobs/daily-summary-notification.ts b/src/jobs/daily-summary-notification.ts new file mode 100644 index 0000000..d17c449 --- /dev/null +++ b/src/jobs/daily-summary-notification.ts @@ -0,0 +1,34 @@ +import { useWebUsageSummaryForDay } from '../functions/useWebUsageSummaryForDay'; +import { convertLimitTimeToString } from '../utils/converter'; +import { Settings } from '../functions/settings'; +import { StorageParams } from '../storage/storage-params'; +import { NotificationType, useNotification } from '../functions/useNotification'; +import { getMessagesFromLocale } from '../plugins/i18n'; + +export async function dailySummaryNotification() { + const showDailyNotification = (await Settings.getInstance().getSetting( + StorageParams.DAILY_NOTIFICATION, + )) as boolean; + + if (showDailyNotification) { + const data = await useWebUsageSummaryForDay(); + if (data == null) return; + + const title = `${ + getMessagesFromLocale()['todayUsageTime']['message'] + }${convertLimitTimeToString(data.time!)}`; + const messageWithMostVisitedWebsite = + data.mostVisitedSite == undefined + ? '' + : `${data.mostVisitedSite} ${ + getMessagesFromLocale()['mostVisited']['message'] + }${convertLimitTimeToString(data.mostVisitedSiteTime!)}`; + + const message = [ + `${data.percentageFromYesterday}${getMessagesFromLocale()['comparedToYesterday']['message']}`, + messageWithMostVisitedWebsite, + ].join('\n'); + + return await useNotification(NotificationType.DailySummaryNotification, title, message); + } +} diff --git a/src/jobs/remove-time-intervals.ts b/src/jobs/remove-time-intervals.ts new file mode 100644 index 0000000..0fe83cb --- /dev/null +++ b/src/jobs/remove-time-intervals.ts @@ -0,0 +1,23 @@ +import { StorageDeserializeParam } from '../storage/storage-params'; +import { injectStorage } from '../storage/inject-storage'; +import { TimeInterval } from '../entity/time-interval'; +import { todayLocalDate } from '../utils/date'; + +export async function removeOldTimeIntervals() { + const storage = injectStorage(); + let timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + if (timeIntervalList == undefined) timeIntervalList = []; + const arrayToRemove: number[] = []; + timeIntervalList.forEach(interval => { + if (new Date(interval.day) < new Date(todayLocalDate())) + arrayToRemove.push(timeIntervalList.indexOf(interval)); + }); + + arrayToRemove.forEach(index => { + if (index > -1) timeIntervalList.splice(index, 1); + }); + + await storage.saveIntervalList(timeIntervalList); +} diff --git a/src/jobs/sheduler.ts b/src/jobs/sheduler.ts new file mode 100644 index 0000000..43f4204 --- /dev/null +++ b/src/jobs/sheduler.ts @@ -0,0 +1,71 @@ +import Browser, { Alarms } from 'webextension-polyfill'; +import { log } from '../utils/logger'; +import { StorageParams } from '../storage/storage-params'; +import { DAY_MINUTES, SECOND, getNextTimeOfDay } from '../utils/time'; +import { Settings } from '../functions/settings'; +import { dailySummaryNotification } from './daily-summary-notification'; +import { removeOldTimeIntervals } from './remove-time-intervals'; +import { startOfTomorrow } from 'date-fns'; +import { Messages } from '../utils/messages'; + +export enum JobId { + DailySummaryNotification = '@alarm/daily-summary-notification', + RemoveOldTimeIntervals = '@alarm/remove-old-time-intervals', +} + +export function scheduleJobs(): void { + Browser.alarms.onAlarm.addListener(async alarm => { + log(`[schedule-jobs] Alarm ${alarm.name} triggered`, alarm); + switch (alarm.name) { + case JobId.DailySummaryNotification: { + await dailySummaryNotification(); + break; + } + case JobId.RemoveOldTimeIntervals: { + await removeOldTimeIntervals(); + break; + } + } + log(`[schedule-jobs] ${alarm.name} finished`); + }); + + Browser.runtime.onMessage.addListener(message => { + if (message == Messages.RescheduleJobs) rescheduleJobs(); + }); + + rescheduleJobs(); +} + +async function rescheduleJobs(): Promise { + log('Reschedule jobs'); + const dailySummaryNotificationTime = (await Settings.getInstance().getSetting( + StorageParams.DAILY_SUMMARY_NOTIFICATION_TIME, + )) as number; + await Browser.alarms.clear(JobId.DailySummaryNotification); + const nextTime = getNextTimeOfDay(dailySummaryNotificationTime * SECOND); + log(`[schedule-jobs] ${JobId.DailySummaryNotification} start time ${new Date(nextTime)}`); + Browser.alarms.create(JobId.DailySummaryNotification, { + when: nextTime, + periodInMinutes: DAY_MINUTES, + }); + + await createAlarmIfMissing(JobId.RemoveOldTimeIntervals, { + when: startOfTomorrow().getTime(), + periodInMinutes: DAY_MINUTES, + }); +} + +async function createAlarmIfMissing( + name: string, + alarmInfo: Alarms.CreateAlarmInfoType, +): Promise { + const existing = await Browser.alarms.get(name).catch(() => undefined); + if (existing == null) { + log( + `[schedule-jobs] ${name} start time ${ + alarmInfo.when != undefined ? new Date(alarmInfo.when) : null + }`, + ); + Browser.alarms.create(name, alarmInfo); + } +} diff --git a/src/manifest.json b/src/manifest.json index 585195d..64b8888 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,50 +1,37 @@ { - "manifest_version": 2, - - "name": "Web Activity Time Tracker", - "short_name": "Web Time Tracker", - "version": "1.7.2", - "minimum_chrome_version": "26", - - "description": "Track and limit time your activity in the browser every day.", - - "options_page": "options.html", - - "icons": { - "16": "icons/16x16.png", - "32": "icons/32x32.png", - "48": "icons/48x48.png", - "128": "icons/128x128.png" - }, - "permissions": [ - "tabs", - "activeTab", - "storage", - "idle", - "chrome://favicon/*", - "webNavigation", - "unlimitedStorage", - "alarms" - ], - "optional_permissions": [ - "https://www.youtube.com/*", - "https://www.netflix.com/*", - "notifications" - ], - "offline_enabled": true, - "background": { - "scripts": ["scripts/common.js", - "scripts/storage.js", - "scripts/activity.js", - "scripts/tab.js", - "scripts/timeInterval.js", - "scripts/background.js", - "scripts/restriction.js"], - "persistent": false - }, - "browser_action": { - "default_popup": "index.html", - "default_title": "Web Activity Time Tracker", - "default_icon": "icons/48x48.png" - } -} \ No newline at end of file + "manifest_version": 3, + "name": "__MSG_extName__", + "short_name": "Web Tracker", + "version": "2.2.2", + "description": "__MSG_extDescription__", + "options_page": "src/dashboard.html", + "default_locale": "en", + "icons": { + "16": "16x16.png", + "32": "32x32.png", + "48": "48x48.png", + "128": "128x128.png" + }, + "permissions": [ + "tabs", + "activeTab", + "storage", + "idle", + "unlimitedStorage", + "alarms", + "notifications", + "offscreen" + ], + "offline_enabled": true, + "background": { + "service_worker": "src/background.ts" + }, + "action": { + "default_popup": "src/popup.html", + "default_title": "Web Activity Time Tracker" + }, + "web_accessible_resources": [{ + "resources": ["assets/pomodoro-sounds/*.mp3"], + "matches": [""] + }] +} diff --git a/src/offscreen.html b/src/offscreen.html new file mode 100644 index 0000000..9c5de41 --- /dev/null +++ b/src/offscreen.html @@ -0,0 +1,14 @@ + + + + + + + Offscreen + + + + + + + diff --git a/src/offscreen.ts b/src/offscreen.ts new file mode 100644 index 0000000..b4c0574 --- /dev/null +++ b/src/offscreen.ts @@ -0,0 +1,23 @@ +import Browser from 'webextension-polyfill'; +import { Messages } from './utils/messages'; + +console.log('ofscreen'); + +Browser.runtime.onMessage.addListener(msg => { + console.log('ofscreen message'); + if (msg.message == Messages.PlayAudio) { + if (msg.offscreen == undefined) return; + + playAudio(msg.sound); + } +}); + +function playAudio(sound: string) { + const audio = document.querySelector('audio'); + if (!audio) return; + + const path = Browser.runtime.getURL(`../assets/pomodoro-sounds/${sound}`); + audio.src = path; + audio.volume = 1; + audio.play(); +} diff --git a/src/offscreen/index.ts b/src/offscreen/index.ts new file mode 100644 index 0000000..6f8fd85 --- /dev/null +++ b/src/offscreen/index.ts @@ -0,0 +1,12 @@ +import Browser from 'webextension-polyfill'; + +export async function createOffscreen() { + const path = 'src/offscreen.html'; + const offscreenUrl = Browser.runtime.getURL(path); + if (await chrome.offscreen.hasDocument()) return; + await chrome.offscreen.createDocument({ + url: offscreenUrl, + reasons: ['AUDIO_PLAYBACK'], + justification: 'Play audio sounds', + }); +} diff --git a/src/options.html b/src/options.html deleted file mode 100644 index 2a29a13..0000000 --- a/src/options.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - Web Activity Time Tracker - - - - - - - - - - - - -
-
-

Web Activity Time Tracker

-
- -
-
- -
- -
-
- -
-
-
- -
- An activity is an action with a mouse or keyboard -
-
- -
-
-
-
- -
-
-
- -
- Activity for these domains not will tracked -
-
-
    -
    -
    - - -
    - -
    -
    -
    - -
    -
    - -
    -
    - - - - - - - -
    -
    - - - -
    - - - - - -
    - -
    - -
    -
    - - - -
    - -
    - - - -
    -
    -
    - -
    -
    - -
    -
    - - - -
    -
    - - - diff --git a/src/pages/Block.vue b/src/pages/Block.vue new file mode 100644 index 0000000..4355405 --- /dev/null +++ b/src/pages/Block.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/src/pages/Dashboard.vue b/src/pages/Dashboard.vue new file mode 100644 index 0000000..27362cb --- /dev/null +++ b/src/pages/Dashboard.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/src/pages/Popup.vue b/src/pages/Popup.vue new file mode 100644 index 0000000..51d8460 --- /dev/null +++ b/src/pages/Popup.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/src/pages/Welcome.vue b/src/pages/Welcome.vue new file mode 100644 index 0000000..67e57e2 --- /dev/null +++ b/src/pages/Welcome.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts new file mode 100644 index 0000000..dfc5ada --- /dev/null +++ b/src/plugins/i18n.ts @@ -0,0 +1,35 @@ +import { createI18n } from 'vue-i18n'; +import Browser from 'webextension-polyfill'; +import en from '../_locales/en/messages.json'; +import ru from '../_locales/ru/messages.json'; +import de from '../_locales/de/messages.json'; +import zh from '../_locales/zh_CN/messages.json'; +import es from '../_locales/es/messages.json'; +import ja from '../_locales/ja/messages.json'; + +const locales = { + en, + ru, + de, + zh, + es, + ja, +}; + +export type Languages = keyof typeof locales; + +const i18n = createI18n({ + legacy: false, + locale: Browser.i18n.getUILanguage(), + fallbackLocale: 'en', + globalInjection: true, + messages: locales, +}); + +export default i18n; + +export function getMessagesFromLocale() { + let locale = i18n.global.locale.value; + if (Object.keys(locales).indexOf(locale) == -1) locale = 'en'; + return i18n.global.getLocaleMessage(locale); +} diff --git a/src/popup.html b/src/popup.html new file mode 100644 index 0000000..6fa1948 --- /dev/null +++ b/src/popup.html @@ -0,0 +1,17 @@ + + + + + + + Popup + + + + + + + + + + diff --git a/src/popup.ts b/src/popup.ts new file mode 100644 index 0000000..42ccbf5 --- /dev/null +++ b/src/popup.ts @@ -0,0 +1,10 @@ +import Popup from './pages/Popup.vue'; +import VueDatePicker from '@vuepic/vue-datepicker'; +import '@vuepic/vue-datepicker/dist/main.css'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Popup); +app.component('VueDatePicker', VueDatePicker); +app.use(i18n); +app.mount('body'); diff --git a/src/repository/inject-tabs-repository.ts b/src/repository/inject-tabs-repository.ts new file mode 100644 index 0000000..44de742 --- /dev/null +++ b/src/repository/inject-tabs-repository.ts @@ -0,0 +1,21 @@ +import { ITabsRepository } from './tabs-repository-interface'; +import { TabsRepository } from './tabs-repository'; + +let instanse: ITabsRepository | null = null; + +async function createAndInitInstance() { + let repo = new TabsRepository(); + await repo.initAsync(); + return repo; +} + +export async function injectTabsRepositorySingleton(): Promise { + if (instanse == null) { + instanse = await createAndInitInstance(); + } + return instanse; +} + +export async function injectTabsRepository(): Promise { + return createAndInitInstance(); +} diff --git a/src/repository/tabs-repository-interface.ts b/src/repository/tabs-repository-interface.ts new file mode 100644 index 0000000..9f708c7 --- /dev/null +++ b/src/repository/tabs-repository-interface.ts @@ -0,0 +1,10 @@ +import { Tab } from '../entity/tab'; + +export interface ITabsRepository { + initAsync(): void; + getTabs(): Tab[]; + removeAllTabs(): void; + getTodayTabs(): Tab[]; + getTab(domain: string): Tab | undefined; + addTab(domain: string): Promise; +} diff --git a/src/repository/tabs-repository.ts b/src/repository/tabs-repository.ts new file mode 100644 index 0000000..740dd13 --- /dev/null +++ b/src/repository/tabs-repository.ts @@ -0,0 +1,48 @@ +import { ITabsRepository } from './tabs-repository-interface'; +import { Tab } from '../entity/tab'; +import { injectStorage } from '../storage/inject-storage'; +import { isInBlackList } from '../functions/black-list'; +import { StorageDeserializeParam } from '../storage/storage-params'; +import { todayLocalDate } from '../utils/date'; + +export class TabsRepository implements ITabsRepository { + private tabs: Tab[]; + + constructor() { + this.tabs = []; + } + + async initAsync() { + this.tabs = (await injectStorage().getDeserializeList(StorageDeserializeParam.TABS)) as Tab[]; + } + + getTabs(): Tab[] { + return this.tabs; + } + + removeAllTabs(): void { + this.tabs = []; + } + + getTodayTabs(): Tab[] { + return this.tabs.filter(x => x.days.find(s => s.date === todayLocalDate())); + } + + getTab(domain: string): Tab | undefined { + return this.tabs?.find(x => x.url === domain); + } + + async addTab(domain: string): Promise { + const tabFromStorage = this.getTab(domain); + const isInBlackListFlag = await isInBlackList(domain); + + if (!isInBlackListFlag && !tabFromStorage) { + const newTab = new Tab(); + newTab.init(domain); + this.tabs.push(newTab); + return newTab; + } + + return undefined; + } +} diff --git a/src/scripts/activity.js b/src/scripts/activity.js deleted file mode 100644 index 920513c..0000000 --- a/src/scripts/activity.js +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; - -class Activity { - addTab(tab) { - if (this.isValidPage(tab) === true) { - if (tab.id && (tab.id != 0)) { - tabs = tabs || []; - var domain = extractHostname(tab.url); - var isDifferentUrl = false; - if (currentTab !== tab.url) { - isDifferentUrl = true; - } - - if (this.isNewUrl(domain) && !this.isInBlackList(domain)) { - var favicon = tab.favIconUrl; - if (favicon === undefined) { - favicon = 'chrome://favicon/' + domain; - } - var newTab = new Tab(domain, favicon); - tabs.push(newTab); - } - - if (isDifferentUrl && !this.isInBlackList(domain)) { - this.setCurrentActiveTab(domain); - var tabUrl = this.getTab(domain); - if (tabUrl !== undefined) - tabUrl.incCounter(); - this.addTimeInterval(domain); - } - } - } else this.closeIntervalForCurrentTab(); - } - - isValidPage(tab) { - if (!tab || !tab.url || (tab.url.indexOf('http:') == -1 && tab.url.indexOf('https:') == -1) - || tab.url.indexOf('chrome://') !== -1 - || tab.url.indexOf('chrome-extension://') !== -1) - return false; - return true; - } - - isInBlackList(domain) { - if (setting_black_list !== undefined && setting_black_list.length > 0) - return setting_black_list.find(o => isDomainEquals(extractHostname(o), extractHostname(domain))) !== undefined; - else return false; - } - - isLimitExceeded(domain, tab) { - if (setting_restriction_list !== undefined && setting_restriction_list.length > 0) { - var item = setting_restriction_list.find(o => isDomainEquals(extractHostname(o.domain), extractHostname(domain))); - if (item !== undefined) { - var data = tab.days.find(x => x.date == todayLocalDate()); - if (data !== undefined) { - var todayTimeUse = data.summary; - if (todayTimeUse >= item.time) { - return true; - } - } - } - } - return false; - } - - wasDeferred(domain){ - if (deferredRestrictionsList != undefined){ - let defItem = deferredRestrictionsList.find(x => extractHostname(x.site) == extractHostname(domain)); - if (defItem != null){ - let time = defItem.dateOfDeferred; - if (time + DEFERRED_TIMEOUT > new Date().getTime()){ - return true; - } - else { - let index = deferredRestrictionsList.indexOf(defItem); - if (index > -1) - deferredRestrictionsList.splice(index, 1); - - return false; - } - } - } - - return false; - } - - isNewUrl(domain) { - if (tabs.length > 0) - return tabs.find(o => o.url === domain) === undefined; - else return true; - } - - getTab(domain) { - if (tabs !== undefined) - return tabs.find(o => o.url === domain); - } - - - updateFavicon(tab) { - var domain = extractHostname(tab.url); - var currentTab = this.getTab(domain); - if (currentTab !== null && currentTab !== undefined) { - if (tab.favIconUrl !== undefined && tab.favIconUrl !== currentTab.favicon) { - currentTab.favicon = tab.favIconUrl; - } - } - } - - setCurrentActiveTab(domain) { - this.closeIntervalForCurrentTab(); - currentTab = domain; - this.addTimeInterval(domain); - } - - clearCurrentActiveTab() { - this.closeIntervalForCurrentTab(); - currentTab = ''; - } - - addTimeInterval(domain) { - var item = timeIntervalList.find(o => o.domain === domain && o.day == todayLocalDate()); - if (item != undefined) { - if (item.day == todayLocalDate()) - item.addInterval(); - else { - var newInterval = new TimeInterval(todayLocalDate(), domain); - newInterval.addInterval(); - timeIntervalList.push(newInterval); - } - } else { - var newInterval = new TimeInterval(todayLocalDate(), domain); - newInterval.addInterval(); - timeIntervalList.push(newInterval); - } - } - - closeIntervalForCurrentTab() { - if (currentTab !== '' && timeIntervalList != undefined) { - var item = timeIntervalList.find(o => o.domain === currentTab && o.day == todayLocalDate()); - if (item != undefined) - item.closeInterval(); - } - currentTab = ''; - } - - isNeedNotifyView(domain, tab){ - if (setting_notification_list !== undefined && setting_notification_list.length > 0) { - var item = setting_notification_list.find(o => isDomainEquals(extractHostname(o.domain), extractHostname(domain))); - if (item !== undefined) { - var today = todayLocalDate(); - var data = tab.days.find(x => x.date == today); - if (data !== undefined) { - var todayTimeUse = data.summary; - if (todayTimeUse == item.time || todayTimeUse % item.time == 0) { - return true; - } - } - } - } - return false; - } -}; \ No newline at end of file diff --git a/src/scripts/background.js b/src/scripts/background.js deleted file mode 100644 index fcb61bc..0000000 --- a/src/scripts/background.js +++ /dev/null @@ -1,476 +0,0 @@ -'use strict'; - -var tabs; -var timeIntervalList; -var currentTab; -var isNeedDeleteTimeIntervalFromTabs = false; -var activity = new Activity(); -var storage = new LocalStorage(); -var deferredRestrictionsList; - -var setting_black_list; -var setting_restriction_list; -var setting_interval_save; -var setting_interval_inactivity; -var setting_view_in_badge; -var setting_block_deferral; -var setting_dark_mode; -var setting_notification_list; -var setting_notification_message; - -var isHasPermissioForYouTube; -var isHasPermissioForNetflix; -var isHasPermissioForNotification; - -function updateSummaryTime() { - setInterval(backgroundCheck, SETTINGS_INTERVAL_CHECK_DEFAULT); -} - -function updateStorage() { - setInterval(backgroundUpdateStorage, SETTINGS_INTERVAL_SAVE_STORAGE_DEFAULT); -} - -function backgroundCheck() { - chrome.windows.getLastFocused({ populate: true }, function(currentWindow) { - if (currentWindow.focused) { - var activeTab = currentWindow.tabs.find(t => t.active === true); - if (activeTab !== undefined && activity.isValidPage(activeTab)) { - var activeUrl = extractHostname(activeTab.url); - var tab = activity.getTab(activeUrl); - if (tab === undefined) { - activity.addTab(activeTab); - } - - if (activity.isInBlackList(activeUrl)) { - chrome.browserAction.setBadgeBackgroundColor({ color: '#fdb8b8' }) - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: 'n/a' - }); - } else { - if (tab !== undefined) { - if (currentTab !== tab.url) { - activity.setCurrentActiveTab(tab.url); - } - chrome.idle.queryState(parseInt(setting_interval_inactivity), function(state) { - if (state === 'active') { - mainTRacker(activeUrl, tab, activeTab); - } else checkDOM(state, activeUrl, tab, activeTab); - }); - } - } - } - } else activity.closeIntervalForCurrentTab(); - }); -} - -function mainTRacker(activeUrl, tab, activeTab) { - if (activity.isLimitExceeded(activeUrl, tab) && !activity.wasDeferred(activeUrl)) { - setBlockPageToCurrent(activeTab.url, tab.days.at(-1).summary, tab.days.at(-1).counter); - } - if (!activity.isInBlackList(activeUrl)) { - if (activity.isNeedNotifyView(activeUrl, tab)) { - if (isHasPermissioForNotification) { - showNotification(activeUrl, tab); - } else { - checkPermissionsForNotifications(showNotification, activeUrl, tab); - } - } - tab.incSummaryTime(); - } - if (setting_view_in_badge === true) { - chrome.browserAction.setBadgeBackgroundColor({ color: '#e7e7e7' }) - var summary = tab.days.find(s => s.date === todayLocalDate()).summary; - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: String(convertSummaryTimeToBadgeString(summary)) - }); - } else { - chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 0, 0] }) - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: '' - }); - } -} - -function showNotification(activeUrl, tab) { - chrome.notifications.clear('watt-site-notification', function(wasCleared) { - if (!wasCleared) { - console.log('!wasCleared'); - - chrome.notifications.create( - 'watt-site-notification', { - type: 'basic', - iconUrl: 'icons/128x128.png', - title: "Web Activity Time Tracker", - contextMessage: activeUrl + ' ' + convertShortSummaryTimeToString(tab.getTodayTime()), - message: setting_notification_message - }, - function(notificationId) { - console.log(notificationId); - chrome.notifications.clear('watt-site-notification', function(wasCleared) { - if (wasCleared) - notificationAction(activeUrl, tab); - }); - }); - } else { - notificationAction(activeUrl, tab); - } - }); -} - -function notificationAction(activeUrl, tab) { - chrome.notifications.create( - 'watt-site-notification', { - type: 'basic', - iconUrl: 'icons/128x128.png', - title: "Web Activity Time Tracker", - contextMessage: activeUrl + ' ' + convertShortSummaryTimeToString(tab.getTodayTime()), - message: setting_notification_message - }); -} - -function setBlockPageToCurrent(currentUrl, summaryTime, counter) { - var blockUrl = chrome.runtime.getURL("block.html") + '?url=' + currentUrl - + '&summaryTime=' + summaryTime - + '&counter=' + counter; - chrome.tabs.query({ currentWindow: true, active: true }, function(tab) { - chrome.tabs.update(tab.id, { url: blockUrl }); - }); -} - -function isVideoPlayedOnPage() { - var videoElement = document.getElementsByTagName('video')[0]; - if (videoElement !== undefined && videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2) { - return true; - } else return false; -} - -function checkDOM(state, activeUrl, tab, activeTab) { - if (state === 'idle' && isDomainEquals(activeUrl, "youtube.com")) { - trackForYT(mainTRacker, activeUrl, tab, activeTab); - } else if (state === 'idle' && isDomainEquals(activeUrl, "netflix.com")) { - trackForNetflix(mainTRacker, activeUrl, tab, activeTab); - } else activity.closeIntervalForCurrentTab(); -} - -function trackForYT(callback, activeUrl, tab, activeTab) { - if (isHasPermissioForYouTube) { - executeScriptYoutube(callback, activeUrl, tab, activeTab); - } else { - checkPermissionsForYT(executeScriptYoutube, activity.closeIntervalForCurrentTab, callback, activeUrl, tab, activeTab); - } -} - -function trackForNetflix(callback, activeUrl, tab, activeTab) { - if (isHasPermissioForNetflix) { - executeScriptNetflix(callback, activeUrl, tab, activeTab); - } else { - checkPermissionsForNetflix(executeScriptNetflix, activity.closeIntervalForCurrentTab, callback, activeUrl, tab, activeTab); - } -} - -function executeScriptYoutube(callback, activeUrl, tab, activeTab) { - chrome.tabs.executeScript({ code: "var videoElement = document.getElementsByTagName('video')[0]; (videoElement !== undefined && videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2);" }, (results) => { - if (results !== undefined && results[0] !== undefined && results[0] === true) - callback(activeUrl, tab, activeTab); - else activity.closeIntervalForCurrentTab(); - }); -} - -function executeScriptNetflix(callback, activeUrl, tab, activeTab) { - chrome.tabs.executeScript({ code: "var videoElement = document.getElementsByTagName('video')[0]; (videoElement !== undefined && videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2);" }, (results) => { - if (results !== undefined && results[0] !== undefined && results[0] === true) { - callback(activeUrl, tab, activeTab); - } else { - activity.closeIntervalForCurrentTab(); - } - }); -} - -function backgroundUpdateStorage() { - if (tabs != undefined && tabs.length > 0) - storage.saveTabs(tabs); - if (timeIntervalList != undefined && timeIntervalList.length > 0) - storage.saveValue(STORAGE_TIMEINTERVAL_LIST, timeIntervalList); -} - -function setDefaultSettings() { - storage.saveValue(SETTINGS_INTERVAL_INACTIVITY, SETTINGS_INTERVAL_INACTIVITY_DEFAULT); - storage.saveValue(SETTINGS_INTERVAL_RANGE, SETTINGS_INTERVAL_RANGE_DEFAULT); - storage.saveValue(SETTINGS_VIEW_TIME_IN_BADGE, SETTINGS_VIEW_TIME_IN_BADGE_DEFAULT); - storage.saveValue(SETTINGS_BLOCK_DEFERRAL, SETTINGS_BLOCK_DEFERRAL_DEFAULT); - storage.saveValue(SETTINGS_DARK_MODE, SETTINGS_DARK_MODE_DEFAULT); - storage.saveValue(SETTINGS_INTERVAL_SAVE_STORAGE, SETTINGS_INTERVAL_SAVE_STORAGE_DEFAULT); - storage.saveValue(STORAGE_NOTIFICATION_MESSAGE, STORAGE_NOTIFICATION_MESSAGE_DEFAULT); -} - -function checkSettingsImEmpty() { - chrome.storage.local.getBytesInUse(['inactivity_interval'], function(item) { - if (item == 0) { - setDefaultSettings(); - } - }); -} - -function setDefaultValueForNewSettings() { - loadNotificationMessage(); -} - -function addListener() { - chrome.tabs.onActivated.addListener(function(info) { - chrome.tabs.get(info.tabId, function(tab) { - activity.addTab(tab); - }); - }); - - chrome.webNavigation.onCompleted.addListener(function(details) { - chrome.tabs.get(details.tabId, function(tab) { - activity.updateFavicon(tab); - }); - }); - chrome.runtime.onInstalled.addListener(function(details) { - if (details.reason == 'install') { - storage.saveValue(SETTINGS_SHOW_HINT, SETTINGS_SHOW_HINT_DEFAULT); - setDefaultSettings(); - } - if (details.reason == 'update') { - storage.saveValue(SETTINGS_SHOW_HINT, SETTINGS_SHOW_HINT_DEFAULT); - checkSettingsImEmpty(); - setDefaultValueForNewSettings(); - isNeedDeleteTimeIntervalFromTabs = true; - } - }); - chrome.storage.onChanged.addListener(function(changes, namespace) { - for (var key in changes) { - if (key === STORAGE_BLACK_LIST) { - loadBlackList(); - } - if (key === STORAGE_RESTRICTION_LIST) { - loadRestrictionList(); - } - if (key === STORAGE_NOTIFICATION_LIST) { - loadNotificationList(); - } - if (key === STORAGE_NOTIFICATION_MESSAGE) { - loadNotificationMessage(); - } - if (key === SETTINGS_INTERVAL_INACTIVITY) { - storage.getValue(SETTINGS_INTERVAL_INACTIVITY, function(item) { setting_interval_inactivity = item; }); - } - if (key === SETTINGS_VIEW_TIME_IN_BADGE) { - storage.getValue(SETTINGS_VIEW_TIME_IN_BADGE, function(item) { setting_view_in_badge = item; }); - } - if (key === SETTINGS_BLOCK_DEFERRAL) { - storage.getValue(SETTINGS_BLOCK_DEFERRAL, function(item) { setting_block_deferral = item; }); - } - if (key === SETTINGS_DARK_MODE) { - storage.getValue(SETTINGS_DARK_MODE, function(item) { setting_dark_mode = item; }); - } - } - }); - - chrome.runtime.setUninstallURL("https://docs.google.com/forms/d/e/1FAIpQLSdImHtvey6sg5mzsQwWfAQscgZOOV52blSf9HkywSXJhuQQHg/viewform"); -} - -function loadTabs() { - storage.loadTabs(STORAGE_TABS, function(items) { - tabs = []; - if (items != undefined) { - for (var i = 0; i < items.length; i++) { - tabs.push(new Tab(items[i].url, items[i].favicon, items[i].days, items[i].summaryTime, items[i].counter)); - } - if (isNeedDeleteTimeIntervalFromTabs) - deleteTimeIntervalFromTabs(); - } - }); -} - -function deleteTimeIntervalFromTabs() { - tabs.forEach(function(item) { - item.days.forEach(function(day) { - if (day.time != undefined) - day.time = []; - }) - }) -} - -function deleteYesterdayTimeInterval() { - timeIntervalList = timeIntervalList.filter(x => x.day == todayLocalDate()); -} - -function loadBlackList() { - storage.getValue(STORAGE_BLACK_LIST, function(items) { - setting_black_list = items; - }) -} - -function loadTimeIntervals() { - storage.getValue(STORAGE_TIMEINTERVAL_LIST, function(items) { - timeIntervalList = []; - if (items != undefined) { - for (var i = 0; i < items.length; i++) { - timeIntervalList.push(new TimeInterval(items[i].day, items[i].domain, items[i].intervals)); - } - deleteYesterdayTimeInterval(); - } - }); -} - -function loadRestrictionList() { - storage.getValue(STORAGE_RESTRICTION_LIST, function(items) { - setting_restriction_list = items; - }) -} - -function loadNotificationList() { - storage.getValue(STORAGE_NOTIFICATION_LIST, function(items) { - setting_notification_list = items; - }); -} - -function loadNotificationMessage() { - storage.getValue(STORAGE_NOTIFICATION_MESSAGE, function(item) { - setting_notification_message = item; - if (isEmpty(setting_notification_message)) { - storage.saveValue(STORAGE_NOTIFICATION_MESSAGE, STORAGE_NOTIFICATION_MESSAGE_DEFAULT); - setting_notification_message = STORAGE_NOTIFICATION_MESSAGE_DEFAULT; - } - }); -} - -function loadSettings() { - storage.getValue(SETTINGS_INTERVAL_INACTIVITY, function(item) { setting_interval_inactivity = item; }); - storage.getValue(SETTINGS_VIEW_TIME_IN_BADGE, function(item) { setting_view_in_badge = item; }); - storage.getValue(SETTINGS_BLOCK_DEFERRAL, function(item) { setting_block_deferral = item; }); - storage.getValue(SETTINGS_DARK_MODE, function(item) { setting_dark_mode = item; }); -} - -function loadAddDataFromStorage() { - loadTabs(); - loadTimeIntervals(); - loadBlackList(); - loadRestrictionList(); - loadNotificationList(); - loadNotificationMessage(); - loadSettings(); -} - -function loadPermissions() { - checkPermissionsForYT(); - checkPermissionsForNetflix(); - checkPermissionsForNotifications(); -} - -function checkPermissionsForYT(callbackIfTrue, callbackIfFalse, ...props) { - chrome.permissions.contains({ - permissions: ['tabs'], - origins: ["https://www.youtube.com/*"] - }, function(result) { - if (callbackIfTrue != undefined && result) - callbackIfTrue(...props); - if (callbackIfFalse != undefined && !result) - callbackIfFalse(); - isHasPermissioForYouTube = result; - }); -} - -function checkPermissionsForNetflix(callbackIfTrue, callbackIfFalse, ...props) { - chrome.permissions.contains({ - permissions: ['tabs'], - origins: ["https://www.netflix.com/*"] - }, function(result) { - if (callbackIfTrue != undefined && result) - callbackIfTrue(...props); - if (callbackIfFalse != undefined && !result) - callbackIfFalse(); - isHasPermissioForNetflix = result; - }); -} - -function checkPermissionsForNotifications(callback, ...props) { - chrome.permissions.contains({ - permissions: ["notifications"] - }, function(result) { - if (callback != undefined && result) - callback(...props); - isHasPermissioForNotification = result; - }); -} - -function createFile(data, type, fileName) { - var file = new Blob([data], { type: type }); - var downloadLink; - downloadLink = document.createElement("a"); - downloadLink.download = fileName; - downloadLink.href = window.URL.createObjectURL(file); - downloadLink.style.display = "none"; - document.body.appendChild(downloadLink); - downloadLink.click(); - } - - function toCsv(tabsData) { - var str = "domain,date,time(sec)\r\n"; - for (var i = 0; i < tabsData.length; i++) { - for (var y = 0; y < tabsData[i].days.length; y++) { - var line = - tabsData[i].url + - "," + - new Date(tabsData[i].days[y].date).toLocaleDateString() + - "," + - tabsData[i].days[y].summary; - str += line + "\r\n"; - } - } - - createFile(str, "text/csv", "domains.csv"); - } - - function exportToCSV() { - storage.getValue(STORAGE_TABS, function (item) { - toCsv(item); - }); - } - - storage.getValue("SETTINGS_PERIODIC_HOUR_DOWNLOAD", function (hour) { - storage.getValue("SETTINGS_PERIODIC_MINUTE_DOWNLOAD", function (minute) { - if (typeof hour !== "number" || typeof minute !== "number") { - return; - } else { - autoDownloadCsv(hour, minute); - } - }); - }); - - function autoDownloadCsv(hour, minute) { - var now = new Date(); - var triggerTime = new Date( - now.getFullYear(), - now.getMonth(), - now.getDate(), - hour, - minute, - 0, - 0 - ); - - if (triggerTime < now) { - triggerTime.setDate(triggerTime.getDate() + 1); - } - chrome.alarms.create("periodic_Download", { - when: triggerTime.getTime(), - periodInMinutes: 1440, // 24 hours - }); - chrome.alarms.onAlarm.addListener(function (alarm) { - if (alarm.name === "periodic_Download") { - exportToCSV(); - } - }); - } - -loadPermissions(); -addListener(); -loadAddDataFromStorage(); -updateSummaryTime(); -updateStorage(); \ No newline at end of file diff --git a/src/scripts/block.js b/src/scripts/block.js deleted file mode 100644 index e2d34d0..0000000 --- a/src/scripts/block.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; - -var storage = new LocalStorage(); -var blockSiteUrl; -var blockSiteTime; -var blockSiteCounter; -var restrictionList = []; - -document.addEventListener("DOMContentLoaded", function () { - var url = new URL(document.URL); - blockSiteUrl = url.searchParams.get("url"); - blockSiteTime = url.searchParams.get("summaryTime"); - blockSiteCounter = url.searchParams.get("counter"); - document.getElementById("site").innerText = extractHostname(blockSiteUrl); - document.getElementById("deferredTime").innerText = convertShortSummaryTimeToString(blockSiteTime); - document.getElementById("deferredCount").innerText = blockSiteCounter; - - storage.getValue(STORAGE_RESTRICTION_LIST, function (items) { - restrictionList = items; - if (restrictionList === undefined) restrictionList = []; - var currentItem = restrictionList.find((x) => - isDomainEquals(extractHostname(x.domain), extractHostname(blockSiteUrl)) - ); - if (currentItem !== undefined) { - document.getElementById("limit").innerText = - convertShortSummaryTimeToString(currentItem.time); - } - }); - - storage.getValue(SETTINGS_BLOCK_DEFERRAL, function (item) { - var deferBtn = document.getElementById("deffererBtn"); - if (item) { - deferBtn.addEventListener("click", function () { - chrome.runtime.getBackgroundPage(function (bg) { - let defList = bg.deferredRestrictionsList; - if (defList == undefined) defList = []; - defList.push({ - site: blockSiteUrl, - dateOfDeferred: new Date().getTime(), - }); - - bg.deferredRestrictionsList = defList; - - chrome.tabs.query( - { currentWindow: true, active: true }, - function (tab) { - chrome.tabs.update(tab.id, { url: blockSiteUrl }); - } - ); - }); - }); - } else { - deferBtn.remove(); - } - }); -}); diff --git a/src/scripts/chart/chart-core.js b/src/scripts/chart/chart-core.js deleted file mode 100644 index 7b859ad..0000000 --- a/src/scripts/chart/chart-core.js +++ /dev/null @@ -1,528 +0,0 @@ -function donutChart() { - var width, - height, - darkMode, - margin = { top: 10, right: 10, bottom: 0, left: 10 }, - colour = d3.scaleOrdinal(d3.schemeCategory20), // colour scheme - variable, // value in data that will dictate proportions on chart - category, // compare data by - padAngle, // effectively dictates the gap between slices - floatFormat = d3.format('.4r'), - cornerRadius, // sets how rounded the corners are on each slice - percentFormat = d3.format(',.2%'); - - function chart(selection) { - selection.each(function (data) { - // generate chart - - // =========================================================================================== - // Set up constructors for making donut. See https://github.com/d3/d3-shape/blob/master/README.md - var radius = 110; - - // creates a new pie generator - var pie = d3.pie() - .value(function (d) { return floatFormat(d[variable]); }) - .sort(null); - - // contructs and arc generator. This will be used for the donut. The difference between outer and inner - // radius will dictate the thickness of the donut - var arc = d3.arc() - .outerRadius(radius) - .innerRadius(radius * 0.75) - .cornerRadius(cornerRadius) - .padAngle(padAngle); - - // =========================================================================================== - // append the svg object to the selection - var svg = selection.append('svg') - .attr('width', width + margin.left + margin.right) - .attr('height', height + margin.top + margin.bottom) - .attr('class', 'backColorChart') - .append('g') - .attr('transform', 'translate(' + (width / 2 - 105) + ',' + (height / 2) + ')'); - // =========================================================================================== - - // =========================================================================================== - // g elements to keep elements within svg modular - svg.append('g').attr('class', 'slices'); - svg.append('g').attr('class', 'labelName'); - svg.append('g').attr('class', 'lines'); - // =========================================================================================== - - // =========================================================================================== - // add and colour the donut slices - var path = svg.select('.slices') - .datum(data).selectAll('path') - .data(pie) - .enter().append('path') - .attr('fill', function (d) { return colour(d.data[category]); }) - .attr('d', arc) - .attr('id', function (d) { return d.data[category]; }); - // =========================================================================================== - - var legendG = svg.selectAll(".legend") // note appending it to mySvg and not svg to make positioning easier - .data(pie(data)) - .enter().append("g") - .attr("transform", function (d, i) { - return "translate(" + (130) + "," + (i * 20 - 100) + ")"; // place each legend on the right and bump each one down 15 pixels - }) - .attr("class", "legend"); - - if (darkMode) - legendG.style("fill", "#ffffff"); - else legendG.style("fill", "black"); - - legendG.append("rect") // make a matching color rect - .attr("width", 10) - .attr("height", 10) - .attr("fill", function (d, i) { - return colour(d.data[category]); - }); - - if (darkMode) - legendG.append("text") // add the text - .text(function (d) { - return d.data.url; - }) - .style("font-size", 13) - .style('fill', '#ffffff') - .attr("y", 10) - .attr("x", 13); - else - legendG.append("text") // add the text - .text(function (d) { - return d.data.url; - }) - .style("fill", "black") - .style("font-size", 14) - .attr("y", 10) - .attr("x", 15); - - // =========================================================================================== - // add tooltip to mouse events on slices and labels - d3.selectAll('.labelName text, .slices path').call(toolTip); - // =========================================================================================== - - // =========================================================================================== - // Functions - - // calculates the angle for the middle of a slice - function midAngle(d) { return d.startAngle + (d.endAngle - d.startAngle) / 2; } - - // function that creates and adds the tool tip to a selected element - function toolTip(selection) { - - // add tooltip (svg circle element) when mouse enters label or slice - selection.on('mouseenter', function (data) { - d3.selectAll('.toolCircle').remove(); - if (darkMode) - svg.append('text') - .attr('class', 'toolCircle') - .attr('dy', -15) // hard-coded. can adjust this to adjust text vertical alignment in tooltip - .html(toolTipHTML(data)) // add text to the circle. - .style('font-size', '.9em') - .style('fill', '#ffffff') - .style('text-anchor', 'middle'); // centres text in tooltip - else - svg.append('text') - .attr('class', 'toolCircle') - .attr('dy', -15) - .html(toolTipHTML(data)) - .style('font-size', '.9em') - .style('text-anchor', 'middle'); - - svg.append('circle') - .attr('class', 'toolCircle') - .attr('r', radius * 0.75) // radius of tooltip circle - .style('fill', 'white') // colour based on category mouse is over - .style('fill-opacity', 0.35); - - }); - - // remove the tooltip when mouse leaves the slice/label - // selection.on('mouseout', function () { - // d3.selectAll('.toolCircle').remove(); - // }); - } - - // function to create the HTML string for the tool tip. Loops through each key in data object - // and returns the html string key: value - function toolTipHTML(data) { - - var tip = '', - i = 0; - - for (var key in data.data) { - - // if value is a number, format it as a percentage - var value = (!isNaN(parseFloat(data.data[key]))) ? percentFormat(data.data[key]) : data.data[key]; - if (key === 'summary') - value = convertSummaryTimeToString(data.data[key]); - if (key === 'visits' && data.data[key] !== undefined) - value = data.data[key] + ' visits'; - var className = ''; - if (key === 'percentage') - className = 'class="percentageValue"'; - - // leave off 'dy' attr for first tspan so the 'dy' attr on text element works. The 'dy' attr on - // tspan effectively imitates a line break. - if (i === 0) tip += '' + value + ''; - else tip += '' + value + ''; - i++; - } - - return tip; - } - - function angleIsInRangeDifference(tempAngle, currentAngle, difference) { - return currentAngle < (tempAngle + difference) && currentAngle > (tempAngle - difference); - } - // =========================================================================================== - - }); - } - - chart.width = function (value) { - if (!arguments.length) return width; - width = value; - return chart; - }; - - chart.height = function (value) { - if (!arguments.length) return height; - height = value; - return chart; - }; - - chart.darkMode = function (value) { - if (!arguments.length) return darkMode; - darkMode = value; - return chart; - }; - - chart.margin = function (value) { - if (!arguments.length) return margin; - margin = value; - return chart; - }; - - chart.radius = function (value) { - if (!arguments.length) return radius; - radius = value; - return chart; - }; - - chart.padAngle = function (value) { - if (!arguments.length) return padAngle; - padAngle = value; - return chart; - }; - - chart.cornerRadius = function (value) { - if (!arguments.length) return cornerRadius; - cornerRadius = value; - return chart; - }; - - chart.colour = function (value) { - if (!arguments.length) return colour; - colour = value; - return chart; - }; - - chart.variable = function (value) { - if (!arguments.length) return variable; - variable = value; - return chart; - }; - - chart.category = function (value) { - if (!arguments.length) return category; - category = value; - return chart; - }; - - return chart; -} - -function barChart(data, darkMode) { - var margin = { top: 25, right: 5, bottom: 25, left: 5 }, - width = 555, - height = 160; - - // set the ranges - var x = d3.scaleBand() - .range([0, width]) - .padding(0.1); - var y = d3.scaleLinear() - .range([height, 0]); - - // append the svg object to the body of the page - // append a 'group' element to 'svg' - // moves the 'group' element to the top left margin - var svg = d3.select("#barChart").append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", - "translate(" + margin.left + "," + margin.top + ")"); - - var tip = d3.tip() - .attr('class', 'd3-tip') - .offset([-10, 0]) - .html(function (d) { - if (data.length > 9) - return "" + new Date(d.date).toLocaleDateString() + "
    " + convertShortSummaryTimeToString(d.total) + ""; - else - return "" + convertShortSummaryTimeToString(d.total) + ""; - }); - - svg.call(tip); - - // Scale the range of the data in the domains - x.domain(data.map(function (d) { return new Date(d.date).toLocaleDateString(); })); - y.domain([0, d3.max(data, function (d) { return d.total; })]); - - // append the rectangles for the bar chart - svg.selectAll(".bar") - .data(data) - .enter().append("rect") - .attr("class", "bar") - .attr("x", function (d) { return x(new Date(d.date).toLocaleDateString()); }) - .attr("width", x.bandwidth()) - .attr("y", function (d) { return y(d.total); }) - .attr("height", function (d) { return height - y(d.total); }) - .on('mouseover', tip.show) - .on('mouseout', tip.hide); - - // add the x Axis - svg.append("g") - .attr("transform", "translate(0," + height + ")") - .style("stroke", darkMode ? "white" : "") - .style("stroke-width", darkMode ? "0.5px" : "") - .call(d3.axisBottom(x)); - - if (data.length > 9) - document.querySelectorAll('#barChart g.tick ').forEach(element => { element.remove() }); - - if (darkMode){ - document.querySelector("#barChart path").setAttribute("stroke", "white"); - document.querySelectorAll('#barChart g.tick line').forEach(element => { element.setAttribute("stroke", "white") }); - } -} - -function drawIntervalChart(data) { - data.forEach(function (item) { - var hFrom = getHourFrom(item.interval); - var hTo = getHourTo(item.interval); - if (hFrom != hTo) { - var sourceTimeFrom = item.interval.split('-')[0].split(':'); - var sourceTimeTo = item.interval.split('-')[1].split(':'); - var timeTo = sourceTimeFrom[0] + ":" + 59 + ":" + 59; - var timeFrom = sourceTimeTo[0] + ":" + 00 + ":" + 00; - data.push({ "domain": item.domain, "interval": item.interval.split('-')[0] + "-" + timeTo }); - data.push({ "domain": item.domain, "interval": timeFrom + "-" + item.interval.split('-')[1] }); - } - }); - - var margin = { top: 5, right: 10, bottom: 20, left: 20 }, - width = 580 - margin.left - margin.right, - height = 410 - margin.top - margin.bottom; - - //linear 24 hour scale - var y = d3.scaleLinear() - .domain([0, 60]) - .range([height, 0]); - - //vertical axis - var yAxis = d3.axisLeft() - .ticks(10) - .scale(y); - - var x = d3.scaleLinear() - .domain([0, 24]) - .range([0, width]); - - //vertical axis - var xAxis = d3.axisBottom() - .ticks(24) - .scale(x) - - var tickDistance = 4.38; - - var tooltip; - if (document.body.classList.contains('dark-mode')) - tooltip = d3.select("#timeChart") - .append("div") - .style("opacity", 0) - .style("display", "none") - .style("position", "absolute") - .attr("class", "tooltip") - .style("background-color", "#cbcbcb") - .style("color", "black") - .style("border", "solid") - .style("border-width", "1px") - .style("border-radius", "5px") - .style("padding", "5px") - else - tooltip = d3.select("#timeChart") - .append("div") - .style("opacity", 0) - .style("display", "none") - .style("position", "absolute") - .attr("class", "tooltip") - .style("background-color", "white") - .style("color", "black") - .style("border", "solid") - .style("border-width", "1px") - .style("border-radius", "5px") - .style("padding", "5px") - - // Three function that change the tooltip when user hover / move / leave a cell - var mouseover = function (d) { - tooltip - .style("opacity", 1) - .style("display", "block") - d3.select(this) - .style("stroke", "black") - .style("stroke-width", "0.5px") - .style("opacity", 1) - } - var mousemove = function (d) { - tooltip - .html(d.domain + "
    " + d.interval) - .style("left", (d3.mouse(this)[0]) + 10 + "px") - .style("top", (d3.mouse(this)[1]) + 30 + "px") - } - var mouseleave = function (d) { - tooltip - .style("opacity", 0) - .style("display", "none") - d3.select(this) - .style("stroke", "none") - .style("opacity", 0.8) - } - - //create the svg - var svg; - if (document.body.classList.contains('dark-mode')) - svg = d3.select("#timeChart").append("svg") - .style('background-color', '#383838') - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - else - svg = d3.select("#timeChart").append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - - //draw the axis. - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + height + ")") - .attr("class", "label") - .call(xAxis) - .append("text") - .text("Value"); - - // Add a y-axis with label. - svg.append("g") - .attr("class", "y axis") - .call(yAxis) - .append("text") - .attr("class", "label") - .attr("y", 6) - .attr("dy", ".71em") - .attr("text-anchor", "end") - .attr("transform", "rotate(-90)") - .text("Value"); - - svg.append("g") - .attr("class", "grid") - .attr("transform", "translate(0," + height + ")") - .call(make_x_axis() - .tickSize(-height, 0, 0) - ) - - svg.append("g") - .attr("class", "grid") - .call(make_y_axis() - .tickSize(-width, 0, 0) - ) - - //draw the bars, offset y and bar height based on data - svg.selectAll(".bar") - .data(data) - .enter() - .append("rect") - .style("fill", "orangered") - .style("stroke", "#f1f1f1") - .style("stroke-width", "1") - .attr("class", "bar") - .attr("x", function (d) { - return x(getHourFrom(d.interval)) + 2; - }) - .attr("width", 20) - .attr("y", function (d) { - return y(getMinutesTo(d.interval)) - 1; - }) - .attr("height", function (d) { - var offset = getMinutesTo(d.interval) - getMinutesFrom(d.interval); - if (offset == 0) { - var offsetSeconds = getSecondsTo(d.interval) - getSecondsFrom(d.interval); - if (offsetSeconds <= 3) - return 0; - else - return 1; - } - else return offset * tickDistance; - }) - .on("mouseover", mouseover) - .on("mousemove", mousemove) - .on("mouseleave", mouseleave); - - function make_x_axis() { - return d3.axisBottom() - .scale(x) - .ticks(24) - } - - function make_y_axis() { - return d3.axisLeft() - .scale(y) - .ticks(10) - } - - function getHourFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[0]; - } - - function getHourTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[0]; - } - - function getMinutesFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[1]; - } - - function getMinutesTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[1]; - } - - function getSecondsFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[2]; - } - - function getSecondsTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[2]; - } -} \ No newline at end of file diff --git a/src/scripts/chart/d3.v4.min.js b/src/scripts/chart/d3.v4.min.js deleted file mode 100644 index ffe427c..0000000 --- a/src/scripts/chart/d3.v4.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(I){"use strict";function a(t,n){return t>>1;o(t[i],n)<0?e=i+1:r=i}return e},right:function(t,n,e,r){for(null==e&&(e=0),null==r&&(r=t.length);e>>1;0>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Xs.exec(t))?At(parseInt(n[1],16)):(n=Vs.exec(t))?new Rt(n[1],n[2],n[3],1):(n=$s.exec(t))?new Rt(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ws.exec(t))?Ct(n[1],n[2],n[3],n[4]):(n=Zs.exec(t))?Ct(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Gs.exec(t))?Lt(n[1],n[2]/100,n[3]/100,1):(n=Qs.exec(t))?Lt(n[1],n[2]/100,n[3]/100,n[4]):Js.hasOwnProperty(t)?At(Js[t]):"transparent"===t?new Rt(NaN,NaN,NaN,0):null}function At(t){return new Rt(t>>16&255,t>>8&255,255&t,1)}function Ct(t,n,e,r){return r<=0&&(t=n=e=NaN),new Rt(t,n,e,r)}function zt(t){return t instanceof St||(t=Et(t)),t?new Rt((t=t.rgb()).r,t.g,t.b,t.opacity):new Rt}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Lt(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||1<=e?t=n=NaN:n<=0&&(t=NaN),new Dt(t,n,e,r)}function qt(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Dt)return new Dt(t.h,t.s,t.l,t.opacity);if(t instanceof St||(t=Et(t)),!t)return new Dt;if(t instanceof Dt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(ea&&(i=r.slice(a,i),s[c]?s[c]+=i:s[++c]=i),(n=n[0])===(e=e[0])?s[c]?s[c]+=e:s[++c]=e:(s[++c]=null,f.push({i:c,x:un(n,e)})),a=Nf.lastIndex;return ae._time&&(r=e._time),(t=e)._next):(n=e._next,e._next=null,t?t._next=n:mf=n);xf=t,Nn(r)}(),Bf=0}}function Tn(){var t=jf.now(),n=t-Yf;IfWf)throw new Error("too late; already scheduled");return e}function An(t,n){var e=Cn(t,n);if(e.state>Gf)throw new Error("too late; already started");return e}function Cn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function zn(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Gf&&e.stateMath.abs(t[1]-C[1])?v=!0:d=!0),C=t,p=!0,Vn(),n()}function n(){var t;switch(l=C[0]-A[0],h=C[1]-A[1],y){case xl:case ml:m&&(l=Math.max(T-r,Math.min(k-a,l)),i=r+l,c=a+l),x&&(h=Math.max(N-o,Math.min(S-s,h)),u=o+h,f=s+h);break;case bl:m<0?(l=Math.max(T-r,Math.min(k-r,l)),i=r+l,c=a):0=o?c=!0:10===(n=r.charCodeAt(u++))?s=!0:13===n&&(s=!0,10===r.charCodeAt(u)&&++u),r.slice(e+1,t-1).replace(/""/g,'"')}for(;u=(o=(v+_)/2))?v=o:_=o,(f=e>=(u=(g+y)/2))?g=u:y=u,!(p=(i=p)[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;for(;i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+_)/2))?v=o:_=o,(f=e>=(u=(g+y)/2))?g=u:y=u,(l=f<<1|s)==(h=(u<=c)<<1|o<=a););return i[h]=p,i[l]=d,t}function xe(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function be(t){return t[0]}function we(t){return t[1]}function Me(t,n,e){var r=new Te(null==n?be:n,null==e?we:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Te(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Ne(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function ke(t){return t.x+t.vx}function Se(t){return t.y+t.vy}function Ee(t){return t.index}function Ae(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Ce(t){return t.x}function ze(t){return t.y}function Pe(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[1i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}function qe(t){return new De(t)}function De(t){if(!(n=ih.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):rh[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function Ue(t){return t}function Oe(t){function u(t){function n(t){var n,e,r,i=_,o=y;if("c"===g)o=m(t)+o,t="";else{var u=(t=+t)<0;if(t=m(Math.abs(t),v),u&&0==+t&&(u=!1),i=(u?"("===l?l:"-":"-"===l||"("===l?"":l)+i,o=("s"===g?uh[8+nh/3]:"")+o+(u&&"("===l?")":""),x)for(n=-1,e=t.length;++n>1)+i+t+o+c.slice(a);break;default:t=c+i+t+o}return M(t)}var s=(t=qe(t)).fill,f=t.align,l=t.sign,e=t.symbol,h=t.zero,p=t.width,d=t.comma,v=t.precision,g=t.type,_="$"===e?r[0]:"#"===e&&/[boxX]/.test(g)?"0"+g.toLowerCase():"",y="$"===e?r[1]:/[%p]/.test(g)?i:"",m=rh[g],x=!g||/[defgprs%]/.test(g);return v=null==v?g?6:12:/[gprs]/.test(g)?Math.max(1,Math.min(21,v)):Math.max(0,Math.min(20,v)),n.toString=function(){return t+""},n}var n,a,c,b=t.grouping&&t.thousands?(a=t.grouping,c=t.thousands,function(t,n){for(var e=t.length,r=[],i=0,o=a[0],u=0;0n));)o=a[i=(i+1)%a.length];return r.reverse().join(c)}):Ue,r=t.currency,w=t.decimal,M=t.numerals?(n=t.numerals,function(t){return t.replace(/[0-9]/g,function(t){return n[+t]})}):Ue,i=t.percent||"%";return{format:u,formatPrefix:function(t,n){var e=u(((t=qe(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Re(n)/3))),i=Math.pow(10,-r),o=uh[8+r/3];return function(t){return e(i*t)+o}}}}function Fe(t){return oh=Oe(t),I.format=oh.format,I.formatPrefix=oh.formatPrefix,oh}function Ie(t){return Math.max(0,-Re(Math.abs(t)))}function Ye(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Re(n)/3)))-Re(Math.abs(t)))}function Be(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Re(n)-Re(t))+1}function He(){return new je}function je(){this.reset()}function Xe(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ve(t){return 1vh&&(vh=o):s^(a*gh<(c=(c+360)%360-180)&&cyr(hh,dh)&&(dh=t):yr(t,dh)>yr(hh,dh)&&(hh=t):hh<=dh?(tyr(hh,dh)&&(dh=t):yr(t,dh)>yr(hh,dh)&&(hh=t)}else xh.push(bh=[hh=t,dh=t]);nFh&&(hh=-(dh=180)),bh[0]=hh,bh[1]=dh,mh=null}function yr(t,n){return(n-=t)<0?n+360:n}function mr(t,n){return t[0]-n[0]}function xr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nk}function d(t,n,e){var r=[1,0,0],i=ar(or(t),or(n)),o=ur(i,i),u=i[0],a=o-u*u;if(!a)return!e&&t;var c=k*o/a,s=-k*u/a,f=ar(r,i),l=sr(r,c);cr(l,sr(i,s));var h=f,p=ur(l,h),d=ur(h,h),v=p*p-d*(ur(l,l)-1);if(!(v<0)){var g=ep(v),_=sr(h,(-p-g)/d);if(cr(_,l),_=ir(_),!e)return _;var y,m=t[0],x=n[0],b=t[1],w=n[1];xFh;return $r(p,function(a){var c,s,f,l,h;return{lineStart:function(){l=f=!1,h=1},point:function(t,n){var e,r=[t,n],i=p(t,n),o=g?i?0:v(t,n):i?v(t+(t<0?Ih:-Ih),n):0;if(!c&&(l=f=i)&&a.lineStart(),i!==f&&(!(e=d(c,r))||Br(c,e)||Br(r,e))&&(r[0]+=Fh,r[1]+=Fh,i=p(r[0],r[1])),i!==f)h=0,i?(a.lineStart(),e=d(r,c),a.point(e[0],e[1])):(e=d(c,r),a.point(e[0],e[1]),a.lineEnd()),c=e;else if(_&&c&&g^i){var u;o&s||!(u=d(r,c,!0))||(h=0,g?(a.lineStart(),a.point(u[0][0],u[0][1]),a.point(u[1][0],u[1][1]),a.lineEnd()):(a.point(u[1][0],u[1][1]),a.lineEnd(),a.lineStart(),a.point(u[0][0],u[0][1])))}!i||c&&Br(c,r)||a.point(r[0],r[1]),c=r,f=i,s=o},lineEnd:function(){f&&a.lineEnd(),c=null},clean:function(){return h|(l&&f)<<1}}},function(t,n,e,r){Fr(r,i,o,e,t,n)},g?[0,-i]:[-Ih,i-Ih])}function Qr(_,y,m,x){function b(t,n){return _<=t&&t<=m&&y<=n&&n<=x}function w(t,n,e,r){var i=0,o=0;if(null==t||(i=u(t,e))!==(o=u(n,e))||a(t,n)<0^0Fh}).map(f)).concat(N(Gh(a/v)*v,u,v).filter(function(t){return Vh(t%_)>Fh}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,g=90,_=360,y=2.5;return n.lines=function(){return t().map(function(t){return{type:"LineString",coordinates:t}})},n.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.extentMajor(t).extentMinor(t):n.extentMinor()},n.extentMajor=function(t){return arguments.length?(o=+t[0][0],i=+t[1][0],s=+t[0][1],c=+t[1][1],id){f-=a;break}d=p}_.push(u={value:f,dice:cvg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>vg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function wc(t,n){this._context=t,this._alpha=n}function Mc(t,n){this._context=t,this._alpha=n}function Tc(t,n){this._context=t,this._alpha=n}function Nc(t){this._context=t}function kc(t){return t<0?-1:1}function Sc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(kc(o)+kc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function Ec(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function Ac(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function Cc(t){this._context=t}function zc(t){this._context=new Pc(t)}function Pc(t){this._context=t}function Rc(t){this._context=t}function Lc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(o[i[0]=0]=2,u[0]=t[0]+2*t[1],n=1;n=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]Jg)a=a.L;else{if(!((i=o-function(t,n){var e=t.N;if(e)return as(e,n);var r=t.site;return r[1]===n?r[0]:1/0}(a,u))>Jg)){-JgJg||Math.abs(i[0][1]-i[1][1])>Jg)||delete Zg[o]})(u,a,c,s),function(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,g,_,y=$g.length,m=!0;for(i=0;iJg||Math.abs(v-h)>Jg)&&(c.splice(a,0,Zg.push(Gc(u,p,Math.abs(d-t)h||(o=c.y0)>p||(u=c.x1)=(a=(d+g)/2))?d=a:g=a,(f=u>=(c=(v+_)/2))?v=c:_=c,!(p=(n=p)[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(!(p=(r=p).next))return this;return(i=p.next)&&delete p.next,r?i?r.next=i:delete r.next:n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p)):this._root=i,this},th.removeAll=function(t){for(var n=0,e=t.length;n=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;qe.prototype=De.prototype,De.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var oh,uh=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];Fe({decimal:".",thousands:",",grouping:[3],currency:["$",""]}),je.prototype={constructor:je,reset:function(){this.s=this.t=0},add:function(t){Xe(Oh,t,this.t),Xe(this,Oh.s,this.s),this.s?this.t+=Oh.t:this.s=Oh.t},valueOf:function(){return this.s}};var ah,ch,sh,fh,lh,hh,ph,dh,vh,gh,_h,yh,mh,xh,bh,wh,Mh,Th,Nh,kh,Sh,Eh,Ah,Ch,zh,Ph,Rh,Lh,qh,Dh,Uh,Oh=new je,Fh=1e-6,Ih=Math.PI,Yh=Ih/2,Bh=Ih/4,Hh=2*Ih,jh=180/Ih,Xh=Ih/180,Vh=Math.abs,$h=Math.atan,Wh=Math.atan2,Zh=Math.cos,Gh=Math.ceil,Qh=Math.exp,Jh=Math.log,Kh=Math.pow,tp=Math.sin,np=Math.sign||function(t){return 0Fh?$h((tp(r)*(a=Zh(o))*tp(i)-tp(o)*(u=Zh(r))*tp(e))/(u*a*c)):(r+o)/2,l.point(v,d),l.lineEnd(),l.lineStart(),l.point(s,d),h=0),l.point(p=t,d=n),v=s},lineEnd:function(){l.lineEnd(),p=d=NaN},clean:function(){return 2-h}}},function(t,n,e,r){var i;if(null==t)i=e*Yh,r.point(-Ih,i),r.point(0,i),r.point(Ih,i),r.point(Ih,0),r.point(Ih,-i),r.point(0,-i),r.point(-Ih,-i),r.point(-Ih,0),r.point(-Ih,i);else if(Vh(t[0]-n[0])>Fh){var o=t[0]Fh&&0<--i);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},eo.invert=Vi($e),ro.invert=Vi(function(t){return 2*$h(t)}),io.invert=function(t,n){return[-n,2*$h(Qh(t))-Yh]},po.prototype=so.prototype={constructor:po,count:function(){return this.eachAfter(co)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r=e)return null;for(var r=u-c.site[0],i=a-c.site[1],l=r*r+i*i;c=s.cells[n=f],f=null,c.halfedges.forEach(function(t){var n=s.edges[t],e=n.left;if(e!==c.site&&e||(e=n.right)){var r=u-e[0],i=a-e[1],o=r*r+i*i;oa;)c.pop(),--s;var f,l=new Array(s+1);for(n=0;n<=s;++n)(f=l[n]=[]).x0=0=v.length)return null!=p&&t.sort(p),null!=d?d(t):t;for(var n,o,u,a=-1,c=t.length,s=v[e++],f=ce(),l=r();++av.length)return t;var i,o=u[r-1];return null!=d&&r>=v.length?i=t.entries():(i=[],t.each(function(t,n){i.push({key:n,values:e(t,r)})})),null!=o?i.sort(function(t,n){return o(t.key,n.key)}):i}(h(t,0,le,he),0)},key:function(t){return v.push(t),n},sortKeys:function(t){return u[v.length-1]=t,n},sortValues:function(t){return p=t,n},rollup:function(t){return d=t,n}}},I.set=de,I.map=ce,I.keys=function(t){var n=[];for(var e in t)n.push(e);return n},I.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},I.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},I.color=Et,I.rgb=Pt,I.hsl=qt,I.lab=Ft,I.hcl=Xt,I.cubehelix=$t,I.dispatch=z,I.drag=function(){function d(t){t.on("mousedown.drag",n).filter(g).on("touchstart.drag",i).on("touchmove.drag",o).on("touchend.drag touchcancel.drag",u).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function n(){if(!l&&h.apply(this,arguments)){var t=a("mouse",p.apply(this,arguments),pt,this,arguments);t&&(ct(I.event.view).on("mousemove.drag",e,!0).on("mouseup.drag",r,!0),_t(I.event.view),vt(),f=!1,c=I.event.clientX,s=I.event.clientY,t("start"))}}function e(){if(gt(),!f){var t=I.event.clientX-c,n=I.event.clientY-s;f=xl.index){var c=h-o.x-o.vx,s=p-o.y-o.vy,f=c*c+s*s;ft.r&&(t.r=t[n].r)}function e(){if(o){var t,n,e=o.length;for(u=new Array(e),t=0;tyr(r[0],r[1])&&(r[1]=i[1]),yr(i[0],r[1])>yr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=yr(r[1],i[0]))>u&&(u=a,hh=i[0],dh=r[1])}return xh=bh=null,hh===1/0||ph===1/0?[[NaN,NaN],[NaN,NaN]]:[[hh,ph],[dh,vh]]},I.geoCentroid=function(t){wh=Mh=Th=Nh=kh=Sh=Eh=Ah=Ch=zh=Ph=0,Ke(t,lp);var n=Ch,e=zh,r=Ph,i=n*n+e*e+r*r;return i<1e-12&&(n=Sh,e=Eh,r=Ah,Mhe.x&&(e=t),t.depth>r.depth&&(r=t)});var i=n===e?1:m(n,e)/2,o=i-n.x,u=h/(e.x+i+o),a=p/(r.depth||1);c.eachBefore(function(t){t.x=(t.x+o)*u,t.y=t.depth*a})}return c}function s(u){var t=u.children,n=u.parent.children,e=u.i?n[u.i-1]:null;if(t){!function(t){for(var n,e=0,r=0,i=u.children,o=i.length;0<=--o;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}();var r=(t[0].z+t[t.length-1].z)/2;e?(u.z=e.z+m(u._,e._),u.m=u.z-r):u.z=r}else e&&(u.z=e.z+m(u._,e._));u.parent.A=function(t,n,e){if(n){for(var r,i=t,o=t,u=n,a=i.parent.children[0],c=i.m,s=o.m,f=u.m,l=a.m;u=Fo(u),i=Oo(i),u&&i;)a=Oo(a),(o=Fo(o)).a=t,0<(r=u.z+f-i.z-c+m(u._,i._))&&(_=t,y=e,h=(g=u).a.parent===_.parent?g.a:y,void 0,v=(d=r)/((p=t).i-h.i),p.c-=v,p.s+=d,h.c+=v,p.z+=d,p.m+=d,c+=r,s+=r),f+=u.m,c+=i.m,l+=a.m,s+=o.m;u&&!Fo(o)&&(o.t=u,o.m+=f-s),i&&!Oo(a)&&(a.t=i,a.m+=c-l,e=t)}var h,p,d,v,g,_,y;return e}(u,e,u.parent.A||n[0])}function f(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function l(t){t.x*=h,t.y=t.depth*p}var m=Uo,h=1,p=1,d=null;return n.separation=function(t){return arguments.length?(m=t,n):m},n.size=function(t){return arguments.length?(d=!1,h=+t[0],p=+t[1],n):d?null:[h,p]},n.nodeSize=function(t){return arguments.length?(d=!0,h=+t[0],p=+t[1],n):d?[h,p]:null},n},I.treemap=function(){function n(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(e),a=[0],r&&t.eachBefore(Ro),t}function e(t){var n=a[t.depth],e=t.x0+n,r=t.y0+n,i=t.x1-n,o=t.y1-n;i>>1;m[p]a!=avg?(y+=S*=p?1:-1,m-=S):(x=0,y=m=(f+l)/2),(b-=2*E)>vg?(g+=E*=p?1:-1,_-=E):(b=0,g=_=(f+l)/2)}var A=s*fg(g),C=s*pg(g),z=c*fg(m),P=c*pg(m);if(vgZf&&e.name===n)return new Ln([[t]],yl,n,+r);return null},I.interrupt=zn,I.voronoi=function(){function n(r){return new ss(r.map(function(t,n){var e=[Math.round(i(t,n,r)/Jg)*Jg,Math.round(o(t,n,r)/Jg)*Jg];return e.index=n,e.data=t,e}),e)}var i=Bc,o=Hc,e=null;return n.polygons=function(t){return n(t).polygons()},n.links=function(t){return n(t).links()},n.triangles=function(t){return n(t).triangles()},n.x=function(t){return arguments.length?(i="function"==typeof t?t:Yc(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:Yc(+t),n):o},n.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],n):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},n.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],n):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},n},I.zoom=function(){function u(t){t.property("__zoom",_s).on("wheel.zoom",n).on("mousedown.zoom",e).on("dblclick.zoom",r).filter(x).on("touchstart.zoom",i).on("touchmove.zoom",c).on("touchend.zoom touchcancel.zoom",s).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(t,n){return(n=Math.max(b[0],Math.min(b[1],n)))===t.k?t:new ls(n,t.x,t.y)}function d(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ls(t.k,r,i)}function f(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function o(t,c,s){t.on("start.zoom",function(){v(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){v(this,arguments).end()}).tween("zoom",function(){var t=arguments,r=v(this,t),n=_.apply(this,t),i=s||f(n),o=Math.max(n[1][0]-n[0][0],n[1][1]-n[0][1]),e=this.__zoom,u="function"==typeof c?c.apply(this,t):c,a=T(e.invert(i).concat(o/e.k),u.invert(i).concat(o/u.k));return function(t){if(1===t)t=u;else{var n=a(t),e=o/n[2];t=new ls(e,i[0]-n[0]*e,i[1]-n[1]*e)}r.zoom(null,t)}})}function v(t,n){for(var e,r=0,i=N.length;r 0) - resultTimeValue = hour * 3600; - resultTimeValue += min * 60; - - return resultTimeValue; -} - -function convertSummaryTimeToBadgeString(summaryTime) { - var sec = (summaryTime); - var min = (summaryTime / 60).toFixed(0); - var hours = (summaryTime / (60 * 60)).toFixed(1); - var days = (summaryTime / (60 * 60 * 24)).toFixed(0); - - if (sec < 60) { - return sec + "s"; - } else if (min < 60) { - return min + "m"; - } else if (hours < 24) { - return hours + "h"; - } else { - return days + "d" - } -} - -function convertShortSummaryTimeToString(summaryTime) { - var hours = Math.floor(summaryTime / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - - return hours + 'h : ' + mins + 'm'; -} - -function convertShortSummaryTimeToLongString(summaryTime) { - var hours = Math.floor(summaryTime / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - - return `${hours} hour ${mins} minutes`; -} - -function getArrayTime(summaryTime) { - var days = Math.floor(summaryTime / 3600 / 24); - var totalHours = summaryTime % (3600 * 24); - var hours = Math.floor(totalHours / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - var seconds = totalSeconds % 60; - - days = zeroAppend(days); - hours = zeroAppend(hours); - mins = zeroAppend(mins); - seconds = zeroAppend(seconds); - - return { - 'days': days, - 'hours': hours, - 'mins': mins, - 'seconds': seconds - }; -} - -function convertSummaryTimeToString(summaryTime) { - var days = Math.floor(summaryTime / 3600 / 24); - var totalHours = summaryTime % (3600 * 24); - var hours = Math.floor(totalHours / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - var seconds = totalSeconds % 60; - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - seconds = zeroAppend(seconds); - - if (days > 0) - return days + 'd ' + hours + 'h ' + mins + 'm ' + seconds + 's'; - else return hours + 'h ' + mins + 'm ' + seconds + 's'; -} - -function zeroAppend(time) { - if (time < 10) - return '0' + time; - else return time; -} - -function isDateInRange(dateStr, range) { - return new Date(dateStr) >= range.from && new Date(dateStr) <= range.to; -} - -function isCorrectDate(range) { - return range.from.getFullYear() >= 2019 && range.to.getFullYear() >= 2019; -} - -function getDateFromRange(range) { - switch (range) { - case 'days2': - return 2; - case 'days3': - return 3; - case 'days4': - return 4; - case 'days5': - return 5; - case 'days6': - return 6; - case 'days7': - return 7; - case 'month1': - return 30; - case 'month2': - return 60; - case 'month3': - return 90; - } -} - -function isDomainEquals(first, second) { - if (first === second) - return true; - else { - var resultUrl = function(url) { - if (url.indexOf('www.') > -1) - return url.split('www.')[1]; - return url; - }; - - if (resultUrl(first) === resultUrl(second)) - return true; - else return false; - } -} - -function extractHostname(url) { - var hostname; - - if (url.indexOf("//") > -1) { - hostname = url.split('/')[2]; - } - else { - hostname = url.split('/')[0]; - } - - hostname = hostname.split(':')[0]; - hostname = hostname.split('?')[0]; - - return hostname; -} - -function treatAsUTC(date) { - var result = new Date(date); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; -} - -function daysBetween(startDate, endDate) { - var millisecondsPerDay = 24 * 60 * 60 * 1000; - return ((treatAsUTC(endDate) - treatAsUTC(startDate)) / millisecondsPerDay) + 1; -} - -function todayLocalDate(){ - return new Date().toLocaleDateString('en-US'); -} \ No newline at end of file diff --git a/src/scripts/picker/clockpicker.min.js b/src/scripts/picker/clockpicker.min.js deleted file mode 100644 index 5283942..0000000 --- a/src/scripts/picker/clockpicker.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var P,t,i,e,x=window.jQuery,o=x(window),S=x(document),s="http://www.w3.org/2000/svg",E="SVGAngle"in window&&((i=document.createElement("div")).innerHTML="",t=(i.firstChild&&i.firstChild.namespaceURI)==s,i.innerHTML="",t),c="transition"in(e=document.createElement("div").style)||"WebkitTransition"in e||"MozTransition"in e||"msTransition"in e||"OTransition"in e,n="ontouchstart"in window,D="mousedown"+(n?" touchstart":""),I="mousemove.clockpicker"+(n?" touchmove.clockpicker":""),B="mouseup.clockpicker"+(n?" touchend.clockpicker":""),d=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null;function z(t){return document.createElementNS(s,t)}function O(t){return(t<10?"0":"")+t}var j=0;var L=100,U=80,W=13,N=c?350:1,X=['
    ','
    ','
    ',''," : ",'','',"
    ",'
    ','
    ','
    ','
    ','
    ',"
    ",'',"","
    ","
    "].join("");function a(t,h){var i,e,s=x(X),u=s.find(".clockpicker-plate"),o=s.find(".clockpicker-hours"),c=s.find(".clockpicker-minutes"),n=s.find(".clockpicker-am-pm-block"),a="INPUT"===t.prop("tagName"),r=a?t:t.find("input"),p=t.find(".input-group-addon"),k=this;if(this.id=(e=++j+"",(i="cp")?i+e:e),this.element=t,this.options=h,this.isAppended=!1,this.isShown=!1,this.currentView="hours",this.isInput=a,this.input=r,this.addon=p,this.popover=s,this.plate=u,this.hoursView=o,this.minutesView=c,this.amPmBlock=n,this.spanHours=s.find(".clockpicker-span-hours"),this.spanMinutes=s.find(".clockpicker-span-minutes"),this.spanAmPm=s.find(".clockpicker-span-am-pm"),this.amOrPm="PM",h.twelvehour){var l=['
    ','",'","
    "].join("");x(l);x('').on("click",function(){k.amOrPm="AM",x(".clockpicker-span-am-pm").empty().append("AM")}).appendTo(this.amPmBlock),x('').on("click",function(){k.amOrPm="PM",x(".clockpicker-span-am-pm").empty().append("PM")}).appendTo(this.amPmBlock)}h.autoclose||x('").click(x.proxy(this.done,this)).appendTo(s),"top"!==h.placement&&"bottom"!==h.placement||"top"!==h.align&&"bottom"!==h.align||(h.align="left"),"left"!==h.placement&&"right"!==h.placement||"left"!==h.align&&"right"!==h.align||(h.align="top"),s.addClass(h.placement),s.addClass("clockpicker-align-"+h.align),this.spanHours.click(x.proxy(this.toggleView,this,"hours")),this.spanMinutes.click(x.proxy(this.toggleView,this,"minutes")),r.on("focus.clockpicker click.clockpicker",x.proxy(this.show,this)),p.on("click.clockpicker",x.proxy(this.toggle,this));var d,f,v,m,b=x('
    ');if(h.twelvehour)for(d=1;d<13;d+=1)f=b.clone(),v=d/6*Math.PI,m=U,f.css("font-size","120%"),f.css({left:L+Math.sin(v)*m-W,top:L-Math.cos(v)*m-W}),f.html(0===d?"00":d),o.append(f),f.on(D,w);else for(d=0;d<24;d+=1){f=b.clone(),v=d/6*Math.PI;var g=0=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=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)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,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(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===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]||oe.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]&&oe.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&&X.test(n)&&(t=a(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(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!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!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.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:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.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,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.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||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(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&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(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&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!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 i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.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=w.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}},tt.prototype.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=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.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)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,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":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.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 w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + diff --git a/src/welcome.ts b/src/welcome.ts new file mode 100644 index 0000000..c7d5b0e --- /dev/null +++ b/src/welcome.ts @@ -0,0 +1,7 @@ +import Welcome from './pages/Welcome.vue'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Welcome); +app.use(i18n); +app.mount('body'); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..280fa00 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true, + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..9d31e2a --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..cf14fdb --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,73 @@ +import { defineConfig } from 'vite'; +import path from 'path'; +import vue from '@vitejs/plugin-vue'; +import webExtension, { readJsonFile } from 'vite-plugin-web-extension'; +import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; +import copy from 'rollup-plugin-copy'; + +const APP_ID = { + chrome: 'hhfnghjdeddcfegfekjeihfmbjenlomm', + edge: 'eepmlmdenlkkjieghjmedjahpofieogf', +}; +const browser = process.env.TARGET || 'chrome'; + +function generateManifest() { + const manifest = readJsonFile('src/manifest.json'); + const pkg = readJsonFile('package.json'); + return { + name: pkg.name, + description: pkg.description, + version: pkg.version, + ...manifest, + }; +} + +// https://vitejs.dev/config/ +export default defineConfig(({ mode }) => ({ + build: { + assetsInlineLimit: 1024, + rollupOptions: { + output: { + assetFileNames: assetInfo => { + let extType = assetInfo.name.split('.').at(1); + if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) { + extType = 'icons'; + } + return `assets/${extType}/[name][extname]`; + }, + }, + }, + + emptyOutDir: false, + sourcemap: mode === 'development' ? 'inline' : false, + minify: mode === 'development' ? false : true, + }, + define: { + 'process.env': process.env, + __EXTENSION_MODE__: JSON.stringify(mode), + __DEV__: mode === 'development', + __PROD__: mode === 'production', + __APP_ID__: JSON.stringify(APP_ID[browser]), + __BROWSER__: JSON.stringify(browser), + }, + plugins: [ + vue(), + VueI18nPlugin({ + include: path.resolve(__dirname, '..', 'src/assets/_locales/*'), + }), + webExtension({ + manifest: generateManifest, + watchFilePaths: ['package.json', 'manifest.json'], + additionalInputs: ['src/block.html', 'src/welcome.html', 'src/offscreen.html'], + }), + copy({ + targets: [ + { src: 'src/_locales', dest: 'dist' }, + { src: 'src/assets/pomodoro-sounds', dest: 'dist/assets' }, + ], + }), + ], + optimizeDeps: { + include: ['vue', 'webextension-polyfill'], + }, +}));