diff --git a/angular.json b/angular.json index b28e98b49..d16d206e2 100644 --- a/angular.json +++ b/angular.json @@ -18,7 +18,6 @@ "builder": "@angular-devkit/build-angular:browser", "options": { "aot": true, - "allowedCommonJsDependencies": ["angular-svg-round-progressbar", "lodash", "ajv"], "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", diff --git a/helper/config.js b/helper/config.js new file mode 100644 index 000000000..5f2e6f102 --- /dev/null +++ b/helper/config.js @@ -0,0 +1,56 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + +const Store = require('electron-store'); +const Ajv = require('ajv'); +const configSchema = require('./config.schema'); + +let store; +const ajv = new Ajv({ allErrors: true }); +const validate = ajv.compile(configSchema); + +function readConfig(window) { + try { + if (!store) { + store = new Store(); + } + const config = store.get('config'); + window.webContents.send('configRead', config); + } catch { + window.webContents.send('configError', "Can't read config file."); + } +} + +function saveConfig(window, config) { + if (validate(config)) { + try { + store.set('config', config); + window.webContents.send('configSaved', config); + } catch { + window.webContents.send('configError', "Can't save config file."); + } + } else { + window.webContents.send('configSaveFail', getConfigErrors()); + } +} + +function checkConfig(window, config) { + if (!validate(config)) { + window.webContents.send('configFail', getConfigErrors()); + } else { + window.webContents.send('configPass'); + } +} + +function getConfigErrors() { + const errors = []; + validate.errors?.forEach(error => { + if (error.keyword === 'type') { + errors.push(`${error.dataPath} ${error.message}`); + } else { + errors.push(`${error.dataPath === '' ? '.' : error.dataPath} ${error.message}`); + } + }); + return errors; +} + +module.exports = { readConfig, saveConfig, checkConfig }; diff --git a/src/app/config/config.schema.ts b/helper/config.schema.js similarity index 99% rename from src/app/config/config.schema.ts rename to helper/config.schema.js index 566ee1154..ea3ea6107 100644 --- a/src/app/config/config.schema.ts +++ b/helper/config.schema.js @@ -1,4 +1,4 @@ -export const configSchema = { +const configSchema = { definitions: {}, $schema: 'http://json-schema.org/draft-07/schema#', $id: 'http://example.com/root.json', @@ -322,3 +322,5 @@ export const configSchema = { }, }, }; + +module.exports = configSchema; diff --git a/helper/discover.js b/helper/discover.js index 5bd8a70be..0e65e1972 100644 --- a/helper/discover.js +++ b/helper/discover.js @@ -16,7 +16,7 @@ function discoverNodes(window) { id: service.addresses[0] + service.port, name: service.name, version: service.txt.version, - url: `http://${service.host.replace(/\.$/, '')}:${service.port}${service.txt.path}api/`, + url: `http://${service.host.replace(/\.$/, '')}:${service.port}${service.txt.path}`, disable: compareVersions(minimumVersion, service.txt.version) === -1, }); sendNodes(window); diff --git a/helper/listener.js b/helper/listener.js index e1dc2ebaf..d0b1b3d2c 100644 --- a/helper/listener.js +++ b/helper/listener.js @@ -1,22 +1,20 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable import/no-commonjs */ const exec = require('child_process').exec; -const waitPort = require('wait-port'); const sendCustomStyles = require('./styles'); const { downloadUpdate, sendVersionInfo } = require('./update'); const { discoverNodes, stopDiscovery } = require('./discover'); +const { readConfig, saveConfig, checkConfig } = require('./config'); function activateScreenSleepListener(ipcMain) { - ipcMain.on('screenControl', (_, screenCommand) => { - exec(screenCommand.command); - }); + ipcMain.on('screenControl', (_, screenCommand) => exec(screenCommand.command)); } function activateReloadListener(ipcMain, window, dev) { ipcMain.on('reload', () => { if (dev) { - window.reload(); + window.loadURL('http://localhost:4200'); } else { window.loadURL('app://.'); } @@ -31,42 +29,23 @@ function activateAppInfoListener(ipcMain, window, app) { } function activateUpdateListener(ipcMain, window) { - ipcMain.on('update', (_, updateInfo) => { - downloadUpdate(updateInfo, window); - }); + ipcMain.on('update', (_, updateInfo) => downloadUpdate(updateInfo, window)); } function activateDiscoverListener(ipcMain, window) { - ipcMain.on('discover', () => { - discoverNodes(window); - }); + ipcMain.on('discover', () => discoverNodes(window)); - ipcMain.on('stopDiscover', () => { - stopDiscovery(); - }); + ipcMain.on('stopDiscover', () => stopDiscovery()); } -function activatePortListener(ipcMain, window) { - ipcMain.on('checkOctoPrintPort', (_, hostInfo) => { - const waitPortParams = { - host: hostInfo.host, - port: hostInfo.port, - output: 'silent', - timeout: 60000, - }; - - waitPort(waitPortParams) - .then(open => { - window.webContents.send('octoprintReady', open); - }) - .catch(error => { - window.webContents.send('waitPortError', error); - }); - }); +function activateConfigListener(ipcMain, window) { + ipcMain.on('readConfig', () => readConfig(window)); + ipcMain.on('saveConfig', (_, config) => saveConfig(window, config)); + ipcMain.on('checkConfig', (_, config) => checkConfig(window, config)); } function activateListeners(ipcMain, window, app, dev) { - activatePortListener(ipcMain, window); + activateConfigListener(ipcMain, window); activateAppInfoListener(ipcMain, window, app); activateScreenSleepListener(ipcMain); activateReloadListener(ipcMain, window, dev); diff --git a/main.js b/main.js index 013689230..cea45d0d5 100644 --- a/main.js +++ b/main.js @@ -10,21 +10,24 @@ const Store = require('electron-store'); const args = process.argv.slice(1); const big = args.some(val => val === '--big'); const dev = args.some(val => val === '--serve'); -const scheme = 'app'; const activateListeners = require('./helper/listener'); -const createProtocol = require('./helper/protocol'); -protocol.registerSchemesAsPrivileged([{ scheme: scheme, privileges: { standard: true } }]); -createProtocol(scheme, path.join(__dirname, 'dist')); +if (!dev) { + const createProtocol = require('./helper/protocol'); + const scheme = 'app'; -app.commandLine.appendSwitch('touch-events', 'enabled'); + protocol.registerSchemesAsPrivileged([{ scheme: scheme, privileges: { standard: true } }]); + createProtocol(scheme, path.join(__dirname, 'dist')); +} -const store = new Store(); +app.commandLine.appendSwitch('touch-events', 'enabled'); let window; function createWindow() { + const _store = new Store(); + if (!dev) { session.defaultSession.webRequest.onHeadersReceived((details, callback) => { callback({ diff --git a/package-lock.json b/package-lock.json index 9350ba583..d37ec658d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,14 +28,15 @@ "compare-versions": "^3.6.0", "electron-store": "^7.0.2", "got": "^11.8.2", - "lodash": "^4.17.21", + "lodash-es": "^4.17.20", + "lottie-web": "^5.7.6", "ngx-electron": "^2.2.0", + "ngx-lottie": "^6.4.0", "ngx-spinner": "^10.0.1", "progress-stream": "^2.0.0", "rxjs": "~6.6.6", "tslib": "^2.1.0", "v8-compile-cache": "^2.3.0", - "wait-port": "^0.2.9", "zone.js": "~0.11.4" }, "devDependencies": { @@ -46,7 +47,7 @@ "@types/ajv": "^1.0.0", "@types/bonjour": "^3.5.8", "@types/got": "^9.6.11", - "@types/lodash": "^4.14.168", + "@types/lodash-es": "^4.17.4", "@types/node": "12.20.6", "@typescript-eslint/eslint-plugin": "^4.18.0", "@typescript-eslint/parser": "^4.18.0", @@ -4682,6 +4683,15 @@ "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", "dev": true }, + "node_modules/@types/lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -5388,6 +5398,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -6994,6 +7005,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -7404,6 +7416,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -7411,7 +7424,8 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "node_modules/color-string": { "version": "1.5.4", @@ -8688,9 +8702,10 @@ } }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -10014,6 +10029,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, "engines": { "node": ">=0.8.0" } @@ -11734,6 +11750,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, "engines": { "node": ">=4" } @@ -13547,9 +13564,15 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -13652,6 +13675,11 @@ "url": "https://tidelift.com/funding/github/npm/loglevel" } }, + "node_modules/lottie-web": { + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.7.6.tgz", + "integrity": "sha512-qn/KYMI4QQvFDhtoxs0RPkn9uZKhDB9keE5BKgbJlSRfNEZpRiDlwBE9ibYz4nPhbyE+NUlt8IRIVR7g5OSX3w==" + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -14236,7 +14264,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/multicast-dns": { "version": "6.2.3", @@ -14370,6 +14399,19 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/ngx-lottie": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-6.4.0.tgz", + "integrity": "sha512-RuXljkSOpZyt/NLL2X89gNMIxvGrj/D1rRN4qrOrAZHdREeGAIapqvrldJpQDeiThkHeNfyWfmnDavhJfP/DHA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": ">=8.0.0", + "lottie-web": ">=5.4.0", + "rxjs": ">=6.0.0" + } + }, "node_modules/ngx-spinner": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-10.0.1.tgz", @@ -20419,6 +20461,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -21589,27 +21632,6 @@ "node": ">=8.9.0" } }, - "node_modules/wait-port": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.9.tgz", - "integrity": "sha512-hQ/cVKsNqGZ/UbZB/oakOGFqic00YAMM5/PEj3Bt4vKarv2jWIWzDbqlwT94qMs/exAQAsvMOq99sZblV92zxQ==", - "dependencies": { - "chalk": "^2.4.2", - "commander": "^3.0.2", - "debug": "^4.1.1" - }, - "bin": { - "wait-port": "bin/wait-port.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wait-port/node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" - }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -27337,6 +27359,15 @@ "integrity": "sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==", "dev": true }, + "@types/lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -27917,6 +27948,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -29242,6 +29274,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -29587,6 +29620,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -29594,7 +29628,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "color-string": { "version": "1.5.4", @@ -30672,9 +30707,10 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -31745,7 +31781,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eslint": { "version": "7.22.0", @@ -33149,7 +33186,8 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { "version": "1.0.1", @@ -34618,9 +34656,15 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash-es": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==" }, "lodash.memoize": { "version": "4.1.2", @@ -34700,6 +34744,11 @@ "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", "dev": true }, + "lottie-web": { + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.7.6.tgz", + "integrity": "sha512-qn/KYMI4QQvFDhtoxs0RPkn9uZKhDB9keE5BKgbJlSRfNEZpRiDlwBE9ibYz4nPhbyE+NUlt8IRIVR7g5OSX3w==" + }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -35171,7 +35220,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "multicast-dns": { "version": "6.2.3", @@ -35288,6 +35338,14 @@ } } }, + "ngx-lottie": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-6.4.0.tgz", + "integrity": "sha512-RuXljkSOpZyt/NLL2X89gNMIxvGrj/D1rRN4qrOrAZHdREeGAIapqvrldJpQDeiThkHeNfyWfmnDavhJfP/DHA==", + "requires": { + "tslib": "^2.0.0" + } + }, "ngx-spinner": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/ngx-spinner/-/ngx-spinner-10.0.1.tgz", @@ -40253,6 +40311,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -41195,23 +41254,6 @@ "rxjs": "^6.6.3" } }, - "wait-port": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.9.tgz", - "integrity": "sha512-hQ/cVKsNqGZ/UbZB/oakOGFqic00YAMM5/PEj3Bt4vKarv2jWIWzDbqlwT94qMs/exAQAsvMOq99sZblV92zxQ==", - "requires": { - "chalk": "^2.4.2", - "commander": "^3.0.2", - "debug": "^4.1.1" - }, - "dependencies": { - "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" - } - } - }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", diff --git a/package.json b/package.json index 1ecd901b8..34f21dac7 100644 --- a/package.json +++ b/package.json @@ -90,14 +90,15 @@ "compare-versions": "^3.6.0", "electron-store": "^7.0.2", "got": "^11.8.2", - "lodash": "^4.17.21", + "lodash-es": "^4.17.20", + "lottie-web": "^5.7.6", "ngx-electron": "^2.2.0", + "ngx-lottie": "^6.4.0", "ngx-spinner": "^10.0.1", "progress-stream": "^2.0.0", "rxjs": "~6.6.6", "tslib": "^2.1.0", "v8-compile-cache": "^2.3.0", - "wait-port": "^0.2.9", "zone.js": "~0.11.4" }, "devDependencies": { @@ -108,7 +109,7 @@ "@types/ajv": "^1.0.0", "@types/bonjour": "^3.5.8", "@types/got": "^9.6.11", - "@types/lodash": "^4.14.168", + "@types/lodash-es": "^4.17.4", "@types/node": "12.20.6", "@typescript-eslint/eslint-plugin": "^4.18.0", "@typescript-eslint/parser": "^4.18.0", diff --git a/src/app/app.component.html b/src/app/app.component.html index fd32e7b74..62a352c7b 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -8,8 +8,8 @@ >{{ status }} - Initializing is taking longer than usual. Please make sure that your printer is connected.
- Trying again every 15 seconds. + Initializing is taking longer than usual.
+ Please make sure that OctoPrint is up and running.
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3a765d54d..9c724c119 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,46 +1,37 @@ -import { Component, NgZone, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import _ from 'lodash'; -import { ElectronService } from 'ngx-electron'; import { AppService } from './app.service'; import { ConfigService } from './config/config.service'; -import { NotificationService } from './notification/notification.service'; +import { SocketService } from './services/socket/socket.service'; +// TODO: Upgrading settings killed OctoDash @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit { + public activated = false; + public status = 'initializing'; + public showConnectionHint = false; + public constructor( private service: AppService, private configService: ConfigService, - private notificationService: NotificationService, + private socketService: SocketService, private router: Router, - private electronService: ElectronService, - private zone: NgZone, ) {} - public activated = false; - public status = 'connecting'; - public showConnectionHint = false; - public ngOnInit(): void { this.initialize(); } private initialize(): void { - if (!this.electronService.isElectronApp) { - this.notificationService.setWarning( - 'Non electron environment detected!', - 'The app may not work as intended. If you run an official build please open a new issue on GitHub.', - ); - } if (this.configService && this.configService.isInitialized()) { if (this.configService.isLoaded()) { if (this.configService.isValid()) { - this.waitForOctoPrint(); + this.connectWebsocket(); } else { this.checkInvalidConfig(); } @@ -67,63 +58,19 @@ export class AppComponent implements OnInit { } } - private waitForOctoPrint() { - this.electronService.ipcRenderer.on('octoprintReady', (_, octoprintReady: boolean) => { - this.zone.run(() => { - if (octoprintReady) { - this.connectWebsocket(); - this.status = 'initializing'; + private connectWebsocket() { + const showPrinterConnectedTimeout = setTimeout(() => { + this.showConnectionHint = true; + }, 30000); + this.socketService + .connect() + .then(() => { + if (this.configService.isTouchscreen()) { + this.router.navigate(['/main-screen']); } else { - this.notificationService - .setWarning( - 'Connection to OctoPrint timed out!', - 'Make sure that OctoPrint is up and running, then close this card to try again.', - ) - .then(this.checkOctoPrintPort.bind(this)); - this.status = 'no connection'; + this.router.navigate(['/main-screen-no-touch']); } - }); - }); - - this.electronService.ipcRenderer.on('waitPortError', (_, error: Error) => { - this.zone.run(() => { - this.notificationService.setError('System Error - please restart', error.message); - }); - }); - - this.checkOctoPrintPort(); - } - - private checkOctoPrintPort() { - this.status = 'connecting'; - const urlNoProtocol = this.configService.getURL('').split('//')[1]; - this.electronService.ipcRenderer.send('checkOctoPrintPort', { - host: urlNoProtocol.split(':')[0], - port: Number(urlNoProtocol.split(':')[1].split('/')[0]), - }); - } - - private connectWebsocket() { - if (this.configService.isTouchscreen()) { - this.router.navigate(['/main-screen']); - } else { - this.router.navigate(['/main-screen-no-touch']); - } - // const showPrinterConnectedTimeout = setTimeout(() => { - // this.showConnectionHint = true; - // }, 30000); - // this.octoprintScriptService - // .initialize(this.configService.getURL(''), this.configService.getAccessKey()) - // .then(() => { - // this.octoprintScriptService.authenticate(this.configService.getAccessKey()); - // }) - // .catch(() => { - // console.log('REJECTED'); - // this.notificationService.setError( - // "Can't get OctoPrint script!", - // 'Please restart your machine. If the error persists open a new issue on GitHub.', - // ); - // }) - // .finally(() => clearTimeout(showPrinterConnectedTimeout)); + }) + .finally(() => clearTimeout(showPrinterConnectedTimeout)); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 72cb74b91..7cb00e163 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,4 +1,4 @@ -import { HttpClientModule } from '@angular/common/http'; +import { HttpClient, HttpClientModule } from '@angular/common/http'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatRippleModule } from '@angular/material/core'; @@ -7,8 +7,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { fas } from '@fortawesome/free-solid-svg-icons'; import { RoundProgressModule } from 'angular-svg-round-progressbar'; +import player, { LottiePlayer } from 'lottie-web'; import { NgxElectronModule } from 'ngx-electron'; -import { NgxSpinnerModule } from 'ngx-spinner'; +import { LottieModule } from 'ngx-lottie'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app.routing.module'; @@ -24,13 +25,18 @@ import { PluginsComponent } from './config/setup/plugins/plugins.component'; import { ConfigSetupComponent } from './config/setup/setup.component'; import { WelcomeComponent } from './config/setup/welcome/welcome.component'; import { ControlComponent } from './control/control.component'; +import { CustomActionsComponent } from './control/custom-actions/custom-actions.component'; +import { ConversionService } from './conversion.service'; +import { EventService } from './event.service'; +import { ChangeFilamentComponent } from './filament/change-filament/change-filament.component'; import { ChooseFilamentComponent } from './filament/choose-filament/choose-filament.component'; import { FilamentComponent } from './filament/filament.component'; import { HeatNozzleComponent } from './filament/heat-nozzle/heat-nozzle.component'; +import { MoveFilamentComponent } from './filament/move-filament/move-filament.component'; +import { PurgeFilamentComponent } from './filament/purge-filament/purge-filament.component'; import { FilesComponent } from './files/files.component'; -import { JobService } from './job.service'; +import { HeightProgressComponent } from './height-progress/height-progress.component'; import { JobStatusComponent } from './job-status/job-status.component'; -import { LayerProgressComponent } from './layer-progress/layer-progress.component'; import { LongPress } from './long-press.directive'; import { MainMenuComponent } from './main-menu/main-menu.component'; import { MainScreenComponent } from './main-screen/main-screen.component'; @@ -38,17 +44,29 @@ import { MainScreenNoTouchComponent } from './main-screen/no-touch/main-screen-n import { NotificationComponent } from './notification/notification.component'; import { NotificationService } from './notification/notification.service'; import { PrintControlComponent } from './print-control/print-control.component'; -import { PrinterService } from './printer.service'; import { PrinterStatusComponent } from './printer-status/printer-status.component'; +import { EnclosureOctoprintService } from './services/enclosure/enclosure.octoprint.service'; +import { EnclosureService } from './services/enclosure/enclosure.service'; +import { FilamentManagerOctoprintService } from './services/filament/filament-manager.octoprint.service'; +import { FilamentPluginService } from './services/filament/filament-plugin.service'; +import { FilesOctoprintService } from './services/files/files.octoprint.service'; +import { FilesService } from './services/files/files.service'; +import { JobOctoprintService } from './services/job/job.octoprint.service'; +import { JobService } from './services/job/job.service'; +import { PrinterOctoprintService } from './services/printer/printer.octoprint.service'; +import { PrinterService } from './services/printer/printer.service'; +import { OctoPrintSocketService } from './services/socket/socket.octoprint.service'; +import { SocketService } from './services/socket/socket.service'; +import { SystemOctoprintService } from './services/system/system.octoprint.service'; +import { SystemService } from './services/system/system.service'; import { SettingsComponent } from './settings/settings.component'; import { StandbyComponent } from './standby/standby.component'; import { UpdateComponent } from './update/update.component'; import { URLSafePipe } from './url.pipe'; -import { MoveFilamentComponent } from './filament/move-filament/move-filament.component'; -import { ChangeFilamentComponent } from './filament/change-filament/change-filament.component'; -import { PurgeFilamentComponent } from './filament/purge-filament/purge-filament.component'; -import { CustomActionsComponent } from './control/custom-actions/custom-actions.component'; +export function playerFactory(): LottiePlayer { + return player; +} @NgModule({ declarations: [ AppComponent, @@ -62,7 +80,7 @@ import { CustomActionsComponent } from './control/custom-actions/custom-actions. FilamentComponent, FilesComponent, JobStatusComponent, - LayerProgressComponent, + HeightProgressComponent, LongPress, MainMenuComponent, MainScreenComponent, @@ -93,10 +111,105 @@ import { CustomActionsComponent } from './control/custom-actions/custom-actions. HttpClientModule, MatRippleModule, NgxElectronModule, - NgxSpinnerModule, RoundProgressModule, + [LottieModule.forRoot({ player: playerFactory })], + ], + providers: [ + AppService, + ConfigService, + ConversionService, + EventService, + NotificationService, + [ + { + provide: SystemService, + deps: [ConfigService, NotificationService, HttpClient], + useFactory: ( + configService: ConfigService, + notificationService: NotificationService, + httpClient: HttpClient, + ) => { + return new SystemOctoprintService(configService, notificationService, httpClient); + }, + }, + ], + [ + { + provide: SocketService, + deps: [ConfigService, SystemService, ConversionService, HttpClient], + useFactory: ( + configService: ConfigService, + systemService: SystemService, + conversionService: ConversionService, + httpClient: HttpClient, + ) => { + return new OctoPrintSocketService(configService, systemService, conversionService, httpClient); + }, + }, + ], + [ + { + provide: PrinterService, + deps: [ConfigService, NotificationService, HttpClient], + useFactory: ( + configService: ConfigService, + notificationService: NotificationService, + httpClient: HttpClient, + ) => { + return new PrinterOctoprintService(configService, notificationService, httpClient); + }, + }, + ], + [ + { + provide: JobService, + deps: [ConfigService, NotificationService, HttpClient], + useFactory: ( + configService: ConfigService, + notificationService: NotificationService, + httpClient: HttpClient, + ) => { + return new JobOctoprintService(configService, notificationService, httpClient); + }, + }, + ], + [ + { + provide: FilesService, + deps: [ConfigService, NotificationService, HttpClient, ConversionService], + useFactory: ( + configService: ConfigService, + notificationService: NotificationService, + httpClient: HttpClient, + conversionService: ConversionService, + ) => { + return new FilesOctoprintService(configService, notificationService, httpClient, conversionService); + }, + }, + ], + [ + { + provide: FilamentPluginService, + deps: [ConfigService, HttpClient], + useFactory: (configService: ConfigService, httpClient: HttpClient) => { + return new FilamentManagerOctoprintService(configService, httpClient); + }, + }, + ], + [ + { + provide: EnclosureService, + deps: [ConfigService, NotificationService, HttpClient], + useFactory: ( + configService: ConfigService, + notificationService: NotificationService, + httpClient: HttpClient, + ) => { + return new EnclosureOctoprintService(configService, notificationService, httpClient); + }, + }, + ], ], - providers: [AppService, ConfigService, NotificationService, PrinterService, JobService], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) diff --git a/src/app/app.service.ts b/src/app/app.service.ts index 79fba41c9..c074a58a9 100644 --- a/src/app/app.service.ts +++ b/src/app/app.service.ts @@ -1,21 +1,19 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import _ from 'lodash'; +import _ from 'lodash-es'; import { ElectronService } from 'ngx-electron'; import { Config } from './config/config.model'; import { ConfigService } from './config/config.service'; import { NotificationService } from './notification/notification.service'; -@Injectable({ - providedIn: 'root', -}) +@Injectable() export class AppService { private updateError: Record void>; - private loadedFile = false; - public version: string; - public latestVersion: string; private latestVersionAssetsURL: string; + private version: string; + private latestVersion: string; + public updateAvailable = false; public constructor( @@ -48,20 +46,39 @@ export class AppService { }; } - // If all errors can be automatically fixed return true here + private checkUpdate(): void { + this.http.get('https://api.github.com/repos/UnchartedBull/OctoDash/releases/latest').subscribe( + (data: GitHubReleaseInformation): void => { + if (this.version !== data.name.replace('v', '')) { + this.updateAvailable = true; + } + this.latestVersion = data.name.replace('v', ''); + this.latestVersionAssetsURL = data.assets_url; + }, + (): void => null, + ); + setTimeout(this.checkUpdate.bind(this), 3600000); + } + + public hasUpdateError(errors: string[]): boolean { + return _.intersection(errors, _.keys(this.updateError)).length > 0; + } + public fixUpdateErrors(errors: string[]): boolean { const config = this.configService.getCurrentConfig(); - let fullyAutofixed = true; + config.octoprint.url = config.octoprint.url.replace('api/', ''); + + let fullyFixed = true; for (const error of errors) { if (_.hasIn(this.updateError, error)) { this.updateError[error](config); } else { - fullyAutofixed = false; + fullyFixed = false; } } this.configService.saveConfig(config); - return fullyAutofixed; + return fullyFixed; } private enableVersionListener(): void { @@ -83,20 +100,6 @@ export class AppService { }); } - private checkUpdate(): void { - this.http.get('https://api.github.com/repos/UnchartedBull/OctoDash/releases/latest').subscribe( - (data: GitHubReleaseInformation): void => { - if (this.version !== data.name.replace('v', '')) { - this.updateAvailable = true; - } - this.latestVersion = data.name.replace('v', ''); - this.latestVersionAssetsURL = data.assets_url; - }, - (): void => null, - ); - setTimeout(this.checkUpdate.bind(this), 3600000); - } - public getVersion(): string { return this.version; } @@ -105,60 +108,16 @@ export class AppService { return this.latestVersion; } - public turnDisplayOff(): void { - this.electronService.ipcRenderer.send('screenControl', { command: this.configService.getScreenSleepCommand() }); - } - - public turnDisplayOn(): void { - this.electronService.ipcRenderer.send('screenControl', { command: this.configService.getScreenWakeupCommand() }); - } - - public hasUpdateError(errors: string[]): boolean { - return _.intersection(errors, _.keys(this.updateError)).length > 0; - } - - public setLoadedFile(value: boolean): void { - this.loadedFile = value; - } - - public getLoadedFile(): boolean { - return this.loadedFile; - } - public getLatestVersionAssetsURL(): string { return this.latestVersionAssetsURL; } - public convertByteToMegabyte(byte: number): string { - return (byte / 1000000).toFixed(1); - } - - public convertDateToString(date: Date): string { - return `${('0' + date.getDate()).slice(-2)}.${('0' + (date.getMonth() + 1)).slice(-2)}.${date.getFullYear()} ${( - '0' + date.getHours() - ).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}:${('0' + date.getSeconds()).slice(-2)}`; - } - - public convertSecondsToHours(input: number): string { - const hours = input / 60 / 60; - let roundedHours = Math.floor(hours); - const minutes = (hours - roundedHours) * 60; - let roundedMinutes = Math.round(minutes); - if (roundedMinutes === 60) { - roundedMinutes = 0; - roundedHours += 1; - } - return roundedHours + ':' + ('0' + roundedMinutes).slice(-2); - } - - public convertFilamentLengthToWeight(filamentLength: number): number { - return this.convertFilamentVolumeToWeight( - (filamentLength * Math.PI * Math.pow(this.configService.getFilamentThickness() / 2, 2)) / 1000, - ); + public turnDisplayOff(): void { + this.electronService.ipcRenderer.send('screenControl', { command: this.configService.getScreenSleepCommand() }); } - private convertFilamentVolumeToWeight(filamentVolume: number): number { - return Math.round(filamentVolume * this.configService.getFilamentDensity() * 10) / 10; + public turnDisplayOn(): void { + this.electronService.ipcRenderer.send('screenControl', { command: this.configService.getScreenWakeupCommand() }); } } diff --git a/src/app/bottom-bar/bottom-bar.component.html b/src/app/bottom-bar/bottom-bar.component.html index d1fc7df9f..22214226c 100644 --- a/src/app/bottom-bar/bottom-bar.component.html +++ b/src/app/bottom-bar/bottom-bar.component.html @@ -1,12 +1,12 @@ - + -
{{ printer.name }}{{ getPrinterName() }} {{ enclosureTemperature.temperature }}{{ enclosureTemperature.unit }} - {{ printer.status }} + + {{ getStringStatus(printerStatus) }}
diff --git a/src/app/bottom-bar/bottom-bar.component.ts b/src/app/bottom-bar/bottom-bar.component.ts index f883945e2..65eb7bd78 100644 --- a/src/app/bottom-bar/bottom-bar.component.ts +++ b/src/app/bottom-bar/bottom-bar.component.ts @@ -1,9 +1,11 @@ import { Component, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; +import { Subscription, timer } from 'rxjs'; import { ConfigService } from '../config/config.service'; -import { EnclosureService } from '../plugins/enclosure.service'; -import { PrinterService, PrinterStatusAPI } from '../printer.service'; +import { PrinterState, PrinterStatus, TemperatureReading } from '../model'; +import { NotificationService } from '../notification/notification.service'; +import { EnclosureService } from '../services/enclosure/enclosure.service'; +import { SocketService } from '../services/socket/socket.service'; @Component({ selector: 'app-bottom-bar', @@ -12,46 +14,52 @@ import { PrinterService, PrinterStatusAPI } from '../printer.service'; }) export class BottomBarComponent implements OnDestroy { private subscriptions: Subscription = new Subscription(); - public printer: Printer; + private printerReady = false; + + public printerStatus: PrinterState; public enclosureTemperature: TemperatureReading; public constructor( - private printerService: PrinterService, + private socketService: SocketService, private configService: ConfigService, private enclosureService: EnclosureService, + private notificationService: NotificationService, ) { if (this.configService.getAmbientTemperatureSensorName() !== null) { this.subscriptions.add( - this.enclosureService.getObservable().subscribe((temperatureReading: TemperatureReading): void => { - this.enclosureTemperature = temperatureReading; + timer(2500, 15000).subscribe(() => { + if (this.printerReady) { + this.enclosureService.getEnclosureTemperature().subscribe( + (temperatureReading: TemperatureReading) => (this.enclosureTemperature = temperatureReading), + error => { + this.notificationService.setError("Can't retrieve enclosure temperature!", error.message); + }, + ); + } }), ); - } else { - this.enclosureTemperature = null; } - this.printer = { - name: this.configService.getPrinterName(), - status: 'connecting ...', - }; this.subscriptions.add( - this.printerService.getObservable().subscribe((printerStatus: PrinterStatusAPI): void => { - this.printer.status = printerStatus.status; + this.socketService.getPrinterStatusSubscribable().subscribe((printerStatus: PrinterStatus): void => { + this.printerStatus = printerStatus.status; + if (!this.printerReady) { + this.printerReady = [PrinterState.operational, PrinterState.printing, PrinterState.paused].includes( + this.printerStatus, + ); + } }), ); } - public ngOnDestroy(): void { - this.subscriptions.unsubscribe(); + public getStringStatus(printerState: PrinterState): string { + return PrinterState[printerState]; } -} -interface Printer { - name: string; - status: string; -} + public getPrinterName(): string { + return this.configService.getPrinterName(); + } -export interface TemperatureReading { - temperature: number; - humidity: number; - unit: string; + public ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } } diff --git a/src/app/config/config.default.ts b/src/app/config/config.default.ts index 4eb1d6d0b..5ac8339e9 100644 --- a/src/app/config/config.default.ts +++ b/src/app/config/config.default.ts @@ -2,7 +2,7 @@ import { Config } from './config.model'; export const defaultConfig: Config = { octoprint: { - url: 'http://localhost:5000/api/', + url: 'http://localhost:5000/', accessToken: '', }, printer: { diff --git a/src/app/config/config.service.ts b/src/app/config/config.service.ts index 507a28186..d38eaf63d 100644 --- a/src/app/config/config.service.ts +++ b/src/app/config/config.service.ts @@ -1,50 +1,59 @@ import { HttpHeaders } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import Ajv from 'ajv'; -import _ from 'lodash'; +import { Injectable, NgZone } from '@angular/core'; +import _ from 'lodash-es'; +import { ElectronService } from 'ngx-electron'; import { NotificationService } from '../notification/notification.service'; import { Config, CustomAction, HttpHeader, URLSplit } from './config.model'; -import { configSchema } from './config.schema'; @Injectable({ providedIn: 'root', }) export class ConfigService { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private store: any | undefined; - private validator: Ajv.ValidateFunction; - private config: Config; private valid: boolean; + private errors: string[]; private update = false; private initialized = false; private httpHeaders: HttpHeader; - public constructor(private notificationService: NotificationService) { - const ajv = new Ajv({ allErrors: true }); - this.validator = ajv.compile(configSchema); - try { - const Store = window.require('electron-store'); - this.store = new Store(); - this.initialize(this.store.get('config')); - } catch (e) { - console.error(e); + public constructor( + private notificationService: NotificationService, + private electronService: ElectronService, + private zone: NgZone, + ) { + this.electronService.ipcRenderer.addListener('configRead', (_, config: Config) => this.initialize(config)); + this.electronService.ipcRenderer.addListener('configSaved', (_, config: Config) => this.initialize(config)); + this.electronService.ipcRenderer.addListener('configError', (_, error: string) => { this.notificationService.setError( - "Can't read config file!", + error, 'Please restart your system. If the issue persists open an issue on GitHub.', ); - } + }); + + this.electronService.ipcRenderer.addListener('configPass', () => { + this.zone.run(() => { + this.valid = true; + this.generateHttpHeaders(); + this.initialized = true; + }); + }); + this.electronService.ipcRenderer.addListener('configFail', (_, errors) => { + this.zone.run(() => { + this.valid = false; + this.errors = errors; + console.error(errors); + this.initialized = true; + }); + }); + + this.electronService.ipcRenderer.send('readConfig'); } private initialize(config: Config): void { this.config = config; - this.valid = this.validate(); - if (this.valid) { - this.generateHttpHeaders(); - } - this.initialized = true; + this.electronService.ipcRenderer.send('checkConfig', config); } public generateHttpHeaders(): void { @@ -58,10 +67,6 @@ export class ConfigService { }; } - public getRemoteConfig(): Config { - return this.store.get('config'); - } - public getCurrentConfig(): Config { return _.cloneDeep(this.config); } @@ -70,47 +75,17 @@ export class ConfigService { return _.isEqual(this.config, changedConfig); } - public validate(): boolean { - return this.validator(this.config) ? true : false; - } - - public validateGiven(config: Config): boolean { - return this.validator(config) ? true : false; - } - public getErrors(): string[] { - const errors = []; - this.validator.errors?.forEach((error): void => { - if (error.keyword === 'type') { - errors.push(`${error.dataPath} ${error.message}`); - } else { - errors.push(`${error.dataPath === '' ? '.' : error.dataPath} ${error.message}`); - } - }); - console.error(errors); - return errors; + return this.errors; } - public saveConfig(config: Config): string { - try { - this.store.set('config', config); - const configStored = this.store.get('config'); - if (this.validateGiven(configStored)) { - this.config = config; - this.valid = true; - this.generateHttpHeaders(); - return null; - } else { - return 'Saved config is invalid!'; - } - } catch { - return 'Saving config failed!'; - } + public saveConfig(config: Config): void { + this.electronService.ipcRenderer.send('saveConfig', config); } public splitOctoprintURL(octoprintURL: string): URLSplit { const host = octoprintURL.split(':')[1].replace('//', ''); - const port = parseInt(octoprintURL.split(':')[2].replace('/api/', ''), 10); + const port = parseInt(octoprintURL.split(':')[2], 10); return { host, @@ -119,11 +94,10 @@ export class ConfigService { } public mergeOctoprintURL(urlSplit: URLSplit): string { - // TODO: remove api/ from URL for v2.2.0 if (urlSplit.port !== null || !isNaN(urlSplit.port)) { - return `http://${urlSplit.host}:${urlSplit.port}/api/`; + return `http://${urlSplit.host}:${urlSplit.port}/`; } else { - return `http://${urlSplit.host}/api/`; + return `http://${urlSplit.host}/`; } } @@ -146,8 +120,9 @@ export class ConfigService { return this.httpHeaders; } - public getURL(path: string): string { - return this.config.octoprint.url + path; + public getApiURL(path: string, includeApi = true): string { + if (includeApi) return `${this.config.octoprint.url}api/${path}`; + else return `${this.config.octoprint.url}${path}`; } public getAPIPollingInterval(): number { @@ -198,6 +173,10 @@ export class ConfigService { return this.config.octodash.turnOnPrinterWhenExitingSleep; } + public usePSUControl(): boolean { + return this.config.plugins.psuControl.enabled; + } + public useTpLinkSmartPlug(): boolean { return this.config.plugins.tpLinkSmartPlug.enabled; } @@ -205,6 +184,7 @@ export class ConfigService { public getSmartPlugIP(): string { return this.config.plugins.tpLinkSmartPlug.smartPlugIP; } + public getFilamentThickness(): number { return this.config.filament.thickness; } @@ -233,6 +213,10 @@ export class ConfigService { return this.config.printer.defaultTemperatureFanSpeed.fan; } + public isDisplayLayerProgressEnabled(): boolean { + return this.config.plugins.displayLayerProgress.enabled; + } + public isPreheatPluginEnabled(): boolean { return this.config.plugins.preheatButton.enabled; } diff --git a/src/app/config/setup/discover-octoprint/discover-octoprint.component.html b/src/app/config/setup/discover-octoprint/discover-octoprint.component.html index cb0efc4e6..2bb1a0070 100644 --- a/src/app/config/setup/discover-octoprint/discover-octoprint.component.html +++ b/src/app/config/setup/discover-octoprint/discover-octoprint.component.html @@ -7,9 +7,7 @@
{{ node.name }}
- - Version {{ node.version }}, URL: {{ node.url.replace('/api/', '') }} - + Version {{ node.version }}, URL: {{ node.url }}
diff --git a/src/app/config/setup/octoprint-authentication/octoprint-authentication.component.ts b/src/app/config/setup/octoprint-authentication/octoprint-authentication.component.ts index 2987992ea..04ceb7b99 100644 --- a/src/app/config/setup/octoprint-authentication/octoprint-authentication.component.ts +++ b/src/app/config/setup/octoprint-authentication/octoprint-authentication.component.ts @@ -1,8 +1,10 @@ import { HttpResponse } from '@angular/common/http'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { interval } from 'rxjs'; -import { NotificationService } from 'src/app/notification/notification.service'; -import { AuthService, TokenSuccess } from 'src/app/octoprint/auth.service'; + +import { TokenSuccess } from '../../../model/octoprint/auth.model'; +import { NotificationService } from '../../../notification/notification.service'; +import { OctoprintAuthenticationService } from './octoprint-authentication.service'; @Component({ selector: 'app-config-setup-octoprint-authentication', @@ -16,10 +18,10 @@ export class OctoprintAuthenticationComponent { @Output() increasePage = new EventEmitter(); @Output() accessTokenChange = new EventEmitter(); - constructor(private authService: AuthService, private notificationService: NotificationService) {} + constructor(private authService: OctoprintAuthenticationService, private notificationService: NotificationService) {} public loginWithOctoprintUI(): void { - this.authService.probeSupport(this.octoprintURL).subscribe( + this.authService.probeAuthSupport(this.octoprintURL).subscribe( result => { if (result.status === 204) { this.sendLoginRequest(); @@ -47,13 +49,13 @@ export class OctoprintAuthenticationComponent { } private sendLoginRequest(): void { - this.authService.startProcess(this.octoprintURL).subscribe( - result => { + this.authService.startAuthProcess(this.octoprintURL).subscribe( + token => { this.notificationService.setNotification( 'Login request send!', 'Please confirm the request via the popup in the OctoPrint WebUI.', ); - this.pollResult(result.app_token); + this.pollResult(token); }, _ => { this.notificationService.setWarning( @@ -69,7 +71,7 @@ export class OctoprintAuthenticationComponent { this.notificationService.closeNotification(); }, 2000); const pollInterval = interval(1000).subscribe(() => { - this.authService.pollStatus(this.octoprintURL, token).subscribe( + this.authService.pollAuthProcessStatus(this.octoprintURL, token).subscribe( result => { if (result.status === 200) { pollInterval.unsubscribe(); diff --git a/src/app/config/setup/octoprint-authentication/octoprint-authentication.service.ts b/src/app/config/setup/octoprint-authentication/octoprint-authentication.service.ts new file mode 100644 index 000000000..1a8f2a6fc --- /dev/null +++ b/src/app/config/setup/octoprint-authentication/octoprint-authentication.service.ts @@ -0,0 +1,29 @@ +/* eslint-disable camelcase */ +import { HttpClient, HttpResponseBase } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { pluck } from 'rxjs/operators'; + +import { AppToken } from '../../../model/octoprint'; + +@Injectable({ + providedIn: 'root', +}) +@Injectable() +export class OctoprintAuthenticationService { + constructor(private http: HttpClient) {} + + public probeAuthSupport(octoprintURL: string): Observable { + return this.http.get(`${octoprintURL}plugin/appkeys/probe`, { observe: 'response' }); + } + + public startAuthProcess(octoprintURL: string): Observable { + return this.http + .post(`${octoprintURL}plugin/appkeys/request`, { app: 'OctoDash' }) + .pipe(pluck('app_token')); + } + + public pollAuthProcessStatus(octoprintURL: string, token: string): Observable { + return this.http.get(`${octoprintURL}plugin/appkeys/request/${token}`, { observe: 'response' }); + } +} diff --git a/src/app/config/setup/personalization/personalization.component.ts b/src/app/config/setup/personalization/personalization.component.ts index c5480ec10..cc4328199 100644 --- a/src/app/config/setup/personalization/personalization.component.ts +++ b/src/app/config/setup/personalization/personalization.component.ts @@ -1,5 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { PrinterProfileService } from 'src/app/printerprofile.service'; + +import { PersonalizationService } from './personalization.service'; @Component({ selector: 'app-config-setup-personalization', @@ -15,10 +16,10 @@ export class PersonalizationComponent implements OnInit { @Output() printerNameChange = new EventEmitter(); @Output() useTouchscreenChange = new EventEmitter(); - constructor(private printerProfileService: PrinterProfileService) {} + constructor(private personalizationService: PersonalizationService) {} ngOnInit(): void { - this.printerProfileService.getActivePrinterProfileName(this.octoprintURL, this.apiKey).subscribe(printerName => { + this.personalizationService.getActivePrinterProfileName(this.octoprintURL, this.apiKey).subscribe(printerName => { if (!this.printerName) { this.printerName = printerName; this.printerNameChange.emit(this.printerName); diff --git a/src/app/config/setup/personalization/personalization.service.ts b/src/app/config/setup/personalization/personalization.service.ts new file mode 100644 index 000000000..92ef3b205 --- /dev/null +++ b/src/app/config/setup/personalization/personalization.service.ts @@ -0,0 +1,29 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { defaultIfEmpty, map } from 'rxjs/operators'; + +import { OctoprintPrinterProfiles } from '../../../model/octoprint'; + +@Injectable({ + providedIn: 'root', +}) +export class PersonalizationService { + public constructor(private http: HttpClient) {} + + public getActivePrinterProfileName(octoprintURL: string, apiKey: string): Observable { + return this.http + .get(`${octoprintURL}printerprofiles`, { + headers: new HttpHeaders({ + 'x-api-key': apiKey, + }), + }) + .pipe( + map(profiles => { + for (const [_, profile] of Object.entries(profiles.profiles)) { + if (profile.current) return profile.name; + } + }, defaultIfEmpty('')), + ); + } +} diff --git a/src/app/config/setup/setup.component.ts b/src/app/config/setup/setup.component.ts index 8af1ce717..06a1c9b89 100644 --- a/src/app/config/setup/setup.component.ts +++ b/src/app/config/setup/setup.component.ts @@ -1,6 +1,7 @@ import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; +import { Component, NgZone, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { ElectronService } from 'ngx-electron'; import { defaultConfig } from '../config.default'; import { Config } from '../config.model'; @@ -11,7 +12,7 @@ import { ConfigService } from '../config.service'; templateUrl: './setup.component.html', styleUrls: ['./setup.component.scss'], }) -export class ConfigSetupComponent implements OnInit { +export class ConfigSetupComponent implements OnInit, OnDestroy { public page = 0; public totalPages = 6; @@ -20,12 +21,18 @@ export class ConfigSetupComponent implements OnInit { public octoprintConnection = false; public configValid = false; - public configSaved = 'no'; + public configSaved = 'saving config'; public configErrors: string[]; public manualURL = false; - public constructor(private configService: ConfigService, private http: HttpClient, private router: Router) { + public constructor( + private configService: ConfigService, + private http: HttpClient, + private router: Router, + private electronService: ElectronService, + private zone: NgZone, + ) { this.configUpdate = this.configService.isUpdate(); if (this.configUpdate) { this.config = configService.getCurrentConfig(); @@ -39,6 +46,11 @@ export class ConfigSetupComponent implements OnInit { this.changeProgress(); } + public ngOnDestroy(): void { + this.electronService.ipcRenderer.removeListener('configSaved', this.onConfigSaved.bind(this)); + this.electronService.ipcRenderer.removeListener('configSaveFail', this.onConfigSaveFail.bind(this)); + } + public changeURLEntryMethod(manual: boolean): void { this.manualURL = manual; } @@ -59,10 +71,10 @@ export class ConfigSetupComponent implements OnInit { 'x-api-key': this.config.octoprint.accessToken, }), }; - this.http.get(this.config.octoprint.url + 'version', httpHeaders).subscribe( + this.http.get(`${this.config.octoprint.url}api/version`, httpHeaders).subscribe( (): void => { this.octoprintConnection = true; - this.validateConfig(); + this.saveConfig(); }, (error: HttpErrorResponse): void => { this.octoprintConnection = false; @@ -79,17 +91,26 @@ export class ConfigSetupComponent implements OnInit { ); } - private async validateConfig(): Promise { - this.configValid = this.configService.validateGiven(this.config); - if (!this.configValid) { - this.configErrors = this.configService.getErrors(); - } else { - this.saveConfig(); - } + private onConfigSaved() { + this.zone.run(() => { + this.configValid = true; + this.configSaved = null; + }); + } + + private onConfigSaveFail(_, errors) { + this.zone.run(() => { + this.configValid = false; + + this.configErrors = errors; + }); } private saveConfig(): void { - this.configSaved = this.configService.saveConfig(this.config); + this.electronService.ipcRenderer.on('configSaved', this.onConfigSaved.bind(this)); + this.electronService.ipcRenderer.on('configSaveFail', this.onConfigSaveFail.bind(this)); + + this.configService.saveConfig(this.config); } public finishWizard(): void { diff --git a/src/app/control/control.component.ts b/src/app/control/control.component.ts index 1109ccddb..c3efb672b 100644 --- a/src/app/control/control.component.ts +++ b/src/app/control/control.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; -import { OctoprintPrinterProfile } from '../octoprint/model/printerProfile'; -import { PrinterService } from '../printer.service'; -import { PrinterProfileService } from '../printerprofile.service'; +import { OctoprintPrinterProfile } from '../model/octoprint'; +import { NotificationService } from '../notification/notification.service'; +import { PrinterService } from '../services/printer/printer.service'; @Component({ selector: 'app-control', @@ -15,21 +15,13 @@ export class ControlComponent { public jogDistance = 10; public showHelp = false; - public constructor(private printerService: PrinterService, private printerProfileService: PrinterProfileService) { - this.printerProfile = { - name: '_default', - model: 'unknown', - current: true, - axes: { - x: { inverted: false }, - y: { inverted: false }, - z: { inverted: false }, + public constructor(private printerService: PrinterService, private notificationService: NotificationService) { + this.printerService.getActiveProfile().subscribe( + (printerProfile: OctoprintPrinterProfile) => (this.printerProfile = printerProfile), + err => { + this.notificationService.setError("Can't retrieve printer profile!", err.message); }, - }; - - this.printerProfileService.getDefaultPrinterProfile().then(profile => { - this.printerProfile = profile; - }); + ); } public setDistance(distance: number): void { diff --git a/src/app/control/custom-actions/custom-actions.component.html b/src/app/control/custom-actions/custom-actions.component.html index a8b475e96..74434d2e6 100644 --- a/src/app/control/custom-actions/custom-actions.component.html +++ b/src/app/control/custom-actions/custom-actions.component.html @@ -28,7 +28,11 @@

Are you sure?

Do you want to execute the following GCode?

{{ actionToConfirm.command }}

- - + + diff --git a/src/app/control/custom-actions/custom-actions.component.ts b/src/app/control/custom-actions/custom-actions.component.ts index 25d0976b4..e2628e077 100644 --- a/src/app/control/custom-actions/custom-actions.component.ts +++ b/src/app/control/custom-actions/custom-actions.component.ts @@ -1,10 +1,12 @@ import { Component, Input } from '@angular/core'; import { SafeResourceUrl } from '@angular/platform-browser'; import { Router } from '@angular/router'; -import { ConfigService } from 'src/app/config/config.service'; -import { OctoprintService } from 'src/app/octoprint.service'; -import { EnclosureService, PsuControlService, TPLinkSmartPlugService } from 'src/app/plugins'; -import { PrinterService } from 'src/app/printer.service'; + +import { ConfigService } from '../../config/config.service'; +import { PSUState } from '../../model'; +import { EnclosureService } from '../../services/enclosure/enclosure.service'; +import { PrinterService } from '../../services/printer/printer.service'; +import { SystemService } from '../../services/system/system.service'; @Component({ selector: 'app-custom-actions', @@ -20,11 +22,9 @@ export class CustomActionsComponent { constructor( private printerService: PrinterService, - private octoprintService: OctoprintService, + private systemService: SystemService, private configService: ConfigService, - private psuControlService: PsuControlService, private enclosureService: EnclosureService, - private tplinkSmartPlugService: TPLinkSmartPlugService, private router: Router, ) { this.customActions = this.configService.getCustomActions(); @@ -37,23 +37,15 @@ export class CustomActionsComponent { exit, }; } else { - this.executeGCode(command); + command.split('; ').forEach(this.executeGCode.bind(this)); if (exit && this.redirectActive) { this.router.navigate(['/main-screen']); } + this.hideConfirm(); } } - public doActionConfirm(): void { - this.executeGCode(this.actionToConfirm.command); - if (this.actionToConfirm.exit) { - this.router.navigate(['/main-screen']); - } else { - this.actionToConfirm = null; - } - } - - public doActionNoConfirm(): void { + public hideConfirm(): void { this.actionToConfirm = null; } @@ -78,19 +70,13 @@ export class CustomActionsComponent { this.kill(); break; case '[!POWEROFF]': - this.psuControlService.changePSUState(false); + this.enclosureService.setPSUState(PSUState.OFF); break; case '[!POWERON]': - this.psuControlService.changePSUState(true); + this.enclosureService.setPSUState(PSUState.ON); break; case '[!POWERTOGGLE]': - this.psuControlService.togglePSU(); - break; - case '[!TPLINKOFF]': - this.tplinkSmartPlugService.changePowerState(false); - break; - case '[!TPLINKON]': - this.tplinkSmartPlugService.changePowerState(true); + this.enclosureService.togglePSU(); break; default: { if (command.includes('[!WEB]')) { @@ -108,7 +94,7 @@ export class CustomActionsComponent { // [!DISCONNECT] public disconnectPrinter(): void { - this.octoprintService.disconnectPrinter(); + this.printerService.disconnectPrinter(); } // [!STOPDASHBOARD] @@ -118,17 +104,17 @@ export class CustomActionsComponent { // [!RELOAD] public reloadOctoPrint(): void { - this.octoprintService.sendSystemCommand('restart'); + this.systemService.sendCommand('restart'); } // [!REBOOT] public rebootPi(): void { - this.octoprintService.sendSystemCommand('reboot'); + this.systemService.sendCommand('reboot'); } // [!SHUTDOWN] public shutdownPi(): void { - this.octoprintService.sendSystemCommand('shutdown'); + this.systemService.sendCommand('shutdown'); } // [!KILL] diff --git a/src/app/conversion.service.ts b/src/app/conversion.service.ts new file mode 100644 index 000000000..c38e4f15e --- /dev/null +++ b/src/app/conversion.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; + +import { ConfigService } from './config/config.service'; + +@Injectable() +export class ConversionService { + constructor(private configService: ConfigService) {} + + public convertByteToMegabyte(byte: number): string { + return (byte / 1000000).toFixed(1); + } + + public convertDateToString(date: Date): string { + return `${('0' + date.getDate()).slice(-2)}.${('0' + (date.getMonth() + 1)).slice(-2)}.${date.getFullYear()} ${( + '0' + date.getHours() + ).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}:${('0' + date.getSeconds()).slice(-2)}`; + } + + public convertSecondsToHours(input: number): string { + const hours = input / 60 / 60; + let roundedHours = Math.floor(hours); + const minutes = (hours - roundedHours) * 60; + let roundedMinutes = Math.round(minutes); + if (roundedMinutes === 60) { + roundedMinutes = 0; + roundedHours += 1; + } + return roundedHours + ':' + ('0' + roundedMinutes).slice(-2); + } + + public convertFilamentLengthToWeight(filamentLength: number): number { + return this.convertFilamentVolumeToWeight( + (filamentLength * Math.PI * Math.pow(this.configService.getFilamentThickness() / 2, 2)) / 1000, + ); + } + + private convertFilamentVolumeToWeight(filamentVolume: number): number { + return Math.round(filamentVolume * this.configService.getFilamentDensity() * 10) / 10; + } +} diff --git a/src/app/event.service.ts b/src/app/event.service.ts new file mode 100644 index 000000000..ef629aaca --- /dev/null +++ b/src/app/event.service.ts @@ -0,0 +1,54 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { Router } from '@angular/router'; +import { Subscription } from 'rxjs'; + +import { ConfigService } from './config/config.service'; +import { PrinterEvent } from './model/event.model'; +import { SocketService } from './services/socket/socket.service'; + +@Injectable() +export class EventService implements OnDestroy { + private subscriptions: Subscription = new Subscription(); + + private printing = false; + + public constructor( + private socketService: SocketService, + private configService: ConfigService, + private router: Router, + ) { + this.subscriptions.add( + this.socketService.getEventSubscribable().subscribe((event: PrinterEvent) => { + if (event === PrinterEvent.PRINTING || event === PrinterEvent.PAUSED) { + setTimeout(() => { + this.printing = true; + }, 500); + } else { + setTimeout(() => { + this.printing = false; + }, 1000); + } + + if (event === PrinterEvent.CLOSED) { + this.router.navigate(['/standby']); + } else if (event === PrinterEvent.CONNECTED) { + setTimeout(() => { + if (this.configService.isTouchscreen()) { + this.router.navigate(['/main-screen']); + } else { + this.router.navigate(['/main-screen-no-touch']); + } + }, 1000); + } + }), + ); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + + public isPrinting(): boolean { + return this.printing; + } +} diff --git a/src/app/filament/change-filament/change-filament.component.ts b/src/app/filament/change-filament/change-filament.component.ts index 113dd9e2f..315fc4d8f 100644 --- a/src/app/filament/change-filament/change-filament.component.ts +++ b/src/app/filament/change-filament/change-filament.component.ts @@ -1,7 +1,8 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { ConfigService } from 'src/app/config/config.service'; -import { FilamentSpool } from 'src/app/plugins'; -import { PrinterService } from 'src/app/printer.service'; + +import { ConfigService } from '../../config/config.service'; +import { FilamentSpool } from '../../model'; +import { PrinterService } from '../../services/printer/printer.service'; @Component({ selector: 'app-filament-change-filament', @@ -32,7 +33,7 @@ export class ChangeFilamentComponent implements OnInit { } private initiateM600FilamentChange(): void { - // this.printerService.executeGCode('M600'); + this.printerService.executeGCode('M600'); } public getSpoolWeightLeft(weight: number, used: number): number { diff --git a/src/app/filament/choose-filament/choose-filament.component.html b/src/app/filament/choose-filament/choose-filament.component.html index 12cc67d83..9cce4d69e 100644 --- a/src/app/filament/choose-filament/choose-filament.component.html +++ b/src/app/filament/choose-filament/choose-filament.component.html @@ -1,5 +1,5 @@ select your new filament - + (); - constructor(public filament: FilamentManagementComponent) {} + constructor(public filament: FilamentService) {} public getSpoolWeightLeft(weight: number, used: number): number { return Math.floor(weight - used); diff --git a/src/app/filament/filament.component.html b/src/app/filament/filament.component.html index 9006cdee8..95d36dfcb 100644 --- a/src/app/filament/filament.component.html +++ b/src/app/filament/filament.component.html @@ -46,10 +46,11 @@ *ngIf="page === 5 && !showCheckmark" (purgeDone)="setSpoolSelection()" > -
- - - - +
+
diff --git a/src/app/filament/filament.component.scss b/src/app/filament/filament.component.scss index 6fc6e2a1a..aa7ed2a6f 100644 --- a/src/app/filament/filament.component.scss +++ b/src/app/filament/filament.component.scss @@ -61,51 +61,7 @@ } .checkmark { - width: 20vw; - height: 20vw; - border-radius: 50%; + margin-top: 10vh; + height: 80vh; display: block; - stroke-width: 2; - stroke: #fff; - stroke-miterlimit: 10; - margin: 19% auto; - box-shadow: inset 0 0 0 #44bd32; - animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both; - - &__circle { - stroke-dasharray: 166; - stroke-dashoffset: 166; - stroke-width: 2; - stroke-miterlimit: 10; - stroke: #44bd32; - fill: none; - animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; - } - - &__check { - transform-origin: 50% 50%; - stroke-dasharray: 48; - stroke-dashoffset: 48; - animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; - } -} - -@keyframes stroke { - 100% { - stroke-dashoffset: 0; - } -} -@keyframes scale { - 0%, - 100% { - transform: none; - } - 50% { - transform: scale3d(1.1, 1.1, 1); - } -} -@keyframes fill { - 100% { - box-shadow: inset 0 0 0 11vw #44bd32; - } } diff --git a/src/app/filament/filament.component.ts b/src/app/filament/filament.component.ts index 2dd85c974..30fe54261 100644 --- a/src/app/filament/filament.component.ts +++ b/src/app/filament/filament.component.ts @@ -1,36 +1,45 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { AnimationItem } from 'lottie-web'; +import { AnimationOptions } from 'ngx-lottie'; import { take } from 'rxjs/operators'; import { ConfigService } from '../config/config.service'; -import { FilamentManagementComponent, FilamentSpool } from '../plugins'; -import { PrinterService, PrinterStatusAPI } from '../printer.service'; +import { FilamentSpool, PrinterStatus } from '../model'; +import { FilamentService } from '../services/filament/filament.service'; +import { PrinterService } from '../services/printer/printer.service'; +import { SocketService } from '../services/socket/socket.service'; @Component({ selector: 'app-filament', templateUrl: './filament.component.html', styleUrls: ['./filament.component.scss'], - providers: [FilamentManagementComponent], + providers: [FilamentService], }) export class FilamentComponent implements OnInit, OnDestroy { private totalPages = 5; - public page: number; - public showCheckmark = false; private hotendPreviousTemperature = 0; + public page: number; + public showCheckmark = false; public selectedSpool: FilamentSpool; + public checkmarkOptions: AnimationOptions = { + path: '/assets/checkmark.json', + loop: false, + }; public constructor( private router: Router, private configService: ConfigService, private printerService: PrinterService, - private filament: FilamentManagementComponent, + private socketService: SocketService, + private filament: FilamentService, ) { - this.printerService - .getObservable() + this.socketService + .getPrinterStatusSubscribable() .pipe(take(1)) - .subscribe((printerStatus: PrinterStatusAPI): void => { - this.hotendPreviousTemperature = printerStatus.nozzle.set; + .subscribe((printerStatus: PrinterStatus): void => { + this.hotendPreviousTemperature = printerStatus.tool0.set; }); } @@ -93,7 +102,7 @@ export class FilamentComponent implements OnInit, OnDestroy { .setSpool(this.selectedSpool) .then((): void => { this.showCheckmark = true; - setTimeout(this.increasePage.bind(this), 1500, true); + setTimeout(this.increasePage.bind(this), 1350, true); }) .catch(() => this.increasePage(true)); } else { @@ -102,6 +111,10 @@ export class FilamentComponent implements OnInit, OnDestroy { } public get currentSpool(): FilamentSpool { - return this.filament.currentSpool; + return this.filament.getCurrentSpool(); + } + + public setAnimationSpeed(animation: AnimationItem): void { + animation.setSpeed(0.55); } } diff --git a/src/app/filament/heat-nozzle/heat-nozzle.component.ts b/src/app/filament/heat-nozzle/heat-nozzle.component.ts index f823de714..68ae5ee0e 100644 --- a/src/app/filament/heat-nozzle/heat-nozzle.component.ts +++ b/src/app/filament/heat-nozzle/heat-nozzle.component.ts @@ -1,8 +1,10 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Subscription } from 'rxjs'; -import { ConfigService } from 'src/app/config/config.service'; -import { FilamentSpool } from 'src/app/plugins'; -import { PrinterService, PrinterStatusAPI } from 'src/app/printer.service'; + +import { ConfigService } from '../../config/config.service'; +import { FilamentSpool, PrinterStatus } from '../../model'; +import { PrinterService } from '../../services/printer/printer.service'; +import { SocketService } from '../../services/socket/socket.service'; @Component({ selector: 'app-filament-heat-nozzle', @@ -24,7 +26,11 @@ export class HeatNozzleComponent implements OnInit, OnDestroy { private checkNozzleTemperatureTimeout: ReturnType; private subscriptions: Subscription = new Subscription(); - constructor(private printerService: PrinterService, private configService: ConfigService) {} + constructor( + private printerService: PrinterService, + private socketService: SocketService, + private configService: ConfigService, + ) {} ngOnInit(): void { this.isHeating = false; @@ -33,9 +39,10 @@ export class HeatNozzleComponent implements OnInit, OnDestroy { this.hotendTarget = this.currentSpool ? this.configService.getDefaultHotendTemperature() + this.currentSpool.temperatureOffset : this.configService.getDefaultHotendTemperature(); + this.subscriptions.add( - this.printerService.getObservable().subscribe((printerStatus: PrinterStatusAPI): void => { - this.hotendTemperature = printerStatus.nozzle.current; + this.socketService.getPrinterStatusSubscribable().subscribe((printerStatus: PrinterStatus): void => { + this.hotendTemperature = printerStatus.tool0.current; }), ); } diff --git a/src/app/filament/move-filament/move-filament.component.ts b/src/app/filament/move-filament/move-filament.component.ts index 0d8ab427a..dcbc29dab 100644 --- a/src/app/filament/move-filament/move-filament.component.ts +++ b/src/app/filament/move-filament/move-filament.component.ts @@ -1,7 +1,8 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { ConfigService } from 'src/app/config/config.service'; -import { FilamentSpool } from 'src/app/plugins'; -import { PrinterService } from 'src/app/printer.service'; + +import { ConfigService } from '../../config/config.service'; +import { FilamentSpool } from '../../model'; +import { PrinterService } from '../../services/printer/printer.service'; @Component({ selector: 'app-filament-move-filament', @@ -89,7 +90,7 @@ export class MoveFilamentComponent implements OnInit, OnDestroy { } public stopExtruderMovement(): void { - this.printerService.stopMotors(); + this.printerService.emergencyStop(); clearTimeout(this.fastMoveTimeout); clearTimeout(this.slowMoveTimeout); diff --git a/src/app/filament/purge-filament/purge-filament.component.ts b/src/app/filament/purge-filament/purge-filament.component.ts index 6dd17c9d7..194ebe78a 100644 --- a/src/app/filament/purge-filament/purge-filament.component.ts +++ b/src/app/filament/purge-filament/purge-filament.component.ts @@ -1,6 +1,7 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { ConfigService } from 'src/app/config/config.service'; -import { PrinterService } from 'src/app/printer.service'; + +import { ConfigService } from '../../config/config.service'; +import { PrinterService } from '../../services/printer/printer.service'; @Component({ selector: 'app-filament-purge-filament', diff --git a/src/app/files.service.ts b/src/app/files.service.ts deleted file mode 100644 index c1c32ed07..000000000 --- a/src/app/files.service.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import _ from 'lodash'; -import { Subscription } from 'rxjs'; - -import { AppService } from './app.service'; -import { ConfigService } from './config/config.service'; -import { NotificationService } from './notification/notification.service'; -import { OctoprintFile, OctoprintFolder, OctoprintFolderContent } from './octoprint/model/file'; - -@Injectable({ - providedIn: 'root', -}) -export class FilesService { - private httpGETRequest: Subscription; - private httpGETRequestTimeout: ReturnType; - private httpPOSTRequest: Subscription; - private httpDELETERequest: Subscription; - - public constructor( - private configService: ConfigService, - private http: HttpClient, - private notificationService: NotificationService, - private service: AppService, - ) {} - - public getFolder(folderPath = '/'): Promise<(File | Folder)[]> { - return new Promise((resolve, reject): void => { - this.httpGETRequestTimeout = setTimeout(() => { - this.httpGETRequest.unsubscribe(); - this.notificationService.setError("Can't retrieve folder!", 'Operation timed out. Please try again.'); - reject(); - }, 10000); - folderPath = folderPath === '/' ? '' : folderPath; - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('files' + folderPath), this.configService.getHTTPHeaders()) - .subscribe( - (data: OctoprintFolder & OctoprintFolderContent): void => { - if ('children' in data) { - data.files = data.children; - delete data.children; - } - const folder: (File | Folder)[] = []; - let localCount = 0; - let sdCardCount = 0; - data.files.forEach((fileOrFolder): void => { - if (fileOrFolder.type === 'folder') { - if (folderPath === '') { - if (fileOrFolder.origin == 'local') { - localCount += fileOrFolder.children.length; - } else { - sdCardCount += fileOrFolder.children.length; - } - } - - folder.push(({ - type: 'folder', - path: '/' + fileOrFolder.origin + '/' + fileOrFolder.path, - name: fileOrFolder.name, - size: this.service.convertByteToMegabyte(fileOrFolder.size), - } as unknown) as Folder); - } else if (fileOrFolder.typePath.includes('gcode')) { - let filamentLength = 0; - if (fileOrFolder.gcodeAnalysis) { - _.forEach(fileOrFolder.gcodeAnalysis.filament, (tool): void => { - filamentLength += tool.length; - }); - } - - if (folderPath === '') { - if (fileOrFolder.origin == 'local') { - localCount += 1; - } else { - sdCardCount += 1; - } - } - - folder.push(({ - type: 'file', - path: '/' + fileOrFolder.origin + '/' + fileOrFolder.path, - name: fileOrFolder.name, - date: fileOrFolder.date, - size: this.service.convertByteToMegabyte(fileOrFolder.size), - ...(fileOrFolder.gcodeAnalysis - ? { - printTime: this.service.convertSecondsToHours(fileOrFolder.gcodeAnalysis.estimatedPrintTime), - filamentWeight: this.service.convertFilamentLengthToWeight(filamentLength), - } - : {}), - } as unknown) as File); - } - }); - data = null; - - if (folderPath === '') { - if (localCount > 0 && sdCardCount > 0) { - folder.length = 0; - folder.push(({ - type: 'folder', - path: '/local', - name: 'local', - files: localCount, - } as unknown) as Folder); - folder.push(({ - type: 'folder', - path: '/sdcard', - name: 'sdcard', - files: sdCardCount, - } as unknown) as Folder); - } - } - - resolve(folder); - }, - (error: HttpErrorResponse): void => { - if (error.status === 404) { - this.notificationService.setError("Can't find specified folder!", error.message); - if (folderPath !== '/') { - this.getFolder(folderPath.substring(0, folderPath.lastIndexOf('/'))); - } else { - reject(); - } - } else { - this.notificationService.setError("Can't retrieve folder!", error.message); - reject(); - } - }, - (): void => { - clearTimeout(this.httpGETRequestTimeout); - }, - ); - }); - } - - public getFile(filePath: string): Promise { - return new Promise((resolve, reject): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('files' + filePath), this.configService.getHTTPHeaders()) - .subscribe( - (data: OctoprintFile): void => { - let filamentLength = 0; - if (data.gcodeAnalysis) { - _.forEach(data.gcodeAnalysis.filament, (tool): void => { - filamentLength += tool.length; - }); - } - const file = ({ - type: 'file', - path: '/' + data.origin + '/' + data.path, - name: data.name, - size: this.service.convertByteToMegabyte(data.size), - ...(data.gcodeAnalysis - ? { - date: this.service.convertDateToString(new Date(data.date * 1000)), - printTime: this.service.convertSecondsToHours(data.gcodeAnalysis.estimatedPrintTime), - filamentWeight: this.service.convertFilamentLengthToWeight(filamentLength), - } - : {}), - thumbnail: data.thumbnail - ? this.configService.getURL(data.thumbnail).replace('/api/', '/') - : 'assets/object.svg', - } as unknown) as File; - resolve(file); - }, - (error: HttpErrorResponse): void => { - if (error.status === 404) { - this.notificationService.setError("Can't find specified file!", error.message); - reject(); - } else { - this.notificationService.setError("Can't retrieve folder!", error.message); - reject(); - } - }, - ); - }); - } - - public getThumbnail(filePath: string): Promise { - return new Promise((resolve, reject): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('files' + filePath), this.configService.getHTTPHeaders()) - .subscribe( - (data: OctoprintFile): void => { - const thumbnail = data.thumbnail - ? this.configService.getURL(data.thumbnail).replace('/api/', '/') - : 'assets/object.svg'; - resolve(thumbnail); - }, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't load thumbnail!", error.message); - reject(); - }, - ); - }); - } - - public loadFile(filePath: string): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const loadFileBody = { - command: 'select', - print: false, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('files' + filePath), loadFileBody, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't load the file!", error.message); - }, - ); - } - - public printFile(filePath: string): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const printFileBody = { - command: 'select', - print: true, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('files' + filePath), printFileBody, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't start print!", error.message); - }, - ); - } - - public deleteFile(filePath: string): void { - if (this.httpDELETERequest) { - this.httpDELETERequest.unsubscribe(); - } - this.httpDELETERequest = this.http - .delete(this.configService.getURL('files' + filePath), this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't delete file!", error.message); - }, - ); - } -} - -export interface Folder { - type: string; - path: string; - name: string; - size: string; -} - -export interface File { - type: string; - path: string; - name: string; - size: string; - printTime?: string; - filamentWeight?: number; - date?: string; - thumbnail?: string; -} diff --git a/src/app/files/files.component.html b/src/app/files/files.component.html index 70d6eee5e..1a79bb2c4 100644 --- a/src/app/files/files.component.html +++ b/src/app/files/files.component.html @@ -7,19 +7,14 @@ - - +
+ sort
+ +
- -

loading

-
+ -
can't load files ...
+
can't load files ...
+ +
+
+
+ + .. +
+
-
- - .. -
-
-
-
- {{ content.size }} mb + + {{ folder.size }} mb +
- {{ content.name }} + {{ folder.name }}
+
- {{ content.size }}mb - - {{ content.filamentWeight }}g + {{ file.size }}mb + + {{ file.filamentWeight }}g - - {{ content.printTime }}h + + {{ file.printTime }}h
- {{ content.name }} + {{ file.name }}
-
+
diff --git a/src/app/files/files.component.ts b/src/app/files/files.component.ts index 12b226ff9..176e43072 100644 --- a/src/app/files/files.component.ts +++ b/src/app/files/files.component.ts @@ -1,11 +1,13 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { NgxSpinnerService } from 'ngx-spinner'; +import _ from 'lodash-es'; +import { AnimationOptions } from 'ngx-lottie'; -import { AppService } from '../app.service'; import { ConfigService } from '../config/config.service'; -import { File, FilesService, Folder } from '../files.service'; -import { JobService } from '../job.service'; +import { Directory, File } from '../model'; +import { NotificationService } from '../notification/notification.service'; +import { FilesService } from '../services/files/files.service'; @Component({ selector: 'app-files', @@ -14,111 +16,81 @@ import { JobService } from '../job.service'; }) export class FilesComponent { public currentFolder: string; - public folderContent: (File | Folder)[]; + public homeFolder = '/'; + public directory: Directory; public fileDetail: File; + public sortingAttribute: 'name' | 'date' | 'size'; public sortingOrder: 'asc' | 'dsc'; public showSorting = false; - public homeFolder = '/'; + + public loadingOptions: AnimationOptions = { + path: '/assets/loading.json', + }; + public loading = Date.now(); public constructor( private filesService: FilesService, - private spinner: NgxSpinnerService, - private service: AppService, + private notificationService: NotificationService, private router: Router, - private jobService: JobService, private configService: ConfigService, ) { this.showLoader(); - this.folderContent = []; + this.directory = { files: [], folders: [] }; this.currentFolder = '/'; + this.sortingAttribute = this.configService.getDefaultSortingAttribute(); this.sortingOrder = this.configService.getDefaultSortingOrder(); - this.openFolder(this.currentFolder); - } - public openDetails(filePath: string): void { - this.filesService - .getFile(filePath) - .then((data): void => { - this.fileDetail = data; - }) - .catch((): void => { - this.fileDetail = ({ name: 'error' } as unknown) as File; - }); - const fileDOMElement = document.getElementById('fileDetailView'); - fileDOMElement.style.display = 'block'; - setTimeout((): void => { - fileDOMElement.style.opacity = '1'; - }, 50); + this.openFolder(this.currentFolder); } public openFolder(folderPath: string): void { setTimeout((): void => { this.showLoader(); - this.folderContent = []; - this.filesService - .getFolder(folderPath) - .then((data): void => { - this.folderContent = data; - if (folderPath === '/' && !(data[0].name === 'local' && data[1].name == 'sdcard')) { - this.currentFolder = data[0].path.startsWith('/local') ? '/local' : '/sdcard'; + this.directory = { files: [], folders: [] }; + + this.filesService.getFolderContent(folderPath).subscribe( + (directory: Directory) => { + this.directory = directory; + const mergedDirectory = _.concat(directory.files, directory.folders); + if (folderPath === '/' && !(mergedDirectory[0].name === 'local' && mergedDirectory[1].name == 'sdcard')) { + this.currentFolder = mergedDirectory[0].path.startsWith('/local') ? '/local' : '/sdcard'; this.homeFolder = this.currentFolder; } else { this.currentFolder = folderPath; } this.sortFolder(this.sortingAttribute, this.sortingOrder); - this.spinner.hide(); - }) - .catch((): void => { - this.folderContent = null; + }, + (error: HttpErrorResponse) => { + this.notificationService.setError("Can't load file/folder!", error.message); this.currentFolder = folderPath; - this.spinner.hide(); - }); - }, 300); + }, + () => { + this.hideLoader(); + }, + ); + }, 240); } public sortFolder(by: 'name' | 'date' | 'size' = 'name', order: 'asc' | 'dsc' = 'asc'): void { - switch (by) { - case 'name': { - this.folderContent.sort((a, b): number => - a.type === b.type - ? (order === 'asc' ? a.name > b.name : a.name < b.name) - ? 1 - : -1 - : a.type === 'folder' - ? -1 - : 1, - ); - break; - } - case 'date': { - this.sortFolder('name', order); - this.folderContent.sort((a, b): number => { - if (a.type === b.type && a.type === 'file') { - const aFile = (a as unknown) as File; - const bFile = (b as unknown) as File; - return (order === 'asc' ? aFile.date > bFile.date : aFile.date < bFile.date) ? 1 : -1; - } else { - return a.type === 'folder' ? -1 : 1; - } - }); - break; - } - case 'size': { - this.sortFolder('name', order); - this.folderContent.sort((a, b): number => { - if (a.type === b.type && (a as File).type) { - const aFile = (a as unknown) as File; - const bFile = (b as unknown) as File; - return (order === 'asc' ? aFile.size > bFile.size : aFile.size < bFile.size) ? 1 : -1; - } else { - return 1; - } - }); - break; - } - } + this.directory.folders.sort((a, b): number => ((order === 'asc' ? a.name > b.name : a.name < b.name) ? 1 : -1)); + this.directory.files.sort((a, b): number => ((order === 'asc' ? a[by] > b[by] : a[by] < b[by]) ? 1 : -1)); + } + + public openDetails(filePath: string): void { + this.filesService.getFile(filePath).subscribe( + (fileData: File) => (this.fileDetail = fileData), + (error: HttpErrorResponse) => { + this.fileDetail = ({ name: 'error' } as unknown) as File; + this.notificationService.setError("Can't load file!", error.message); + }, + ); + const fileDOMElement = document.getElementById('fileDetailView'); + fileDOMElement.style.display = 'block'; + setTimeout((): void => { + fileDOMElement.style.opacity = '1'; + }, 50); } public closeDetails(): void { @@ -149,36 +121,37 @@ export class FilesComponent { } public loadFile(filePath: string): void { + this.filesService.loadFile(filePath); + this.filesService.setLoadedFile(true); setTimeout((): void => { - this.filesService.loadFile(filePath); - this.service.setLoadedFile(true); - this.jobService.deleteJobInformation(); this.router.navigate(['/main-screen']); }, 300); } public printFile(filePath: string): void { + this.filesService.printFile(filePath); setTimeout((): void => { - this.filesService.printFile(filePath); this.router.navigate(['/main-screen']); - }, 300); + }, 550); } public deleteFile(filePath: string): void { + this.filesService.deleteFile(filePath); setTimeout((): void => { - this.filesService.deleteFile(filePath); this.closeDetails(); this.openFolder(this.currentFolder); }, 300); } + private hideLoader(): void { + if (Date.now() - this.loading > 750) { + this.loading = 0; + } else { + setTimeout(this.hideLoader.bind(this), 750 - (Date.now() - this.loading)); + } + } + private showLoader(): void { - this.spinner.show(undefined, { - bdColor: '#353b48', - color: '#f5f6fa', - size: 'medium', - type: 'pacman', - fullScreen: false, - }); + this.loading = Date.now(); } } diff --git a/src/app/height-progress/height-progress.component.html b/src/app/height-progress/height-progress.component.html new file mode 100644 index 000000000..e488261f2 --- /dev/null +++ b/src/app/height-progress/height-progress.component.html @@ -0,0 +1,14 @@ + + + Z {{ height }}mm + + + + + + Layer + {{ height.current }} + of {{ height.total >= 0 ? height.total : '---' }} + + diff --git a/src/app/height-progress/height-progress.component.scss b/src/app/height-progress/height-progress.component.scss new file mode 100644 index 000000000..e807590e6 --- /dev/null +++ b/src/app/height-progress/height-progress.component.scss @@ -0,0 +1,23 @@ +.height-indication { + width: 100%; + display: block; + margin-top: 1vh; + text-align: center; + font-size: 4vw; + + &__current-height { + font-size: 6vw; + font-weight: 500; + } + + &__z { + border: 3px solid white; + padding: 0 0.2rem; + font-size: 0.5rem; + font-weight: bold; + border-radius: 0.1rem; + vertical-align: 0.05rem; + display: inline-block; + margin-right: 1.5vw; + } +} diff --git a/src/app/height-progress/height-progress.component.ts b/src/app/height-progress/height-progress.component.ts new file mode 100644 index 000000000..741928858 --- /dev/null +++ b/src/app/height-progress/height-progress.component.ts @@ -0,0 +1,33 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; + +import { ZHeightLayer } from '../model'; +import { SocketService } from '../services/socket/socket.service'; + +@Component({ + selector: 'app-height-progress', + templateUrl: './height-progress.component.html', + styleUrls: ['./height-progress.component.scss'], +}) +export class HeightProgressComponent implements OnInit, OnDestroy { + private subscriptions: Subscription = new Subscription(); + public height: number | ZHeightLayer; + + public constructor(private socketService: SocketService) {} + + public ngOnInit(): void { + this.subscriptions.add( + this.socketService.getJobStatusSubscribable().subscribe(jobStatus => { + this.height = jobStatus.zHeight; + }), + ); + } + + public ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + + public isNumber(variable: number | ZHeightLayer): boolean { + return typeof variable === 'number'; + } +} diff --git a/src/app/job-status/job-status.component.html b/src/app/job-status/job-status.component.html index 5faef367d..fc53f5724 100644 --- a/src/app/job-status/job-status.component.html +++ b/src/app/job-status/job-status.component.html @@ -1,58 +1,67 @@ -
-
+
+
-
{{ job.progress }}%
+
{{ jobStatus.progress }}%
-
+ +
- +
-
+
+
+
- +
- {{ job.progress }}% + {{ jobStatus.progress }}%
- {{ job.filename }} + + {{ jobStatus.file }}
- {{ job.filamentAmount }}g Filament + {{ jobStatus.filamentAmount }}g Filament
+ - - {{ job.timeLeft.value }}{{ job.timeLeft.unit }} left, + + {{ jobStatus.timeLeft.value }}{{ jobStatus.timeLeft.unit }} left, - elapsed: {{ job.timePrinted.value }}{{ job.timePrinted.unit }} + elapsed: {{ jobStatus.timePrinted.value }}{{ jobStatus.timePrinted.unit }}
-
+ +
- + discard
- {{ job.filename }} + {{ jobStatus.file }}
+ - - -
+
+
- + - {{ job.estimatedPrintTime.value }}{{ job.estimatedPrintTime.unit }} + {{ jobStatus.estimatedPrintTime.value }}{{ jobStatus.estimatedPrintTime.unit }} - - will finish ~{{ job.estimatedEndTime }} + - will finish ~{{ jobStatus.estimatedEndTime }}
- + + - {{ job.filamentAmount }}g + {{ jobStatus.filamentAmount }}g filament will be used
-
loading info
-
no job running ...
+ +
+ loading info +
+ +
no job running ...
+ + diff --git a/src/app/job-status/job-status.component.ts b/src/app/job-status/job-status.component.ts index bdc902f02..bb16b36f1 100644 --- a/src/app/job-status/job-status.component.ts +++ b/src/app/job-status/job-status.component.ts @@ -1,10 +1,12 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; -import { AppService } from '../app.service'; import { ConfigService } from '../config/config.service'; -import { Job, JobService } from '../job.service'; -import { NotificationService } from '../notification/notification.service'; +import { EventService } from '../event.service'; +import { JobStatus } from '../model'; +import { FilesService } from '../services/files/files.service'; +import { JobService } from '../services/job/job.service'; +import { SocketService } from '../services/socket/socket.service'; @Component({ selector: 'app-job-status', @@ -13,17 +15,33 @@ import { NotificationService } from '../notification/notification.service'; }) export class JobStatusComponent implements OnInit, OnDestroy { private subscriptions: Subscription = new Subscription(); - public job: Job; + + public jobStatus: JobStatus; + public thumbnail: string; + public showPreviewWhilePrinting: boolean; public constructor( private jobService: JobService, - private service: AppService, - private notificationService: NotificationService, + private fileService: FilesService, + private socketService: SocketService, + private eventService: EventService, private configService: ConfigService, - ) {} + ) { + this.showPreviewWhilePrinting = this.configService.showThumbnailByDefault(); + } public ngOnInit(): void { - this.subscriptions.add(this.jobService.getObservable().subscribe((job: Job): Job => (this.job = job))); + this.subscriptions.add( + this.socketService.getJobStatusSubscribable().subscribe((jobStatus: JobStatus): void => { + if (jobStatus.file !== this.jobStatus?.file) { + this.fileService.getThumbnail(jobStatus.fullPath).subscribe(thumbnail => { + this.thumbnail = thumbnail; + console.log(this.thumbnail); + }); + } + this.jobStatus = jobStatus; + }), + ); } public ngOnDestroy(): void { @@ -31,7 +49,7 @@ export class JobStatusComponent implements OnInit, OnDestroy { } public isFileLoaded(): boolean { - return this.service.getLoadedFile(); + return this.fileService.getLoadedFile(); } public isPreheatEnabled(): boolean { @@ -42,30 +60,23 @@ export class JobStatusComponent implements OnInit, OnDestroy { this.jobService.preheat(); } - public preheatDisabled(): void { - this.notificationService.setWarning( - 'Preheat Plugin is not enabled!', - 'Please make sure to install and enable the Preheat Plugin to use this functionality.', - ); - } - public discardLoadedFile(): void { - this.service.setLoadedFile(false); + this.fileService.setLoadedFile(false); } public startJob(): void { this.jobService.startJob(); setTimeout((): void => { - this.service.setLoadedFile(false); + this.fileService.setLoadedFile(false); }, 5000); } public isPrinting(): boolean { - return this.jobService.isPrinting(); + return this.eventService.isPrinting(); } - public showPreview(): boolean { - return this.jobService.showPreviewWhilePrinting(); + public togglePreview(): void { + this.showPreviewWhilePrinting = !this.showPreviewWhilePrinting; } public hasProperty(object: Record, name: string): boolean { diff --git a/src/app/job.service.ts b/src/app/job.service.ts deleted file mode 100644 index 1db006730..000000000 --- a/src/app/job.service.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable, Observer, Subscription, timer } from 'rxjs'; -import { shareReplay } from 'rxjs/operators'; - -import { AppService } from './app.service'; -import { ConfigService } from './config/config.service'; -import { FilesService } from './files.service'; -import { NotificationService } from './notification/notification.service'; -import { JobCommand, OctoprintFilament, OctoprintJobStatus } from './octoprint/model/job'; - -@Injectable({ - providedIn: 'root', -}) -export class JobService { - private httpGETRequest: Subscription; - private httpPOSTRequest: Subscription; - private observable: Observable; - private observer: Observer; - private printing = false; - private previewWhilePrinting = false; - - public constructor( - private configService: ConfigService, - private http: HttpClient, - private notificationService: NotificationService, - private service: AppService, - private fileService: FilesService, - ) { - this.previewWhilePrinting = this.configService.showThumbnailByDefault(); - this.observable = new Observable((observer: Observer): void => { - this.observer = observer; - timer(750, this.configService.getAPIPollingInterval()).subscribe((): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('job'), this.configService.getHTTPHeaders()) - .subscribe( - async (data: OctoprintJobStatus): Promise => { - let job: Job = null; - if (data.job && data.job.file.name) { - this.printing = ['Printing', 'Pausing', 'Paused', 'Cancelling', 'Printing from SD'].includes( - data.state, - ); - try { - job = { - status: JobStatus[data.state], - filename: data.job.file.display.replace('.gcode', '').replace('.ufp', ''), - thumbnail: await this.fileService.getThumbnail( - '/' + data.job.file.origin + '/' + data.job.file.path, - ), - progress: Math.round(data.progress.completion), - ...(data.job.filament !== null - ? { - filamentAmount: this.service.convertFilamentLengthToWeight( - this.getTotalAmountOfFilament(data.job.filament), - ), - } - : {}), - ...(data.progress.printTimeLeft !== null - ? { - timeLeft: { - value: this.service.convertSecondsToHours(data.progress.printTimeLeft), - unit: 'h', - }, - } - : {}), - timePrinted: { - value: this.service.convertSecondsToHours(data.progress.printTime), - unit: 'h', - }, - ...(data.job.estimatedPrintTime !== null - ? { - estimatedPrintTime: { - value: this.service.convertSecondsToHours(data.job.estimatedPrintTime), - unit: 'h', - }, - estimatedEndTime: this.calculateEndTime(data.job.estimatedPrintTime), - } - : {}), - }; - } catch (error) { - this.notificationService.setError("Can't retrieve Job Status", error); - } - } else { - this.printing = false; - } - observer.next(job); - }, - (error: HttpErrorResponse): void => { - this.printing = false; - this.notificationService.setError("Can't retrieve jobs!", error.message); - }, - ); - }); - }).pipe(shareReplay(1)); - this.observable.subscribe(); - } - - private getTotalAmountOfFilament(filamentAmount: OctoprintFilament): number { - let filamentLength = 0; - for (const property in filamentAmount) { - if ( - Object.prototype.hasOwnProperty.call(filamentAmount, property) && - Object.prototype.hasOwnProperty.call(filamentAmount[property], 'length') - ) { - filamentLength += filamentAmount[property].length; - } - } - return filamentLength; - } - - public deleteJobInformation(): void { - this.observer.next(null); - } - - public getObservable(): Observable { - return this.observable; - } - - public isPrinting(): boolean { - return this.printing; - } - - public togglePreviewWhilePrinting(): void { - this.previewWhilePrinting = !this.previewWhilePrinting; - } - - public showPreviewWhilePrinting(): boolean { - return this.previewWhilePrinting; - } - - public cancelJob(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const cancelPayload: JobCommand = { - command: 'cancel', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('job'), cancelPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.notificationService.setError( - "Can't cancel Job!", - 'There is no running job, that could be cancelled (409)', - ); - } else { - this.notificationService.setError("Can't cancel Job!", error.message); - } - }, - ); - } - - public pauseJob(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const pausePayload: JobCommand = { - command: 'pause', - action: 'pause', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('job'), pausePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.notificationService.setError( - "Can't pause Job!", - 'There is no running job, that could be paused (409)', - ); - } else { - this.notificationService.setError("Can't pause Job!", error.message); - } - }, - ); - } - - public restartJob(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const pausePayload: JobCommand = { - command: 'restart', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('job'), pausePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.notificationService.setError( - "Can't restart Job!", - 'There is no running job, that could be restarted (409)', - ); - } else { - this.notificationService.setError("Can't restart Job!", error.message); - } - }, - ); - } - - public resumeJob(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const pausePayload: JobCommand = { - command: 'pause', - action: 'resume', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('job'), pausePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.notificationService.setError( - "Can't resume Job!", - 'There is no paused job, that could be resumed (409)', - ); - } else { - this.notificationService.setError("Can't resume Job!", error.message); - } - }, - ); - } - - public startJob(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const pausePayload: JobCommand = { - command: 'start', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('job'), pausePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.notificationService.setError("Can't start Job!", 'There is already a job running (409)'); - } else { - this.notificationService.setError("Can't start Job!", error.message); - } - }, - ); - } - - public preheat(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const preheatPayload: JobCommand = { - command: 'preheat', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('plugin/preheat'), preheatPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't preheat printer!", error.message); - }, - ); - } - - private calculateEndTime(duration: number): string { - const date = new Date(); - date.setSeconds(date.getSeconds() + duration); - return `${('0' + date.getHours()).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`; - } -} - -interface Duration { - value: string; - unit: string; -} - -export interface Job { - status: JobStatus; - filename: string; - thumbnail: string | undefined; - progress: number; - filamentAmount?: number; - timeLeft?: Duration; - timePrinted: Duration; - estimatedPrintTime?: Duration; - estimatedEndTime?: string; -} - -export enum JobStatus { - Operational, - Pausing, - Paused, - Printing, - Cancelling, - Error, - Closed, - Ready, - SdReady, - Loading, -} diff --git a/src/app/layer-progress/layer-progress.component.html b/src/app/layer-progress/layer-progress.component.html deleted file mode 100644 index d544016a6..000000000 --- a/src/app/layer-progress/layer-progress.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - Layer - {{ layerProgress.current }} - of - {{ layerProgress.total }} - diff --git a/src/app/layer-progress/layer-progress.component.scss b/src/app/layer-progress/layer-progress.component.scss deleted file mode 100644 index d28543325..000000000 --- a/src/app/layer-progress/layer-progress.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -.layer-indication { - width: 100%; - display: block; - margin-top: 1vh; - text-align: center; - font-size: 4vw; - - &__current-layer { - font-size: 6vw; - font-weight: 500; - } -} diff --git a/src/app/layer-progress/layer-progress.component.ts b/src/app/layer-progress/layer-progress.component.ts deleted file mode 100644 index 439fc5900..000000000 --- a/src/app/layer-progress/layer-progress.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { DisplayLayerProgressAPI, LayerProgressService } from '../plugins/layer-progress.service'; - -@Component({ - selector: 'app-layer-progress', - templateUrl: './layer-progress.component.html', - styleUrls: ['./layer-progress.component.scss'], -}) -export class LayerProgressComponent implements OnInit, OnDestroy { - private subscriptions: Subscription = new Subscription(); - public layerProgress: LayerProgress; - - public constructor(private displayLayerProgressService: LayerProgressService) { - this.layerProgress = { - current: 0, - total: 0, - }; - } - - public ngOnInit(): void { - this.subscriptions.add( - this.displayLayerProgressService.getObservable().subscribe((layerProgress: DisplayLayerProgressAPI): void => { - this.layerProgress.current = layerProgress.current; - this.layerProgress.total = layerProgress.total; - }), - ); - } - - public ngOnDestroy(): void { - this.subscriptions.unsubscribe(); - } -} - -export interface LayerProgress { - current: number; - total: number; -} diff --git a/src/app/long-press.directive.ts b/src/app/long-press.directive.ts index 5908320f8..e58340067 100644 --- a/src/app/long-press.directive.ts +++ b/src/app/long-press.directive.ts @@ -21,7 +21,7 @@ export class LongPress { @Output() onLongPressing = new EventEmitter(); - @HostListener('touchstart', ['$event']) + @HostListener('pointerdown', ['$event']) onMouseDown(event: EventSource): void { this.pressing = true; this.longPressing = false; @@ -34,8 +34,7 @@ export class LongPress { }, this.duration); } - @HostListener('touchend', ['$event']) - @HostListener('touchcancel', ['$event']) + @HostListener('pointerup', ['$event']) endPress(event: EventSource): void { clearTimeout(this.timeout); clearInterval(this.interval); @@ -46,7 +45,7 @@ export class LongPress { this.pressing = false; } - @HostListener('touchmove', ['$event']) + @HostListener('pointerleave', ['$event']) endPressMove(_: EventSource): void { clearTimeout(this.timeout); clearInterval(this.interval); diff --git a/src/app/main-screen/main-screen.component.html b/src/app/main-screen/main-screen.component.html index 01fa8007d..0ab009365 100644 --- a/src/app/main-screen/main-screen.component.html +++ b/src/app/main-screen/main-screen.component.html @@ -2,7 +2,7 @@ - +
diff --git a/src/app/main-screen/main-screen.component.ts b/src/app/main-screen/main-screen.component.ts index b744bdce9..cf4424b6d 100644 --- a/src/app/main-screen/main-screen.component.ts +++ b/src/app/main-screen/main-screen.component.ts @@ -1,7 +1,9 @@ import { Component } from '@angular/core'; +import { Router } from '@angular/router'; -import { AppService } from '../app.service'; -import { JobService } from '../job.service'; +import { ConfigService } from '../config/config.service'; +import { EventService } from '../event.service'; +import { FilesService } from '../services/files/files.service'; @Component({ selector: 'app-main-screen', @@ -10,13 +12,22 @@ import { JobService } from '../job.service'; export class MainScreenComponent { public printing = false; - public constructor(private jobService: JobService, private service: AppService) {} + public constructor( + private eventService: EventService, + private fileService: FilesService, + private configService: ConfigService, + private router: Router, + ) { + if (!this.configService.isInitialized()) { + this.router.navigate(['/']); + } + } public isPrinting(): boolean { - return this.jobService.isPrinting(); + return this.eventService.isPrinting(); } public isFileLoaded(): boolean { - return this.service.getLoadedFile(); + return this.fileService.getLoadedFile(); } } diff --git a/src/app/main-screen/no-touch/main-screen-no-touch.component.html b/src/app/main-screen/no-touch/main-screen-no-touch.component.html index 3762f4457..cb2bf88c6 100644 --- a/src/app/main-screen/no-touch/main-screen-no-touch.component.html +++ b/src/app/main-screen/no-touch/main-screen-no-touch.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/model/auth.model.ts b/src/app/model/auth.model.ts new file mode 100644 index 000000000..1d77c432a --- /dev/null +++ b/src/app/model/auth.model.ts @@ -0,0 +1,4 @@ +export interface SocketAuth { + user: string; + session: string; +} diff --git a/src/app/model/enclosure.model.ts b/src/app/model/enclosure.model.ts new file mode 100644 index 000000000..35ec4eea3 --- /dev/null +++ b/src/app/model/enclosure.model.ts @@ -0,0 +1,10 @@ +export interface TemperatureReading { + temperature: number; + humidity: number; + unit: string; +} + +export enum PSUState { + ON, + OFF, +} diff --git a/src/app/model/event.model.ts b/src/app/model/event.model.ts new file mode 100644 index 000000000..21f30cffa --- /dev/null +++ b/src/app/model/event.model.ts @@ -0,0 +1,8 @@ +export enum PrinterEvent { + PRINTING, + PAUSED, + CLOSED, + CONNECTED, + IDLE, + UNKNOWN, +} diff --git a/src/app/plugins/filament/filament.interface.ts b/src/app/model/filament.model.ts similarity index 57% rename from src/app/plugins/filament/filament.interface.ts rename to src/app/model/filament.model.ts index f5a4f8ae8..c8536554b 100644 --- a/src/app/plugins/filament/filament.interface.ts +++ b/src/app/model/filament.model.ts @@ -1,11 +1,3 @@ -import { Observable } from 'rxjs'; - -export interface FilamentManagementPlugin { - getSpools(): Observable>; - getCurrentSpool(): Observable; - setSpool(spool: FilamentSpool): Observable; -} - export interface FilamentSpoolList { spools: Array; } diff --git a/src/app/model/files.model.ts b/src/app/model/files.model.ts new file mode 100644 index 000000000..12c74cf01 --- /dev/null +++ b/src/app/model/files.model.ts @@ -0,0 +1,22 @@ +export interface Directory { + folders: Array; + files: Array; +} + +export interface Folder { + origin: string; + path: string; + name: string; + size: string; +} + +export interface File { + origin: string; + path: string; + name: string; + size: string; + thumbnail: string; + printTime?: string; + filamentWeight?: number; + date?: string; +} diff --git a/src/app/model/index.ts b/src/app/model/index.ts new file mode 100644 index 000000000..dfaa0c554 --- /dev/null +++ b/src/app/model/index.ts @@ -0,0 +1,9 @@ +export * from './auth.model'; +export * from './enclosure.model'; +export * from './event.model'; +export * from './filament.model'; +export * from './files.model'; +export * from './job.model'; +export * from './printer-profile.model'; +export * from './printer.model'; +export * from './system.model'; diff --git a/src/app/model/job.model.ts b/src/app/model/job.model.ts new file mode 100644 index 000000000..60f794a2c --- /dev/null +++ b/src/app/model/job.model.ts @@ -0,0 +1,21 @@ +export interface JobStatus { + file: string; + fullPath: string; + progress: number; + zHeight: number | ZHeightLayer; + filamentAmount?: number; + timePrinted: Duration; + timeLeft?: Duration; + estimatedPrintTime?: Duration; + estimatedEndTime?: string; +} + +interface Duration { + value: string; + unit: string; +} + +export interface ZHeightLayer { + current: number; + total: number; +} diff --git a/src/app/model/octoprint/auth.model.ts b/src/app/model/octoprint/auth.model.ts new file mode 100644 index 000000000..97dcb163d --- /dev/null +++ b/src/app/model/octoprint/auth.model.ts @@ -0,0 +1,27 @@ +/* eslint-disable camelcase */ + +export interface OctoprintLogin { + _is_external_client: boolean; + _login_mechanism: string; + active: boolean; + admin: boolean; + apikey: string; + groups: Array; + name: string; + needs: { + groups: Array; + role: Array; + }; + permissions: Array; + roles: Array; + session: string; + user: boolean; +} + +export interface AppToken { + app_token: string; +} + +export interface TokenSuccess { + api_key: string; +} diff --git a/src/app/model/octoprint/connection.model.ts b/src/app/model/octoprint/connection.model.ts new file mode 100644 index 000000000..8b83a7e72 --- /dev/null +++ b/src/app/model/octoprint/connection.model.ts @@ -0,0 +1,8 @@ +export interface ConnectCommand { + command: string; + port?: string; + baudrate?: number; + printerProfile?: string; + save?: boolean; + autoconnect?: boolean; +} diff --git a/src/app/octoprint/model/file.ts b/src/app/model/octoprint/file.model.ts similarity index 85% rename from src/app/octoprint/model/file.ts rename to src/app/model/octoprint/file.model.ts index 40325eb10..586953d84 100644 --- a/src/app/octoprint/model/file.ts +++ b/src/app/model/octoprint/file.model.ts @@ -1,4 +1,4 @@ -import { OctoprintFilament } from './job'; +import { OctoprintFilament } from './socket.model'; export interface OctoprintFile { date: number; @@ -18,13 +18,7 @@ export interface OctoprintFile { } export interface OctoprintFolder { - files: [OctoprintFile & OctoprintFolderContent]; - free: number; - total: number; -} - -export interface OctoprintFolderContent { - children: [OctoprintFile & OctoprintFolderContent]; + children: [OctoprintFile & OctoprintFolder]; display: string; name: string; origin: string; @@ -74,3 +68,8 @@ interface OctoprintRefs { download?: string; resource: string; } + +export interface FileCommand { + command: 'select'; + print: boolean; +} diff --git a/src/app/model/octoprint/index.ts b/src/app/model/octoprint/index.ts new file mode 100644 index 000000000..0c6a9efe6 --- /dev/null +++ b/src/app/model/octoprint/index.ts @@ -0,0 +1,13 @@ +export * from './auth.model'; +export * from './connection.model'; +export * from './file.model'; +export * from './job.model'; +export * from './printer-commands.model'; +export * from './printer-profile.model'; +export * from './socket.model'; + +export * from './plugins/display-layer-progress.model'; +export * from './plugins/enclosure.model'; +export * from './plugins/filament-manager.model'; +export * from './plugins/psucontrol.model'; +export * from './plugins/tp-link.model'; diff --git a/src/app/model/octoprint/job.model.ts b/src/app/model/octoprint/job.model.ts new file mode 100644 index 000000000..1056e27af --- /dev/null +++ b/src/app/model/octoprint/job.model.ts @@ -0,0 +1,4 @@ +export interface JobCommand { + command: string; + action?: string; +} diff --git a/src/app/model/octoprint/plugins/display-layer-progress.model.ts b/src/app/model/octoprint/plugins/display-layer-progress.model.ts new file mode 100644 index 000000000..6ceb60c1c --- /dev/null +++ b/src/app/model/octoprint/plugins/display-layer-progress.model.ts @@ -0,0 +1,26 @@ +export interface DisplayLayerProgressData { + averageLayerDuration: string; + averageLayerDurationInSeconds: string; + changeFilamentCount: number; + changeFilamentTimeLeft: string; + changeFilamentTimeLeftInSeconds: string; + currentHeight: string; + currentHeightFormatted: string; + currentLayer: string; + estimatedChangeFilamentTime: string; + estimatedEndTime: string; + fanspeed: string; + feedrate: string; + feedrateG0: string; + feedrateG1: string; + lastLayerDuration: string; + m73progress: string; + printTimeLeft: string; + printTimeLeftInSeconds: string; + printerState: string; + progress: string; + totalHeight: string; + totalHeightFormatted: string; + totalLayer: string; + updateReason: string; +} diff --git a/src/app/model/octoprint/plugins/enclosure.model.ts b/src/app/model/octoprint/plugins/enclosure.model.ts new file mode 100644 index 000000000..b6ad7db1e --- /dev/null +++ b/src/app/model/octoprint/plugins/enclosure.model.ts @@ -0,0 +1,32 @@ +export interface EnclosurePluginAPI { + /* eslint-disable camelcase */ + controlled_io: string; + temp_sensor_address: string; + temp_sensor_navbar: boolean; + temp_sensor_temp: number; + printer_action: string; + filament_sensor_enabled: boolean; + controlled_io_set_value: number; + temp_sensor_type: string; + temp_sensor_humidity: number; + filament_sensor_timeout: number; + edge: string; + ds18b20_serial: string; + action_type: string; + input_pull_resistor: string; + input_type: string; + label: string; + index_id: number; + use_fahrenheit: boolean; + gpio_pin: string; +} + +export interface EnclosureColorBody { + red: number; + green: number; + blue: number; +} + +export interface EnclosureOutputBody { + status: boolean; +} diff --git a/src/app/model/octoprint/plugins/filament-manager.model.ts b/src/app/model/octoprint/plugins/filament-manager.model.ts new file mode 100644 index 000000000..e65cdf8bf --- /dev/null +++ b/src/app/model/octoprint/plugins/filament-manager.model.ts @@ -0,0 +1,44 @@ +export interface FilamentManagerSpoolList { + spools: FilamentManagerSpool[]; +} + +export interface FilamentManagerSelections { + selections: FilamentManagerSelection[]; +} + +export interface FilamentManagerSelectionPatch { + selection: { + tool: number; + spool: { + id: number; + }; + }; +} + +interface FilamentManagerSelection { + // eslint-disable-next-line camelcase + client_id: string; + spool: FilamentManagerSpool; + tool: number; +} + +export interface FilamentManagerSpool { + /* eslint-disable camelcase */ + cost: number; + id: number; + name: string; + displayName?: string; + color?: string; + profile: FilamentManagerProfile; + temp_offset: number; + used: number; + weight: number; +} + +interface FilamentManagerProfile { + density: number; + diameter: number; + id: number; + material: string; + vendor: string; +} diff --git a/src/app/model/octoprint/plugins/psucontrol.model.ts b/src/app/model/octoprint/plugins/psucontrol.model.ts new file mode 100644 index 000000000..83985f4f4 --- /dev/null +++ b/src/app/model/octoprint/plugins/psucontrol.model.ts @@ -0,0 +1,3 @@ +export interface PSUControlCommand { + command: 'turnPSUOn' | 'turnPSUOff'; +} diff --git a/src/app/model/octoprint/plugins/tp-link.model.ts b/src/app/model/octoprint/plugins/tp-link.model.ts new file mode 100644 index 000000000..1589fb1e1 --- /dev/null +++ b/src/app/model/octoprint/plugins/tp-link.model.ts @@ -0,0 +1,4 @@ +export interface TPLinkCommand { + command: 'turnOn' | 'turnOff'; + ip: string; +} diff --git a/src/app/model/octoprint/printer-commands.model.ts b/src/app/model/octoprint/printer-commands.model.ts new file mode 100644 index 000000000..102375b58 --- /dev/null +++ b/src/app/model/octoprint/printer-commands.model.ts @@ -0,0 +1,39 @@ +export interface JogCommand { + command: 'jog'; + x: number; + y: number; + z: number; + speed: number; +} + +export interface ExtrudeCommand { + command: 'extrude'; + amount: number; + speed: number; +} + +export interface GCodeCommand { + commands: string[]; +} + +export interface FeedrateCommand { + command: string; + factor: number; +} + +export interface TemperatureHotendCommand { + command: string; + targets: { + tool0: number; + tool1?: number; + }; +} + +export interface TemperatureHeatbedCommand { + command: string; + target: number; +} + +export interface DisconnectCommand { + command: string; +} diff --git a/src/app/octoprint/model/printerProfile.ts b/src/app/model/octoprint/printer-profile.model.ts similarity index 81% rename from src/app/octoprint/model/printerProfile.ts rename to src/app/model/octoprint/printer-profile.model.ts index fde49ab92..de837cb85 100644 --- a/src/app/octoprint/model/printerProfile.ts +++ b/src/app/model/octoprint/printer-profile.model.ts @@ -11,12 +11,12 @@ export interface OctoprintPrinterProfile { axes: OctoprintPrinterAxis; } -export interface OctoprintPrinterAxis { +interface OctoprintPrinterAxis { x: OctoprintAxisDetails; y: OctoprintAxisDetails; z: OctoprintAxisDetails; } -export interface OctoprintAxisDetails { +interface OctoprintAxisDetails { inverted: boolean; } diff --git a/src/app/model/octoprint/socket.model.ts b/src/app/model/octoprint/socket.model.ts new file mode 100644 index 000000000..d8875aad6 --- /dev/null +++ b/src/app/model/octoprint/socket.model.ts @@ -0,0 +1,99 @@ +/* eslint-disable camelcase */ +import { OctoprintFile } from './file.model'; + +export interface OctoprintSocketCurrent { + current: { + busyFiles: Array; + currentZ: number; + job: OctoprintJob; + logs: Array; + messages: Array; + offsets: OctoprintOffsets; + progress: OctoprintProgress; + resends: OctoprintSocketResends; + serverTime: number; + state: OctoprintSocketState; + temps: OctoprintSocketTemperatures; + }; +} + +export interface OctoprintSocketEvent { + event: { + type: string; + payload: unknown; + }; +} +export interface OctoprintPluginMessage { + plugin: { + plugin: string; + data: unknown; + }; +} + +interface OctoprintJob { + averagePrintTime: number; + estimatedPrintTime: number; + filament: OctoprintFilament; + file: OctoprintFile; + lastPrintTime: string; + user: string; +} +export interface OctoprintFilament { + [key: string]: OctoprintFilamentValues; +} + +interface OctoprintFilamentValues { + length: number; + volume: number; +} + +interface OctoprintOffsets { + tool0: number; +} + +interface OctoprintProgress { + completion: number; + filepos: number; + printTime: number; + printTimeLeft: number; + printTimeLeftOrigin: string; +} + +interface OctoprintSocketResends { + count: number; + transmitted: number; + ratio: number; +} + +interface OctoprintSocketState { + text: string; + flags: OctoprintSocketStateFlags; +} + +interface OctoprintSocketStateFlags { + cancelling: boolean; + closedOrError: boolean; + error: boolean; + finishing: boolean; + operational: boolean; + paused: boolean; + pausing: boolean; + printing: boolean; + ready: boolean; + resuming: boolean; + sdReady: boolean; +} + +interface OctoprintSocketTemperatures { + [key: number]: { + time: number; + bed: OctoprintSocketTemperature; + chamber: OctoprintSocketTemperature; + tool0: OctoprintSocketTemperature; + }; +} + +interface OctoprintSocketTemperature { + actual: number; + target: number; +} diff --git a/src/app/model/printer-profile.model.ts b/src/app/model/printer-profile.model.ts new file mode 100644 index 000000000..4ccb92677 --- /dev/null +++ b/src/app/model/printer-profile.model.ts @@ -0,0 +1,16 @@ +export interface PrinterProfile { + current: boolean; + name: string; + model: string; + axes: PrinterAxis; +} + +export interface PrinterAxis { + x: AxisDetails; + y: AxisDetails; + z: AxisDetails; +} + +export interface AxisDetails { + inverted: boolean; +} diff --git a/src/app/model/printer.model.ts b/src/app/model/printer.model.ts new file mode 100644 index 000000000..dee9a39f1 --- /dev/null +++ b/src/app/model/printer.model.ts @@ -0,0 +1,22 @@ +export interface PrinterStatus { + status: PrinterState; + bed: Temperature; + tool0: Temperature; + fanSpeed: number; +} + +interface Temperature { + current: number; + set: number; + unit: string; +} + +export enum PrinterState { + operational, + pausing, + paused, + printing, + cancelling, + closed, + connecting, +} diff --git a/src/app/model/system.model.ts b/src/app/model/system.model.ts new file mode 100644 index 000000000..afc37d66b --- /dev/null +++ b/src/app/model/system.model.ts @@ -0,0 +1,24 @@ +export interface Notification { + heading: string; + text: string; + type: string; + closed: () => void; +} + +export interface UpdateError { + error: { + message: string; + stack?: string; + }; +} + +export interface UpdateDownloadProgress { + percentage: number; + transferred: number; + total: number | string; + remaining: number; + eta: string; + runtime: string; + delta: number; + speed: number | string; +} diff --git a/src/app/notification/notification.component.ts b/src/app/notification/notification.component.ts index d06385ec0..a0b306129 100644 --- a/src/app/notification/notification.component.ts +++ b/src/app/notification/notification.component.ts @@ -1,7 +1,8 @@ import { Component, NgZone, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; -import { Notification, NotificationService } from './notification.service'; +import { Notification } from '../model'; +import { NotificationService } from './notification.service'; @Component({ selector: 'app-notification', diff --git a/src/app/notification/notification.service.ts b/src/app/notification/notification.service.ts index fc94a7f88..22b69ab58 100644 --- a/src/app/notification/notification.service.ts +++ b/src/app/notification/notification.service.ts @@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; import { Observable, Observer } from 'rxjs'; import { shareReplay } from 'rxjs/operators'; +import { Notification } from '../model'; + @Injectable({ providedIn: 'root', }) export class NotificationService { private observable: Observable; private observer: Observer; - private hideNotifications = false; - private bootGrace = true; + private bootGrace = false; public constructor() { this.observable = new Observable((observer: Observer): void => { @@ -20,46 +21,30 @@ export class NotificationService { }).pipe(shareReplay(1)); } - public enableNotifications(): void { - console.clear(); - this.hideNotifications = false; - this.observer.next('close'); - } - - public disableNotifications(): void { - console.clear(); - this.hideNotifications = true; - this.observer.next('close'); - } - public closeNotification(): void { this.observer.next('close'); } public setError(heading: string, text: string): Promise { return new Promise(resolve => { - if ((!this.hideNotifications && !this.bootGrace) || (this.bootGrace && !text.endsWith('0 Unknown Error'))) { - if (this.observer) { - this.observer.next({ heading, text, type: 'error', closed: resolve }); - } else { - setTimeout(() => { - this.setError(heading, text); - }, 1000); - } + if (this.observer) { + this.observer.next({ heading, text, type: 'error', closed: resolve }); + } else { + setTimeout(() => { + this.setError(heading, text); + }, 1000); } }); } public setWarning(heading: string, text: string): Promise { return new Promise(resolve => { - if (!this.hideNotifications) { - if (this.observer) { - this.observer.next({ heading, text, type: 'warn', closed: resolve }); - } else { - setTimeout(() => { - this.setWarning(heading, text); - }, 1000); - } + if (this.observer) { + this.observer.next({ heading, text, type: 'warn', closed: resolve }); + } else { + setTimeout(() => { + this.setWarning(heading, text); + }, 1000); } }); } @@ -84,10 +69,3 @@ export class NotificationService { return this.bootGrace; } } - -export interface Notification { - heading: string; - text: string; - type: string; - closed: () => void; -} diff --git a/src/app/octoprint.service.ts b/src/app/octoprint.service.ts deleted file mode 100644 index 1c7e668b5..000000000 --- a/src/app/octoprint.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { ConfigService } from './config/config.service'; -import { NotificationService } from './notification/notification.service'; - -@Injectable({ - providedIn: 'root', -}) -export class OctoprintService { - private httpPOSTRequest: Subscription; - - public constructor( - private http: HttpClient, - private configService: ConfigService, - private notificationService: NotificationService, - ) {} - - public disconnectPrinter(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const disconnectPayload: DisconnectCommand = { - command: 'disconnect', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('connection'), disconnectPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't disconnect from Printer!", error.message); - }, - ); - } - - public sendSystemCommand(command: string): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - this.httpPOSTRequest = this.http - .post(this.configService.getURL(`system/commands/core/${command}`), null, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError(`Can't execute ${command} command!`, error.message); - }, - ); - } -} - -interface DisconnectCommand { - command: string; -} diff --git a/src/app/octoprint/auth.service.ts b/src/app/octoprint/auth.service.ts deleted file mode 100644 index 41ffcc1fa..000000000 --- a/src/app/octoprint/auth.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable camelcase */ -import { HttpClient, HttpResponseBase } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -@Injectable({ - providedIn: 'root', -}) -export class AuthService { - constructor(private http: HttpClient) {} - - public probeSupport(octoprintURL: string): Observable { - return this.http.get(`${octoprintURL}plugin/appkeys/probe`, { observe: 'response' }); - } - - public startProcess(octoprintURL: string): Observable { - return this.http.post(`${octoprintURL}plugin/appkeys/request`, { app: 'OctoDash' }); - } - - public pollStatus(octoprintURL: string, token: string): Observable { - return this.http.get(`${octoprintURL}plugin/appkeys/request/${token}`, { observe: 'response' }); - } -} - -export interface AppToken { - app_token: string; -} - -export interface TokenSuccess { - api_key: string; -} diff --git a/src/app/octoprint/model/connection.ts b/src/app/octoprint/model/connection.ts deleted file mode 100644 index e8474547d..000000000 --- a/src/app/octoprint/model/connection.ts +++ /dev/null @@ -1,21 +0,0 @@ -export interface OctoprintConnection { - current: OctoprintCurrentConnection; - options: OctoprintConnectionOptions; -} - -interface OctoprintCurrentConnection { - state: string; - port: string; - baudrate: number; - printerProfile: string; -} - -interface OctoprintConnectionOptions { - ports: string[]; - baudrates: number[]; - printerProfiles: Record; - portPreference: string; - baudratePreference: string; - printerProfilePreference: string; - autoconnect: boolean; -} diff --git a/src/app/octoprint/model/job.ts b/src/app/octoprint/model/job.ts deleted file mode 100644 index c95212f89..000000000 --- a/src/app/octoprint/model/job.ts +++ /dev/null @@ -1,49 +0,0 @@ -export interface OctoprintJobStatus { - job: OctoprintJob; - progress: OctoprintProgress; - state: string; -} - -interface OctoprintJob { - file: OctoprintFile; - estimatedPrintTime: number; - filament: OctoprintFilament; -} - -interface OctoprintFile { - name: string; - origin: string; - display: string; - path?: string; - type?: string; - typePath?: string; - size: number; - date: number; -} - -export interface OctoprintFilament { - tool0?: OctoprintFilamentValues; - tool1?: OctoprintFilamentValues; - tool2?: OctoprintFilamentValues; - tool3?: OctoprintFilamentValues; - tool4?: OctoprintFilamentValues; - tool5?: OctoprintFilamentValues; - [key: string]: OctoprintFilamentValues; -} - -interface OctoprintFilamentValues { - length: number; - volume: number; -} - -interface OctoprintProgress { - completion: number; - filepos: number; - printTime: number; - printTimeLeft: number; -} - -export interface JobCommand { - command: string; - action?: string; -} diff --git a/src/app/octoprint/model/layerProgress.ts b/src/app/octoprint/model/layerProgress.ts deleted file mode 100644 index 6cb1eec72..000000000 --- a/src/app/octoprint/model/layerProgress.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface OctoprintLayerProgress { - layer: OctoprintLayer; - height: OctoprintHeight; - fanSpeed: string; - feedrate: string; -} - -interface OctoprintLayer { - total: string; - current: string; -} - -interface OctoprintHeight { - total: string; - totalWithExtrusion: string; - current: string; -} diff --git a/src/app/octoprint/model/printerStatus.ts b/src/app/octoprint/model/printerStatus.ts deleted file mode 100644 index 11f8971a3..000000000 --- a/src/app/octoprint/model/printerStatus.ts +++ /dev/null @@ -1,43 +0,0 @@ -export interface OctoprintPrinterStatus { - temperature: OctoprintTemperature; - sd: OctoprintSD; - state: OctoprintPrinterState; -} - -interface OctoprintTemperature { - tool0?: OctoprintTemperatureData; - tool1?: OctoprintTemperatureData; - tool2?: OctoprintTemperatureData; - tool3?: OctoprintTemperatureData; - tool4?: OctoprintTemperatureData; - tool5?: OctoprintTemperatureData; - bed?: OctoprintTemperatureData; - [key: string]: OctoprintTemperatureData; -} - -interface OctoprintTemperatureData { - actual: number; - target: number; - offset: number; -} - -interface OctoprintSD { - ready: boolean; -} - -interface OctoprintPrinterState { - text: string; - flags: OctoprintPrinterStateFlags; -} - -interface OctoprintPrinterStateFlags { - operational: boolean; - paused: boolean; - printing: boolean; - pausing: boolean; - cancelling: boolean; - sdReady: boolean; - error: boolean; - ready: boolean; - closedOrError: boolean; -} diff --git a/src/app/plugins/enclosure.service.ts b/src/app/plugins/enclosure.service.ts deleted file mode 100644 index 8c359c24f..000000000 --- a/src/app/plugins/enclosure.service.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable, Observer, Subscription, timer } from 'rxjs'; -import { shareReplay } from 'rxjs/operators'; - -import { TemperatureReading } from '../bottom-bar/bottom-bar.component'; -import { ConfigService } from '../config/config.service'; -import { NotificationService } from '../notification/notification.service'; - -@Injectable({ - providedIn: 'root', -}) -export class EnclosureService { - private httpGETRequest: Subscription; - private httpPOSTRequest: Subscription; - private observable: Observable; - private initialRequest = true; - - public constructor( - private http: HttpClient, - private configService: ConfigService, - private notificationService: NotificationService, - ) { - this.observable = new Observable((observer: Observer): void => { - timer(2500, 15000).subscribe((): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get( - this.configService - .getURL('plugin/enclosure/inputs/' + this.configService.getAmbientTemperatureSensorName()) - .replace('/api', ''), - this.configService.getHTTPHeaders(), - ) - .subscribe( - (data: EnclosurePluginAPI): void => { - this.initialRequest = false; - observer.next(({ - temperature: data.temp_sensor_temp, - humidity: data.temp_sensor_humidity, - unit: data.use_fahrenheit ? '°F' : '°C', - } as unknown) as TemperatureReading); - }, - (error: HttpErrorResponse): void => { - if (this.initialRequest && error.status === 500) { - this.initialRequest = false; - } else { - this.notificationService.setError("Can't retrieve enclosure temperature!", error.message); - } - }, - ); - }); - }).pipe(shareReplay(1)); - } - - public getObservable(): Observable { - return this.observable; - } - - public setLEDColor(identifier: number, red: number, green: number, blue: number): Promise { - return new Promise((resolve, reject): void => { - const colorBody: EnclosureColorBody = { - red, - green, - blue, - }; - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - this.httpPOSTRequest = this.http - .patch( - this.configService.getURL('plugin/enclosure/neopixel/' + identifier).replace('/api', ''), - colorBody, - this.configService.getHTTPHeaders(), - ) - .subscribe( - (): void => resolve(), - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't set LED color!", error.message); - reject(); - }, - ); - }); - } -} - -interface EnclosurePluginAPI { - /* eslint-disable camelcase */ - controlled_io: string; - temp_sensor_address: string; - temp_sensor_navbar: boolean; - temp_sensor_temp: number; - printer_action: string; - filament_sensor_enabled: boolean; - controlled_io_set_value: number; - temp_sensor_type: string; - temp_sensor_humidity: number; - filament_sensor_timeout: number; - edge: string; - ds18b20_serial: string; - action_type: string; - input_pull_resistor: string; - input_type: string; - label: string; - index_id: number; - use_fahrenheit: boolean; - gpio_pin: string; -} - -interface EnclosureColorBody { - red: number; - green: number; - blue: number; -} diff --git a/src/app/plugins/index.ts b/src/app/plugins/index.ts deleted file mode 100644 index 1c5398613..000000000 --- a/src/app/plugins/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './filament/filament-management.component'; -export * from './filament/filament-manager.service'; -export * from './filament/filament.interface'; -export * from './enclosure.service'; -export * from './layer-progress.service'; -export * from './psu-control.service'; -export * from './tplink-smartplug.service'; diff --git a/src/app/plugins/layer-progress.service.ts b/src/app/plugins/layer-progress.service.ts deleted file mode 100644 index 484d784fa..000000000 --- a/src/app/plugins/layer-progress.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable, Observer, Subscription, timer } from 'rxjs'; -import { shareReplay } from 'rxjs/operators'; - -import { ConfigService } from '../config/config.service'; -import { NotificationService } from '../notification/notification.service'; -import { OctoprintLayerProgress } from '../octoprint/model/layerProgress'; - -@Injectable({ - providedIn: 'root', -}) -export class LayerProgressService { - private httpGETRequest: Subscription; - private observable: Observable; - - public constructor( - private configService: ConfigService, - private notificationService: NotificationService, - private http: HttpClient, - ) { - this.observable = new Observable((observer: Observer): void => { - timer(1000, this.configService.getAPIPollingInterval()).subscribe((): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get( - this.configService.getURL('plugin/DisplayLayerProgress/values').replace('/api', ''), - this.configService.getHTTPHeaders(), - ) - .subscribe( - (data: OctoprintLayerProgress): void => { - observer.next({ - current: data.layer.current === '-' ? 0 : Number(data.layer.current), - total: data.layer.total === '-' ? 0 : Number(data.layer.total), - fanSpeed: data.fanSpeed === '-' ? 0 : data.fanSpeed === 'Off' ? 0 : data.fanSpeed.replace('%', ''), - }); - }, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't retrieve layer progress!", error.message); - }, - ); - }); - }).pipe(shareReplay(1)); - } - - public getObservable(): Observable { - return this.observable; - } -} - -export interface DisplayLayerProgressAPI { - current: number; - total: number; - fanSpeed: number | string; -} diff --git a/src/app/plugins/psu-control.service.ts b/src/app/plugins/psu-control.service.ts deleted file mode 100644 index a6d1b3be0..000000000 --- a/src/app/plugins/psu-control.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { ConfigService } from '../config/config.service'; -import { NotificationService } from '../notification/notification.service'; -import { JobCommand } from '../octoprint/model/job'; - -@Injectable({ - providedIn: 'root', -}) -export class PsuControlService { - private httpPOSTRequest: Subscription; - - public constructor( - private configService: ConfigService, - private notificationService: NotificationService, - private http: HttpClient, - ) {} - - public changePSUState(on: boolean): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const psuPayload: JobCommand = { - command: on ? 'turnPSUOn' : 'turnPSUOff', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('plugin/psucontrol'), psuPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't control PSU!", error.message); - }, - ); - } - - public togglePSU(): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const psuPayload: JobCommand = { - command: 'togglePSU', - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('plugin/psucontrol'), psuPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't control PSU!", error.message); - }, - ); - } -} diff --git a/src/app/plugins/tplink-smartplug.service.ts b/src/app/plugins/tplink-smartplug.service.ts deleted file mode 100644 index febc5d60a..000000000 --- a/src/app/plugins/tplink-smartplug.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { ConfigService } from '../config/config.service'; -import { NotificationService } from '../notification/notification.service'; - -@Injectable({ - providedIn: 'root', -}) -export class TPLinkSmartPlugService { - private httpPOSTRequest: Subscription; - - public constructor( - private configService: ConfigService, - private notificationService: NotificationService, - private http: HttpClient, - ) {} - - public changePowerState(on: boolean): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - - const payload = { - command: on ? 'turnOn' : 'turnOff', - ip: this.configService.getSmartPlugIP(), - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('plugin/tplinksmartplug'), payload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't control TPLink SmartPlug!", error.message); - }, - ); - } -} diff --git a/src/app/print-control/print-control.component.ts b/src/app/print-control/print-control.component.ts index 1eb416aae..34b36627d 100644 --- a/src/app/print-control/print-control.component.ts +++ b/src/app/print-control/print-control.component.ts @@ -4,9 +4,10 @@ import { Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; import { ConfigService } from '../config/config.service'; -import { Job, JobService, JobStatus } from '../job.service'; -import { DisplayLayerProgressAPI, LayerProgressService } from '../plugins/layer-progress.service'; -import { PrinterService, PrinterStatusAPI } from '../printer.service'; +import { PrinterState, PrinterStatus } from '../model'; +import { JobService } from '../services/job/job.service'; +import { PrinterService } from '../services/printer/printer.service'; +import { SocketService } from '../services/socket/socket.service'; @Component({ selector: 'app-print-control', @@ -30,8 +31,8 @@ export class PrintControlComponent implements OnInit, OnDestroy { public constructor( private jobService: JobService, private printerService: PrinterService, - private displayLayerProgressService: LayerProgressService, private configService: ConfigService, + private socketService: SocketService, private router: Router, ) { this.temperatureHotend = 0; @@ -43,8 +44,8 @@ export class PrintControlComponent implements OnInit, OnDestroy { public ngOnInit(): void { this.subscriptions.add( - this.jobService.getObservable().subscribe((job: Job): void => { - if (job.status === JobStatus.Paused) { + this.socketService.getPrinterStatusSubscribable().subscribe((printerStatus: PrinterStatus) => { + if (printerStatus.status === PrinterState.paused) { if (!this.showedPauseScreen) { this.view = ControlView.PAUSE; this.showControls = true; @@ -118,7 +119,7 @@ export class PrintControlComponent implements OnInit, OnDestroy { this.view = ControlView.MAIN; this.showControls = true; } else { - this.jobService.togglePreviewWhilePrinting(); + document.getElementById('jobTogglePreview').click(); } } @@ -161,19 +162,13 @@ export class PrintControlComponent implements OnInit, OnDestroy { } private loadData(): void { - this.printerService - .getObservable() + this.socketService + .getPrinterStatusSubscribable() .pipe(take(1)) - .subscribe((printerStatus: PrinterStatusAPI): void => { - this.temperatureHotend = printerStatus.nozzle.set; - this.temperatureHeatbed = printerStatus.heatbed.set; - }); - - this.displayLayerProgressService - .getObservable() - .pipe(take(1)) - .subscribe((layerProgress: DisplayLayerProgressAPI): void => { - this.fanSpeed = Number(layerProgress.fanSpeed); + .subscribe((status: PrinterStatus): void => { + this.temperatureHotend = status.tool0.set; + this.temperatureHeatbed = status.bed.set; + this.fanSpeed = status.fanSpeed; }); } @@ -228,7 +223,7 @@ export class PrintControlComponent implements OnInit, OnDestroy { public setAdjustParameters(event: MouseEvent): void { if (this.showControls) { this.printerService.setTemperatureHotend(this.temperatureHotend); - this.printerService.setTemperatureHeatbed(this.temperatureHeatbed); + this.printerService.setTemperatureBed(this.temperatureHeatbed); this.printerService.setFeedrate(this.feedrate); this.printerService.setFanSpeed(this.fanSpeed); this.hideControlOverlay(event); diff --git a/src/app/printer-status/printer-status.component.html b/src/app/printer-status/printer-status.component.html index b279a45ff..2c89e157e 100644 --- a/src/app/printer-status/printer-status.component.html +++ b/src/app/printer-status/printer-status.component.html @@ -2,32 +2,32 @@ - {{ printerStatus.nozzle.current }}°C + {{ printerStatus.tool0.current }}°C - - /{{ printerStatus.nozzle.set }}°C + + /{{ printerStatus.tool0.set }}°C - {{ printerStatus.heatbed.current }}°C + {{ printerStatus.bed.current }}°C - - /{{ printerStatus.heatbed.set }}°C + + /{{ printerStatus.bed.set }}°C - {{ printerStatus.fan }}% + {{ printerStatus.fanSpeed >= 0 ? printerStatus.fanSpeed : '-- ' }}% diff --git a/src/app/printer-status/printer-status.component.ts b/src/app/printer-status/printer-status.component.ts index eeac78a50..0414b2c68 100644 --- a/src/app/printer-status/printer-status.component.ts +++ b/src/app/printer-status/printer-status.component.ts @@ -2,8 +2,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { ConfigService } from '../config/config.service'; -import { DisplayLayerProgressAPI, LayerProgressService } from '../plugins/layer-progress.service'; -import { PrinterService, PrinterStatusAPI, PrinterValue } from '../printer.service'; +import { PrinterStatus } from '../model'; +import { PrinterService } from '../services/printer/printer.service'; +import { SocketService } from '../services/socket/socket.service'; @Component({ selector: 'app-printer-status', @@ -13,30 +14,21 @@ import { PrinterService, PrinterStatusAPI, PrinterValue } from '../printer.servi export class PrinterStatusComponent implements OnInit, OnDestroy { private subscriptions: Subscription = new Subscription(); public printerStatus: PrinterStatus; + public fanSpeed: number; public status: string; - public QuickControlView = QuickControlView; - public view = QuickControlView.NONE; + public hotendTarget: number; public heatbedTarget: number; public fanTarget: number; + public QuickControlView = QuickControlView; + public view = QuickControlView.NONE; + public constructor( private printerService: PrinterService, - private displayLayerProgressService: LayerProgressService, private configService: ConfigService, + private socketService: SocketService, ) { - this.printerStatus = { - nozzle: { - current: 0, - set: 0, - }, - heatbed: { - current: 0, - set: 0, - }, - fan: 0, - }; - this.status = 'connecting'; this.hotendTarget = this.configService.getDefaultHotendTemperature(); this.heatbedTarget = this.configService.getDefaultHeatbedTemperature(); this.fanTarget = this.configService.getDefaultFanSpeed(); @@ -44,16 +36,8 @@ export class PrinterStatusComponent implements OnInit, OnDestroy { public ngOnInit(): void { this.subscriptions.add( - this.printerService.getObservable().subscribe((printerStatus: PrinterStatusAPI): void => { - this.printerStatus.nozzle = printerStatus.nozzle; - this.printerStatus.heatbed = printerStatus.heatbed; - this.status = printerStatus.status; - }), - ); - - this.subscriptions.add( - this.displayLayerProgressService.getObservable().subscribe((layerProgress: DisplayLayerProgressAPI): void => { - this.printerStatus.fan = layerProgress.fanSpeed; + this.socketService.getPrinterStatusSubscribable().subscribe((status: PrinterStatus): void => { + this.printerStatus = status; }), ); } @@ -159,7 +143,7 @@ export class PrinterStatusComponent implements OnInit, OnDestroy { } private setTemperatureHeatbed(): void { - this.printerService.setTemperatureHeatbed(this.heatbedTarget); + this.printerService.setTemperatureBed(this.heatbedTarget); this.hideQuickControl(); } @@ -169,12 +153,6 @@ export class PrinterStatusComponent implements OnInit, OnDestroy { } } -export interface PrinterStatus { - nozzle: PrinterValue; - heatbed: PrinterValue; - fan: number | string; -} - enum QuickControlView { NONE, HOTEND, diff --git a/src/app/printer.service.ts b/src/app/printer.service.ts deleted file mode 100644 index 8076fce07..000000000 --- a/src/app/printer.service.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { Observable, Observer, Subscription, timer } from 'rxjs'; -import { shareReplay } from 'rxjs/operators'; - -import { ConfigService } from './config/config.service'; -import { NotificationService } from './notification/notification.service'; -import { OctoprintConnection } from './octoprint/model/connection'; -import { OctoprintPrinterStatus } from './octoprint/model/printerStatus'; - -@Injectable({ - providedIn: 'root', -}) -export class PrinterService { - private httpGETRequest: Subscription; - private httpPOSTRequest: Subscription; - private observable: Observable; - - public constructor( - private http: HttpClient, - private configService: ConfigService, - private notificationService: NotificationService, - private router: Router, - ) { - this.observable = new Observable((observer: Observer): void => { - timer(500, this.configService.getAPIPollingInterval()).subscribe((): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('printer'), this.configService.getHTTPHeaders()) - .subscribe( - (data: OctoprintPrinterStatus): void => { - const printerStatus: PrinterStatusAPI = { - status: data.state.text.toLowerCase(), - nozzle: { - current: Math.round(data.temperature.tool0.actual), - set: Math.round(data.temperature.tool0.target), - }, - heatbed: { - current: data.temperature.bed ? Math.round(data.temperature.bed.actual) : 0, - set: data.temperature.bed ? Math.round(data.temperature.bed.target) : 0, - }, - }; - observer.next(printerStatus); - }, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.isPrinterOffline().then((printerOffline): void => { - if (printerOffline) { - this.router.navigate(['/standby']); - } else { - this.notificationService.setError("Can't retrieve printer status!", error.message); - } - }); - } else if (error.status === 0 && this.notificationService.getBootGrace()) { - const printerStatus: PrinterStatusAPI = { - status: `connecting ...`, - nozzle: { - current: 0, - set: 0, - }, - heatbed: { - current: 0, - set: 0, - }, - }; - observer.next(printerStatus); - } else { - const printerStatus: PrinterStatusAPI = { - status: `error (${error.status})`, - nozzle: { - current: 0, - set: 0, - }, - heatbed: { - current: 0, - set: 0, - }, - }; - observer.next(printerStatus); - this.notificationService.setError("Can't retrieve printer status!", error.message); - } - }, - ); - }); - }).pipe(shareReplay(1)); - } - - public getObservable(): Observable { - return this.observable; - } - - public stopMotors(): void { - this.executeGCode('M410'); - } - - public jog(x: number, y: number, z: number): void { - const jogPayload: JogCommand = { - command: 'jog', - x, - y, - z, - speed: z !== 0 ? this.configService.getZSpeed() * 60 : this.configService.getXYSpeed() * 60, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/printhead'), jogPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't move Printhead!", error.message); - }, - ); - } - - public extrude(amount: number, speed: number): void { - let multiplier = 1; - let toBeExtruded: number; - if (amount < 0) { - multiplier = -1; - toBeExtruded = amount * -1; - } else { - toBeExtruded = amount; - } - - while (toBeExtruded > 0) { - if (toBeExtruded >= 100) { - toBeExtruded -= 100; - this.moveExtruder(100 * multiplier, speed); - } else { - this.moveExtruder(toBeExtruded * multiplier, speed); - toBeExtruded = 0; - } - } - } - - private moveExtruder(amount: number, speed: number): void { - const extrudePayload: ExtrudeCommand = { - command: 'extrude', - amount, - speed: speed * 60, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/tool'), extrudePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't extrude Filament!", error.message); - }, - ); - } - - public executeGCode(gCode: string): void { - if (this.httpPOSTRequest) { - this.httpPOSTRequest.unsubscribe(); - } - const gCodePayload: GCodeCommand = { - commands: gCode.split('; '), - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/command'), gCodePayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't send GCode!", error.message); - }, - ); - } - - public setTemperatureHotend(temperature: number): void { - const temperatureHotendCommand: TemperatureHotendCommand = { - command: 'target', - targets: { - tool0: temperature, - }, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/tool'), temperatureHotendCommand, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't set Hotend Temperature!", error.message); - }, - ); - } - - public setTemperatureHeatbed(temperature: number): void { - const temperatureHeatbedCommand: TemperatureHeatbedCommand = { - command: 'target', - target: temperature, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/bed'), temperatureHeatbedCommand, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't set Heatbed Temperature!", error.message); - }, - ); - } - - public setFeedrate(feedrate: number): void { - if (feedrate === 100) { - return; - } - const feedrateCommand: FeedrateCommand = { - command: 'feedrate', - factor: feedrate, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/printhead'), feedrateCommand, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't set Feedrate!", error.message); - }, - ); - } - - public setFlowrate(flowrate: number): void { - if (flowrate === 100) { - return; - } - const flowrateCommand: FeedrateCommand = { - command: 'flowrate', - factor: flowrate, - }; - this.httpPOSTRequest = this.http - .post(this.configService.getURL('printer/tool'), flowrateCommand, this.configService.getHTTPHeaders()) - .subscribe( - (): void => null, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't set Flowrate!", error.message); - }, - ); - } - - public setFanSpeed(percentage: number): void { - this.executeGCode('M106 S' + Math.round((percentage / 100) * 255)); - } - - public isPrinterOffline(): Promise { - return new Promise((resolve): void => { - this.http.get(this.configService.getURL('connection'), this.configService.getHTTPHeaders()).subscribe( - (data: OctoprintConnection): void => { - resolve(data.current.state === 'Closed' || data.current.state.includes('Error:')); - }, - (error: HttpErrorResponse): void => { - this.notificationService.setError("Can't retrieve connection state!", error.message); - resolve(false); - }, - ); - }); - } -} - -export interface PrinterStatusAPI { - status: string; - nozzle: PrinterValue; - heatbed: PrinterValue; -} - -export interface PrinterValue { - current: number; - set: number; -} - -interface JogCommand { - command: 'jog'; - x: number; - y: number; - z: number; - speed: number; -} - -interface ExtrudeCommand { - command: 'extrude'; - amount: number; - speed: number; -} - -interface ExtrudeCommand { - command: 'extrude'; - amount: number; - speed: number; -} - -interface GCodeCommand { - commands: string[]; -} - -interface FeedrateCommand { - command: string; - factor: number; -} - -interface TemperatureHotendCommand { - command: string; - targets: { - tool0: number; - tool1?: number; - }; -} - -interface TemperatureHeatbedCommand { - command: string; - target: number; -} diff --git a/src/app/printerprofile.service.ts b/src/app/printerprofile.service.ts deleted file mode 100644 index 7e816a807..000000000 --- a/src/app/printerprofile.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { ConfigService } from './config/config.service'; -import { NotificationService } from './notification/notification.service'; -import { OctoprintPrinterProfile, OctoprintPrinterProfiles } from './octoprint/model/printerProfile'; -import { PrinterService } from './printer.service'; - -@Injectable({ - providedIn: 'root', -}) -export class PrinterProfileService { - private httpGETRequest: Subscription; - - public constructor( - private http: HttpClient, - private configService: ConfigService, - private notificationService: NotificationService, - private printerStatusService: PrinterService, - private router: Router, - ) {} - - public getDefaultPrinterProfile(): Promise { - return new Promise((resolve, reject): void => { - if (this.httpGETRequest) { - this.httpGETRequest.unsubscribe(); - } - this.httpGETRequest = this.http - .get(this.configService.getURL('printerprofiles/_default'), this.configService.getHTTPHeaders()) - .subscribe( - (printerProfile: OctoprintPrinterProfile): void => { - resolve(printerProfile); - }, - (error: HttpErrorResponse): void => { - if (error.status === 409) { - this.printerStatusService.isPrinterOffline().then((printerOffline): void => { - if (printerOffline) { - this.router.navigate(['/standby']); - } else { - this.notificationService.setError("Can't retrieve printer profile!", error.message); - } - }); - reject(); - } else { - reject(); - if (error.status === 0 && this.notificationService.getBootGrace()) { - this.notificationService.setError("Can't retrieve printer status!", error.message); - } - } - }, - ); - }); - } - - // Needed for initial setup. Config not initialized yet, thus values need to be passed manually. - public getActivePrinterProfileName(octoprintURL: string, apiKey: string): Observable { - return this.http - .get(`${octoprintURL}printerprofiles`, { - headers: new HttpHeaders({ - 'x-api-key': apiKey, - }), - }) - .pipe( - map(profiles => { - for (const [_, profile] of Object.entries(profiles.profiles)) { - return profile.name; - } - }), - ); - } -} diff --git a/src/app/services/enclosure/enclosure.octoprint.service.ts b/src/app/services/enclosure/enclosure.octoprint.service.ts new file mode 100644 index 000000000..a836db79f --- /dev/null +++ b/src/app/services/enclosure/enclosure.octoprint.service.ts @@ -0,0 +1,113 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { ConfigService } from '../../config/config.service'; +import { PSUState, TemperatureReading } from '../../model'; +import { + EnclosureColorBody, + EnclosureOutputBody, + EnclosurePluginAPI, + PSUControlCommand, + TPLinkCommand, +} from '../../model/octoprint'; +import { NotificationService } from '../../notification/notification.service'; +import { EnclosureService } from './enclosure.service'; + +@Injectable() +export class EnclosureOctoprintService implements EnclosureService { + public constructor( + private configService: ConfigService, + private notificationService: NotificationService, + private http: HttpClient, + ) {} + private currentPSUState = PSUState.ON; + + getEnclosureTemperature(): Observable { + return this.http + .get( + this.configService.getApiURL( + 'plugin/enclosure/inputs/' + this.configService.getAmbientTemperatureSensorName(), + false, + ), + this.configService.getHTTPHeaders(), + ) + .pipe( + map((data: EnclosurePluginAPI) => { + return { + temperature: data.temp_sensor_temp, + humidity: data.temp_sensor_humidity, + unit: data.use_fahrenheit ? '°F' : '°C', + } as TemperatureReading; + }), + ); + } + + setLEDColor(identifier: number, red: number, green: number, blue: number): void { + const colorBody: EnclosureColorBody = { + red, + green, + blue, + }; + this.http + .patch( + this.configService.getApiURL('plugin/enclosure/neopixel/' + identifier, false), + colorBody, + this.configService.getHTTPHeaders(), + ) + .pipe(catchError(error => this.notificationService.setError("Can't set LED color!", error.message))) + .subscribe(); + } + + setOutput(identifier: number, status: boolean): void { + const outputBody: EnclosureOutputBody = { + status, + }; + this.http + .patch( + this.configService.getApiURL('plugin/enclosure/outputs/' + identifier, false), + outputBody, + this.configService.getHTTPHeaders(), + ) + .pipe(catchError(error => this.notificationService.setError("Can't set output!", error.message))) + .subscribe(); + } + + setPSUState(state: PSUState): void { + if (this.configService.usePSUControl()) { + this.setPSUStatePSUControl(state); + } else if (this.configService.useTpLinkSmartPlug()) { + this.setPSUStateTPLink(state); + } else { + this.notificationService.setWarning("Can't change PSU State!", 'No provider for PSU Control is configured.'); + } + } + + private setPSUStatePSUControl(state: PSUState) { + const psuControlPayload: PSUControlCommand = { + command: state === PSUState.ON ? 'turnPSUOn' : 'turnPSUOff', + }; + + this.http + .post(this.configService.getApiURL('plugin/psucontrol'), psuControlPayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't send GCode!", error.message))) + .subscribe(); + } + + private setPSUStateTPLink(state: PSUState) { + const tpLinkPayload: TPLinkCommand = { + command: state === PSUState.ON ? 'turnOn' : 'turnOff', + ip: this.configService.getSmartPlugIP(), + }; + + this.http + .post(this.configService.getApiURL('plugin/tplinksmartplug'), tpLinkPayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't send GCode!", error.message))) + .subscribe(); + } + + togglePSU(): void { + this.currentPSUState === PSUState.ON ? this.setPSUState(PSUState.OFF) : this.setPSUState(PSUState.ON); + } +} diff --git a/src/app/services/enclosure/enclosure.service.ts b/src/app/services/enclosure/enclosure.service.ts new file mode 100644 index 000000000..0341407f5 --- /dev/null +++ b/src/app/services/enclosure/enclosure.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { PSUState, TemperatureReading } from '../../model'; + +@Injectable() +export abstract class EnclosureService { + abstract getEnclosureTemperature(): Observable; + + abstract setLEDColor(identifier: number, red: number, green: number, blue: number): void; + + abstract setOutput(identifier: number, status: boolean): void; + + abstract setPSUState(state: PSUState): void; + + abstract togglePSU(): void; +} diff --git a/src/app/plugins/filament/filament-manager.service.ts b/src/app/services/filament/filament-manager.octoprint.service.ts similarity index 62% rename from src/app/plugins/filament/filament-manager.service.ts rename to src/app/services/filament/filament-manager.octoprint.service.ts index 30fe05f86..379531a69 100644 --- a/src/app/plugins/filament/filament-manager.service.ts +++ b/src/app/services/filament/filament-manager.octoprint.service.ts @@ -4,22 +4,24 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ConfigService } from '../../config/config.service'; -import { FilamentManagementPlugin, FilamentSpool } from './filament.interface'; +import { FilamentSpool } from '../../model'; +import { + FilamentManagerSelectionPatch, + FilamentManagerSelections, + FilamentManagerSpool, + FilamentManagerSpoolList, +} from '../../model/octoprint'; +import { FilamentPluginService } from './filament-plugin.service'; const colorRegexp = /\((.*)\)$/g; -@Injectable({ - providedIn: 'root', -}) -export class FilamentManagerService implements FilamentManagementPlugin { +@Injectable() +export class FilamentManagerOctoprintService implements FilamentPluginService { public constructor(private configService: ConfigService, private http: HttpClient) {} public getSpools(): Observable> { return this.http - .get( - this.configService.getURL('plugin/filamentmanager/spools').replace('/api', ''), - this.configService.getHTTPHeaders(), - ) + .get(this.configService.getApiURL('plugin/filamentmanager/spools', false), this.configService.getHTTPHeaders()) .pipe( map( (spools: FilamentManagerSpoolList): Array => { @@ -36,7 +38,7 @@ export class FilamentManagerService implements FilamentManagementPlugin { public getCurrentSpool(): Observable { return this.http .get( - this.configService.getURL('plugin/filamentmanager/selections').replace('/api', ''), + this.configService.getApiURL('plugin/filamentmanager/selections', false), this.configService.getHTTPHeaders(), ) .pipe( @@ -83,54 +85,9 @@ export class FilamentManagerService implements FilamentManagementPlugin { }; return this.http.patch( - this.configService.getURL('plugin/filamentmanager/selections/0').replace('/api', ''), + this.configService.getApiURL('plugin/filamentmanager/selections/0', false), setSpoolBody, this.configService.getHTTPHeaders(), ); } } - -export interface FilamentManagerSpoolList { - spools: FilamentManagerSpool[]; -} - -interface FilamentManagerSelections { - selections: FilamentManagerSelection[]; -} - -interface FilamentManagerSelectionPatch { - selection: { - tool: number; - spool: { - id: number; - }; - }; -} - -interface FilamentManagerSelection { - // eslint-disable-next-line camelcase - client_id: string; - spool: FilamentManagerSpool; - tool: number; -} - -interface FilamentManagerSpool { - /* eslint-disable camelcase */ - cost: number; - id: number; - name: string; - displayName?: string; - color?: string; - profile: FilamentManagerProfile; - temp_offset: number; - used: number; - weight: number; -} - -interface FilamentManagerProfile { - density: number; - diameter: number; - id: number; - material: string; - vendor: string; -} diff --git a/src/app/services/filament/filament-plugin.service.ts b/src/app/services/filament/filament-plugin.service.ts new file mode 100644 index 000000000..c1990ce74 --- /dev/null +++ b/src/app/services/filament/filament-plugin.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { FilamentSpool } from '../../model'; + +@Injectable() +export abstract class FilamentPluginService { + abstract getSpools(): Observable>; + + abstract getCurrentSpool(): Observable; + + abstract setSpool(spool: FilamentSpool): Observable; +} diff --git a/src/app/plugins/filament/filament-management.component.ts b/src/app/services/filament/filament.service.ts similarity index 58% rename from src/app/plugins/filament/filament-management.component.ts rename to src/app/services/filament/filament.service.ts index 70dac04eb..0bb318c24 100644 --- a/src/app/plugins/filament/filament-management.component.ts +++ b/src/app/services/filament/filament.service.ts @@ -1,50 +1,42 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { Component, Injector } from '@angular/core'; -import { ConfigService } from 'src/app/config/config.service'; +import { Injectable } from '@angular/core'; +import { ConfigService } from '../../config/config.service'; +import { FilamentSpool } from '../../model'; import { NotificationService } from '../../notification/notification.service'; -import { FilamentManagementPlugin, FilamentSpool } from './filament.interface'; -import { FilamentManagerService } from './filament-manager.service'; +import { FilamentPluginService } from './filament-plugin.service'; -@Component({ - selector: 'backend-filament-manager', - template: '', - styles: [], -}) -export class FilamentManagementComponent { - private filamentPlugin: FilamentManagementPlugin; - - private _filamentSpools: Array; - private _currentSpool: FilamentSpool; - - private _loading = true; +@Injectable() +export class FilamentService { + private filamentSpools: Array; + private currentSpool: FilamentSpool; + private loading = true; constructor( - private injector: Injector, private notificationService: NotificationService, private configService: ConfigService, + private filamentPluginService: FilamentPluginService, ) { if (this.configService.isFilamentManagerEnabled()) { - this.filamentPlugin = this.injector.get(FilamentManagerService); this.loadSpools(); } } private loadSpools(): void { - this.filamentPlugin.getSpools().subscribe( + this.filamentPluginService.getSpools().subscribe( (spools: Array): void => { - this._filamentSpools = spools; + this.filamentSpools = spools; }, (error: HttpErrorResponse): void => { this.notificationService.setError("Can't load filament spools!", error.message); }, (): void => { - this._loading = false; + this.loading = false; }, ); - this.filamentPlugin.getCurrentSpool().subscribe( + this.filamentPluginService.getCurrentSpool().subscribe( (spool: FilamentSpool): void => { - this._currentSpool = spool; + this.currentSpool = spool; }, (error: HttpErrorResponse): void => { this.notificationService.setError("Can't load active spool!", error.message); @@ -52,23 +44,23 @@ export class FilamentManagementComponent { ); } - public get filamentSpools(): Array { - return this._filamentSpools; + public getFilamentSpools(): Array { + return this.filamentSpools; } - public get currentSpool(): FilamentSpool { - return this._currentSpool; + public getCurrentSpool(): FilamentSpool { + return this.currentSpool; } - public get loading(): boolean { - return this._loading; + public getLoading(): boolean { + return this.loading; } public setSpool(spool: FilamentSpool): Promise { return new Promise((resolve, reject) => { - this.filamentPlugin.setSpool(spool).subscribe( + this.filamentPluginService.setSpool(spool).subscribe( (): void => { - this.filamentPlugin.getCurrentSpool().subscribe( + this.filamentPluginService.getCurrentSpool().subscribe( (spoolRemote: FilamentSpool): void => { if (spool.id === spoolRemote.id) resolve(); else { diff --git a/src/app/services/files/files.octoprint.service.ts b/src/app/services/files/files.octoprint.service.ts new file mode 100644 index 000000000..27b1ba5e7 --- /dev/null +++ b/src/app/services/files/files.octoprint.service.ts @@ -0,0 +1,178 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import _ from 'lodash-es'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { ConfigService } from '../../config/config.service'; +import { ConversionService } from '../../conversion.service'; +import { Directory, File, Folder } from '../../model'; +import { FileCommand, OctoprintFile, OctoprintFolder } from '../../model/octoprint'; +import { NotificationService } from '../../notification/notification.service'; +import { FilesService } from './files.service'; + +@Injectable({ + providedIn: 'root', +}) +export class FilesOctoprintService implements FilesService { + private loadedFile = false; + + public constructor( + private configService: ConfigService, + private notificationService: NotificationService, + private http: HttpClient, + private conversionService: ConversionService, + ) {} + + public getFolderContent(folderPath?: string): Observable { + return this.http + .get( + this.configService.getApiURL('files' + (folderPath === '/' ? '' : folderPath)), + this.configService.getHTTPHeaders(), + ) + .pipe( + map(response => { + if (Object.prototype.hasOwnProperty.call(response, 'children')) { + return response['children']; + } else { + return response['files']; + } + }), + map((folderContent: Array) => { + const directory: Directory = { files: [], folders: [] }; + + folderContent.forEach(fileOrFolder => { + if (fileOrFolder.type === 'folder') { + directory.folders.push({ + origin: fileOrFolder.origin, + path: '/' + fileOrFolder.origin + '/' + fileOrFolder.path, + name: fileOrFolder.name, + size: this.conversionService.convertByteToMegabyte(fileOrFolder.size), + } as Folder); + } + + if (fileOrFolder.typePath.includes('gcode')) { + directory.files.push({ + origin: fileOrFolder.origin, + path: '/' + fileOrFolder.origin + '/' + fileOrFolder.path, + name: fileOrFolder.name, + date: this.conversionService.convertDateToString(new Date(fileOrFolder.date * 1000)), + size: this.conversionService.convertByteToMegabyte(fileOrFolder.size), + ...(fileOrFolder.gcodeAnalysis + ? { + printTime: this.conversionService.convertSecondsToHours( + fileOrFolder.gcodeAnalysis.estimatedPrintTime, + ), + filamentWeight: this.conversionService.convertFilamentLengthToWeight( + _.sumBy(_.values(fileOrFolder.gcodeAnalysis.filament), tool => tool.length), + ), + } + : {}), + } as File); + } + }); + + return directory; + }), + map((directory: Directory) => { + if (folderPath === '/') { + const localCount = _.sumBy(_.concat(directory.files, directory.folders), (fileOrFolder: File & Folder) => + fileOrFolder.origin === 'local' ? 1 : 0, + ); + const sdCardCount = _.sumBy(_.concat(directory.files, directory.folders), (fileOrFolder: File & Folder) => + fileOrFolder.origin === 'sdcard' ? 1 : 0, + ); + + if (localCount > 0 && sdCardCount > 0) { + directory.folders.push({ + origin: 'local', + path: '/local', + name: 'local', + size: `${localCount} files`, + } as Folder); + directory.folders.push({ + origin: 'sdcard', + path: '/sdcard', + name: 'sdcard', + size: `${localCount} files`, + } as Folder); + } + } + + return directory; + }), + ); + } + + public getFile(filePath: string): Observable { + return this.http.get(this.configService.getApiURL('files' + filePath), this.configService.getHTTPHeaders()).pipe( + map( + (file: OctoprintFile): File => { + return { + origin: file.origin, + path: '/' + file.origin + '/' + file.path, + name: file.name, + date: this.conversionService.convertDateToString(new Date(file.date * 1000)), + size: this.conversionService.convertByteToMegabyte(file.size), + thumbnail: file.thumbnail ? this.configService.getApiURL(file.thumbnail, false) : 'assets/object.svg', + ...(file.gcodeAnalysis + ? { + printTime: this.conversionService.convertSecondsToHours(file.gcodeAnalysis.estimatedPrintTime), + filamentWeight: this.conversionService.convertFilamentLengthToWeight( + _.sumBy(_.values(file.gcodeAnalysis.filament), tool => tool.length), + ), + } + : {}), + } as File; + }, + ), + ); + } + + public getThumbnail(filePath: string): Observable { + return this.http.get(this.configService.getApiURL('files' + filePath), this.configService.getHTTPHeaders()).pipe( + map((file: OctoprintFile): string => { + return file.thumbnail ? this.configService.getApiURL(file.thumbnail, false) : 'assets/object.svg'; + }), + ); + } + + public loadFile(filePath: string): void { + const payload: FileCommand = { + command: 'select', + print: false, + }; + + this.http + .post(this.configService.getApiURL('files' + filePath), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't load file!", error.message))) + .subscribe(); + } + + public printFile(filePath: string): void { + const payload: FileCommand = { + command: 'select', + print: true, + }; + + this.http + .post(this.configService.getApiURL('files' + filePath), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't start print!", error.message))) + .subscribe(); + } + + public deleteFile(filePath: string): void { + this.http + .delete(this.configService.getApiURL('files' + filePath), this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't delete file!", error.message))) + .subscribe(); + } + + public setLoadedFile(value: boolean): void { + this.loadedFile = value; + } + + public getLoadedFile(): boolean { + return this.loadedFile; + } +} diff --git a/src/app/services/files/files.service.ts b/src/app/services/files/files.service.ts new file mode 100644 index 000000000..676d9f3ba --- /dev/null +++ b/src/app/services/files/files.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { Directory, File } from '../../model'; + +@Injectable() +export abstract class FilesService { + abstract getFolderContent(folderPath: string): Observable; + + abstract getFile(filePath: string): Observable; + + abstract getThumbnail(filePath: string): Observable; + + abstract loadFile(filePath: string): void; + + abstract printFile(filePath: string): void; + + abstract deleteFile(filePath: string): void; + + abstract setLoadedFile(value: boolean): void; + + abstract getLoadedFile(): boolean; +} diff --git a/src/app/services/job/job.octoprint.service.ts b/src/app/services/job/job.octoprint.service.ts new file mode 100644 index 000000000..db591879f --- /dev/null +++ b/src/app/services/job/job.octoprint.service.ts @@ -0,0 +1,85 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { catchError } from 'rxjs/operators'; + +import { ConfigService } from '../../config/config.service'; +import { JobCommand } from '../../model/octoprint'; +import { NotificationService } from '../../notification/notification.service'; +import { JobService } from './job.service'; + +@Injectable() +export class JobOctoprintService implements JobService { + public constructor( + private configService: ConfigService, + private notificationService: NotificationService, + private http: HttpClient, + ) {} + + startJob(): void { + const payload: JobCommand = { + command: 'start', + }; + + this.http + .post(this.configService.getApiURL('job'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't start job!", error.message))) + .subscribe(); + } + + pauseJob(): void { + const payload: JobCommand = { + command: 'pause', + action: 'pause', + }; + + this.http + .post(this.configService.getApiURL('job'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't pause job!", error.message))) + .subscribe(); + } + + resumeJob(): void { + const payload: JobCommand = { + command: 'pause', + action: 'resume', + }; + + this.http + .post(this.configService.getApiURL('job'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't resume job!", error.message))) + .subscribe(); + } + + cancelJob(): void { + const payload: JobCommand = { + command: 'cancel', + }; + + this.http + .post(this.configService.getApiURL('job'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't cancel job!", error.message))) + .subscribe(); + } + + restartJob(): void { + const payload: JobCommand = { + command: 'restart', + }; + + this.http + .post(this.configService.getApiURL('job'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't restart job!", error.message))) + .subscribe(); + } + + preheat(): void { + const payload: JobCommand = { + command: 'preheat', + }; + + this.http + .post(this.configService.getApiURL('plugin/preheat'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't preheat printer!", error.message))) + .subscribe(); + } +} diff --git a/src/app/services/job/job.service.ts b/src/app/services/job/job.service.ts new file mode 100644 index 000000000..3eba8008d --- /dev/null +++ b/src/app/services/job/job.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export abstract class JobService { + abstract startJob(): void; + + abstract pauseJob(): void; + + abstract resumeJob(): void; + + abstract cancelJob(): void; + + abstract restartJob(): void; + + abstract preheat(): void; +} diff --git a/src/app/services/printer/printer.octoprint.service.ts b/src/app/services/printer/printer.octoprint.service.ts new file mode 100644 index 000000000..edd051391 --- /dev/null +++ b/src/app/services/printer/printer.octoprint.service.ts @@ -0,0 +1,170 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { ConfigService } from '../../config/config.service'; +import { PrinterProfile } from '../../model'; +import { + DisconnectCommand, + ExtrudeCommand, + FeedrateCommand, + GCodeCommand, + JogCommand, + OctoprintPrinterProfiles, + TemperatureHeatbedCommand, + TemperatureHotendCommand, +} from '../../model/octoprint'; +import { NotificationService } from '../../notification/notification.service'; +import { PrinterService } from './printer.service'; + +@Injectable() +export class PrinterOctoprintService implements PrinterService { + public constructor( + private configService: ConfigService, + private notificationService: NotificationService, + private http: HttpClient, + ) {} + + public getActiveProfile(): Observable { + return this.http + .get( + this.configService.getApiURL('printerprofiles'), + this.configService.getHTTPHeaders(), + ) + .pipe( + map(profiles => { + for (const [_, profile] of Object.entries(profiles.profiles)) { + if (profile.current) return profile; + } + }), + ); + } + + public executeGCode(gCode: string): void { + const gCodePayload: GCodeCommand = { + commands: gCode.split('; '), + }; + this.http + .post(this.configService.getApiURL('printer/command'), gCodePayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't send GCode!", error.message))) + .subscribe(); + } + + public jog(x: number, y: number, z: number): void { + const jogPayload: JogCommand = { + command: 'jog', + x, + y, + z, + speed: z !== 0 ? this.configService.getZSpeed() * 60 : this.configService.getXYSpeed() * 60, + }; + this.http + .post(this.configService.getApiURL('printer/printhead'), jogPayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't move Printhead!", error.message))) + .subscribe(); + } + + private moveExtruder(amount: number, speed: number): void { + const extrudePayload: ExtrudeCommand = { + command: 'extrude', + amount, + speed: speed * 60, + }; + this.http + .post(this.configService.getApiURL('printer/tool'), extrudePayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't extrude Filament!", error.message))) + .subscribe(); + } + + public setTemperatureHotend(temperature: number): void { + const temperatureHotendCommand: TemperatureHotendCommand = { + command: 'target', + targets: { + tool0: temperature, + }, + }; + this.http + .post(this.configService.getApiURL('printer/tool'), temperatureHotendCommand, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't set Hotend Temperature!", error.message))) + .subscribe(); + } + + public setTemperatureBed(temperature: number): void { + const temperatureHeatbedCommand: TemperatureHeatbedCommand = { + command: 'target', + target: temperature, + }; + this.http + .post(this.configService.getApiURL('printer/bed'), temperatureHeatbedCommand, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't set Bed Temperature!", error.message))) + .subscribe(); + } + + public setFeedrate(feedrate: number): void { + if (feedrate === 100) { + return; + } + const feedrateCommand: FeedrateCommand = { + command: 'feedrate', + factor: feedrate, + }; + this.http + .post(this.configService.getApiURL('printer/printhead'), feedrateCommand, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't set Feedrate!", error.message))) + .subscribe(); + } + + public setFlowrate(flowrate: number): void { + if (flowrate === 100) { + return; + } + const flowrateCommand: FeedrateCommand = { + command: 'flowrate', + factor: flowrate, + }; + this.http + .post(this.configService.getApiURL('printer/tool'), flowrateCommand, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't set Flowrate!", error.message))) + .subscribe(); + } + + public disconnectPrinter(): void { + const disconnectPayload: DisconnectCommand = { + command: 'disconnect', + }; + this.http + .post(this.configService.getApiURL('connection'), disconnectPayload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't disconnect Printer!", error.message))) + .subscribe(); + } + + public extrude(amount: number, speed: number): void { + let multiplier = 1; + let toBeExtruded: number; + if (amount < 0) { + multiplier = -1; + toBeExtruded = amount * -1; + } else { + toBeExtruded = amount; + } + + while (toBeExtruded > 0) { + if (toBeExtruded >= 100) { + toBeExtruded -= 100; + this.moveExtruder(100 * multiplier, speed); + } else { + this.moveExtruder(toBeExtruded * multiplier, speed); + toBeExtruded = 0; + } + } + } + + public emergencyStop(): void { + this.executeGCode('M410'); + } + + public setFanSpeed(percentage: number): void { + this.executeGCode('M106 S' + Math.round((percentage / 100) * 255)); + } +} diff --git a/src/app/services/printer/printer.service.ts b/src/app/services/printer/printer.service.ts new file mode 100644 index 000000000..386a6aa0b --- /dev/null +++ b/src/app/services/printer/printer.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { PrinterProfile } from '../../model'; + +@Injectable() +export abstract class PrinterService { + abstract getActiveProfile(): Observable; + + abstract executeGCode(gCode: string): void; + + abstract jog(x: number, y: number, z: number): void; + + abstract extrude(amount: number, speed: number): void; + + abstract setTemperatureHotend(temperature: number): void; + + abstract setTemperatureBed(temperature: number): void; + + abstract setFanSpeed(percentage: number): void; + + abstract setFeedrate(feedrate: number): void; + + abstract setFlowrate(flowrate: number): void; + + abstract disconnectPrinter(): void; + + abstract emergencyStop(): void; +} diff --git a/src/app/services/socket/socket.octoprint.service.ts b/src/app/services/socket/socket.octoprint.service.ts new file mode 100644 index 000000000..40342a7ab --- /dev/null +++ b/src/app/services/socket/socket.octoprint.service.ts @@ -0,0 +1,309 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import _ from 'lodash-es'; +import { Observable, ReplaySubject, Subject } from 'rxjs'; +import { pluck, startWith } from 'rxjs/operators'; +import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; + +import { ConfigService } from '../../config/config.service'; +import { ConversionService } from '../../conversion.service'; +import { JobStatus, PrinterEvent, PrinterState, PrinterStatus, SocketAuth } from '../../model'; +import { + DisplayLayerProgressData, + OctoprintFilament, + OctoprintPluginMessage, + OctoprintSocketCurrent, + OctoprintSocketEvent, +} from '../../model/octoprint'; +import { SystemService } from '../system/system.service'; +import { SocketService } from './socket.service'; + +@Injectable() +export class OctoPrintSocketService implements SocketService { + private fastInterval = 0; + private socket: WebSocketSubject; + + private printerStatusSubject: Subject; + private jobStatusSubject: Subject; + private eventSubject: Subject; + + private printerStatus: PrinterStatus; + private jobStatus: JobStatus; + private lastState: PrinterEvent; + + public constructor( + private configService: ConfigService, + private systemService: SystemService, + private conversionService: ConversionService, + private http: HttpClient, + ) { + this.printerStatusSubject = new ReplaySubject(); + this.jobStatusSubject = new ReplaySubject(); + this.eventSubject = new ReplaySubject(); + } + + //==== SETUP & AUTH ====// + + public connect(): Promise { + this.initPrinterStatus(); + this.initJobStatus(); + this.lastState = PrinterEvent.UNKNOWN; + + return new Promise(resolve => { + this.tryConnect(resolve); + }); + } + + private initPrinterStatus(): void { + this.printerStatus = { + status: PrinterState.connecting, + bed: { + current: 0, + set: 0, + unit: '°C', + }, + tool0: { + current: 0, + set: 0, + unit: '°C', + }, + fanSpeed: this.configService.isDisplayLayerProgressEnabled() ? 0 : -1, + } as PrinterStatus; + } + + private initJobStatus(): void { + this.jobStatus = { + file: null, + fullPath: null, + progress: 0, + zHeight: this.configService.isDisplayLayerProgressEnabled() ? { current: 0, total: -1 } : 0, + filamentAmount: 0, + timePrinted: null, + timeLeft: { + value: '---', + unit: null, + }, + estimatedPrintTime: null, + estimatedEndTime: null, + } as JobStatus; + } + + private tryConnect(resolve: () => void): void { + this.systemService.getSessionKey().subscribe( + socketAuth => { + this.connectSocket(); + this.setupSocket(resolve); + this.authenticateSocket(socketAuth); + }, + () => { + setTimeout(this.tryConnect.bind(this), this.fastInterval < 6 ? 5000 : 15000, resolve); + this.fastInterval += 1; + }, + ); + } + + private connectSocket() { + const url = `${this.configService.getApiURL('sockjs/websocket', false).replace(/^http/, 'ws')}`; + if (!this.socket) { + this.socket = webSocket(url); + } + } + + private authenticateSocket(socketAuth: SocketAuth) { + const payload = { + auth: `${socketAuth.user}:${socketAuth.session}`, + }; + this.socket.next(payload); + } + + private setupSocket(resolve: () => void) { + this.socket.subscribe(message => { + if (Object.hasOwnProperty.bind(message)('current')) { + this.extractPrinterStatus(message as OctoprintSocketCurrent); + this.extractJobStatus(message as OctoprintSocketCurrent); + } else if (Object.hasOwnProperty.bind(message)('event')) { + this.extractPrinterEvent(message as OctoprintSocketEvent); + } else if (Object.hasOwnProperty.bind(message)('plugin')) { + const pluginMessage = message as OctoprintPluginMessage; + if ( + pluginMessage.plugin.plugin === 'DisplayLayerProgress-websocket-payload' && + this.configService.isDisplayLayerProgressEnabled() + ) { + this.extractFanSpeed(pluginMessage.plugin.data as DisplayLayerProgressData); + this.extractLayerHeight(pluginMessage.plugin.data as DisplayLayerProgressData); + } + } else if (Object.hasOwnProperty.bind(message)('reauth')) { + this.systemService.getSessionKey().subscribe(socketAuth => this.authenticateSocket(socketAuth)); + } else if (Object.hasOwnProperty.bind(message)('connected')) { + resolve(); + this.checkPrinterConnection(); + } + }); + } + + private checkPrinterConnection() { + this.http + .get(this.configService.getApiURL('connection'), this.configService.getHTTPHeaders()) + .pipe(pluck('current'), pluck('state')) + .subscribe((state: string) => { + if (state === 'Closed' || state === 'Error') { + this.eventSubject.next(PrinterEvent.CLOSED); + } + }); + } + + //==== Printer Status ====// + + public extractPrinterStatus(message: OctoprintSocketCurrent): void { + if (message.current.temps[0]) { + this.printerStatus.bed = { + current: Math.round(message?.current?.temps[0]?.bed?.actual), + set: Math.round(message?.current?.temps[0]?.bed?.target), + unit: '°C', + }; + this.printerStatus.tool0 = { + current: Math.round(message?.current?.temps[0]?.tool0?.actual), + set: Math.round(message?.current?.temps[0]?.tool0?.target), + unit: '°C', + }; + } + this.printerStatus.status = PrinterState[message.current.state.text.toLowerCase()]; + + if (this.printerStatus.status === PrinterState.printing && this.lastState === PrinterEvent.UNKNOWN) { + this.extractPrinterEvent({ + event: { + type: 'PrintStarted', + payload: null, + }, + } as OctoprintSocketEvent); + } else if (this.printerStatus.status === PrinterState.paused && this.lastState === PrinterEvent.UNKNOWN) { + this.extractPrinterEvent({ + event: { + type: 'PrintPaused', + payload: null, + }, + } as OctoprintSocketEvent); + } + + this.printerStatusSubject.next(this.printerStatus); + } + + public extractFanSpeed(message: DisplayLayerProgressData): void { + this.printerStatus.fanSpeed = + message.fanspeed === 'Off' ? 0 : message.fanspeed === '-' ? 0 : Number(message.fanspeed.replace('%', '').trim()); + } + + //==== Job Status ====// + + public extractJobStatus(message: OctoprintSocketCurrent): void { + const file = message?.current?.job?.file?.display?.replace('.gcode', '').replace('.ufp', ''); + if (this.jobStatus.file !== file) { + this.initJobStatus(); + } + + this.jobStatus.file = file; + this.jobStatus.fullPath = '/' + message?.current?.job?.file?.origin + '/' + message?.current?.job?.file?.path; + this.jobStatus.progress = Math.round(message?.current?.progress?.completion); + this.jobStatus.timePrinted = { + value: this.conversionService.convertSecondsToHours(message.current.progress.printTime), + unit: 'h', + }; + + if (message.current.job.filament) { + this.jobStatus.filamentAmount = this.getTotalFilamentWeight(message.current.job.filament); + } + + if (message.current.progress.printTimeLeft) { + this.jobStatus.timeLeft = { + value: this.conversionService.convertSecondsToHours(message.current.progress.printTimeLeft), + unit: 'h', + }; + this.jobStatus.estimatedEndTime = this.calculateEndTime(message.current.progress.printTimeLeft); + } + + if (message.current.job.estimatedPrintTime) { + this.jobStatus.estimatedPrintTime = { + value: this.conversionService.convertSecondsToHours(message.current.job.estimatedPrintTime), + unit: 'h', + }; + } + + if (!this.configService.isDisplayLayerProgressEnabled() && message.current.currentZ) { + this.jobStatus.zHeight = message.current.currentZ; + } + + this.jobStatusSubject.next(this.jobStatus); + } + + private getTotalFilamentWeight(filament: OctoprintFilament) { + let filamentLength = 0; + _.forEach(filament, (tool): void => { + filamentLength += tool.length; + }); + return this.conversionService.convertFilamentLengthToWeight(filamentLength); + } + + private calculateEndTime(printTimeLeft: number) { + const date = new Date(); + date.setSeconds(date.getSeconds() + printTimeLeft); + return `${('0' + date.getHours()).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`; + } + + public extractLayerHeight(message: DisplayLayerProgressData): void { + this.jobStatus.zHeight = { + current: message.currentLayer === '-' ? 0 : Number(message.currentLayer), + total: message.totalLayer === '-' ? 0 : Number(message.totalLayer), + }; + } + + //==== Event ====// + + public extractPrinterEvent(state: OctoprintSocketEvent): void { + let newState: PrinterEvent; + + switch (state.event.type) { + case 'PrintStarted': + case 'PrintResumed': + newState = PrinterEvent.PRINTING; + break; + case 'PrintPaused': + newState = PrinterEvent.PAUSED; + break; + case 'PrintFailed': + case 'PrintDone': + case 'PrintCancelled': + newState = PrinterEvent.IDLE; + break; + case 'Connected': + newState = PrinterEvent.CONNECTED; + break; + case 'Disconnected': + newState = PrinterEvent.CLOSED; + break; + case 'Error': + newState = PrinterEvent.CLOSED; + break; + default: + break; + } + + if (newState !== undefined) { + this.lastState = newState; + this.eventSubject.next(newState); + } + } + + //==== Subscribables ====// + + public getPrinterStatusSubscribable(): Observable { + return this.printerStatusSubject.pipe(startWith(this.printerStatus)); + } + + public getJobStatusSubscribable(): Observable { + return this.jobStatusSubject.pipe(startWith(this.jobStatus)); + } + + public getEventSubscribable(): Observable { + return this.eventSubject; + } +} diff --git a/src/app/services/socket/socket.service.ts b/src/app/services/socket/socket.service.ts new file mode 100644 index 000000000..259fa5ceb --- /dev/null +++ b/src/app/services/socket/socket.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { JobStatus, PrinterEvent, PrinterStatus } from '../../model'; + +@Injectable() +export abstract class SocketService { + abstract connect(): Promise; + + abstract getPrinterStatusSubscribable(): Observable; + + abstract getJobStatusSubscribable(): Observable; + + abstract getEventSubscribable(): Observable; +} diff --git a/src/app/services/system/system.octoprint.service.ts b/src/app/services/system/system.octoprint.service.ts new file mode 100644 index 000000000..6e6d68b8a --- /dev/null +++ b/src/app/services/system/system.octoprint.service.ts @@ -0,0 +1,56 @@ +/* eslint-disable camelcase */ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { ConfigService } from '../../config/config.service'; +import { SocketAuth } from '../../model'; +import { ConnectCommand, OctoprintLogin } from '../../model/octoprint'; +import { NotificationService } from '../../notification/notification.service'; +import { SystemService } from './system.service'; + +@Injectable() +export class SystemOctoprintService implements SystemService { + constructor( + private configService: ConfigService, + private notificationService: NotificationService, + private http: HttpClient, + ) {} + + public getSessionKey(): Observable { + return this.http + .post( + this.configService.getApiURL('login'), + { passive: true }, + this.configService.getHTTPHeaders(), + ) + .pipe( + map(octoprintLogin => { + return { + user: octoprintLogin.name, + session: octoprintLogin.session, + } as SocketAuth; + }), + ); + } + + public sendCommand(command: string): void { + this.http + .post(this.configService.getApiURL(`system/commands/core/${command}`), null, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError(`Can't execute ${command} command!`, error.message))) + .subscribe(); + } + + public connectPrinter(): void { + const payload: ConnectCommand = { + command: 'connect', + save: false, + }; + + this.http + .post(this.configService.getApiURL('connection'), payload, this.configService.getHTTPHeaders()) + .pipe(catchError(error => this.notificationService.setError("Can't connect to printer!", error.message))) + .subscribe(); + } +} diff --git a/src/app/services/system/system.service.ts b/src/app/services/system/system.service.ts new file mode 100644 index 000000000..c449cf24e --- /dev/null +++ b/src/app/services/system/system.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { SocketAuth } from '../../model'; + +@Injectable() +export abstract class SystemService { + abstract getSessionKey(): Observable; + + abstract sendCommand(command: string): void; + + abstract connectPrinter(): void; +} diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index b59e6156e..22a7e2939 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -310,15 +310,21 @@
@@ -494,12 +500,12 @@
Display Layer Progress -
+
- + enabled
@@ -598,7 +604,7 @@
- v{{ service.version }} + v{{ service.getVersion() }} diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts index 028fb0c1b..aa5702de7 100644 --- a/src/app/settings/settings.component.ts +++ b/src/app/settings/settings.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { ElectronService } from 'ngx-electron'; import { AppService } from '../app.service'; @@ -11,7 +11,7 @@ import { NotificationService } from '../notification/notification.service'; templateUrl: './settings.component.html', styleUrls: ['./settings.component.scss'], }) -export class SettingsComponent implements OnInit { +export class SettingsComponent implements OnInit, OnDestroy { @Output() closeFunction = new EventEmitter(); @ViewChild('settingsMain') private settingsMain: ElementRef; @ViewChild('settingsGeneral') private settingsGeneral: ElementRef; @@ -55,6 +55,11 @@ export class SettingsComponent implements OnInit { }, 400); } + public ngOnDestroy(): void { + this.electronService.ipcRenderer.removeListener('configSaved', this.onConfigSaved.bind(this)); + this.electronService.ipcRenderer.removeListener('configSaveFail', this.onConfigSaveFail.bind(this)); + } + public hideSettings(): void { if ( this.configService.isEqualToCurrentConfig(this.configService.createConfigFromInput(this.config)) || @@ -88,11 +93,18 @@ export class SettingsComponent implements OnInit { public updateConfig(): void { const config = this.configService.createConfigFromInput(this.config); - if (!this.configService.validateGiven(config)) { - this.notificationService.setError('Config is invalid!', this.configService.getErrors().toString()); - } + + this.electronService.ipcRenderer.on('configSaved', this.onConfigSaved.bind(this)); + this.electronService.ipcRenderer.on('configSaveFail', this.onConfigSaveFail.bind(this)); + this.configService.saveConfig(config); - this.overwriteNoSave = true; + } + + private onConfigSaveFail(_, errors: string[]) { + this.notificationService.setWarning("Can't save invalid config", String(errors)); + } + + private onConfigSaved() { this.hideSettings(); this.electronService.ipcRenderer.send('reload'); } diff --git a/src/app/standby/standby.component.html b/src/app/standby/standby.component.html index b58f751f7..c54313d3e 100644 --- a/src/app/standby/standby.component.html +++ b/src/app/standby/standby.component.html @@ -1,11 +1,19 @@
- + Shhh! OctoDash is sleeping. Press on the screen to wake me up again. - sleeping ... + + sleeping ... + + + connecting + Connection can't be established. Press screen to try again. +
@@ -25,10 +33,3 @@
- -
- {{ error }} - tap this card to close it -
- -
connecting
diff --git a/src/app/standby/standby.component.ts b/src/app/standby/standby.component.ts index 508b3f201..0d1f63607 100644 --- a/src/app/standby/standby.component.ts +++ b/src/app/standby/standby.component.ts @@ -1,144 +1,67 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; +import { Component, OnDestroy, OnInit } from '@angular/core'; -import { OctoprintConnection } from '.././octoprint/model/connection'; import { AppService } from '../app.service'; import { ConfigService } from '../config/config.service'; -import { NotificationService } from '../notification/notification.service'; -import { PsuControlService } from '../plugins/psu-control.service'; -import { TPLinkSmartPlugService } from '../plugins/tplink-smartplug.service'; +import { PSUState } from '../model'; +import { EnclosureService } from '../services/enclosure/enclosure.service'; +import { SystemService } from '../services/system/system.service'; @Component({ selector: 'app-standby', templateUrl: './standby.component.html', styleUrls: ['./standby.component.scss'], }) -export class StandbyComponent implements OnInit { +export class StandbyComponent implements OnInit, OnDestroy { public connecting = false; - public error = ''; public actionsVisible = false; - private connectionRetries = 3; + public showConnectionError = false; private displaySleepTimeout: ReturnType; + private connectErrorTimeout: ReturnType; public constructor( private configService: ConfigService, - private http: HttpClient, - private router: Router, private service: AppService, - private notificationService: NotificationService, - private psuControlService: PsuControlService, - private tpLinkSmartPlugService: TPLinkSmartPlugService, + private enclosureService: EnclosureService, + private systemService: SystemService, ) {} public ngOnInit(): void { - this.notificationService.disableNotifications(); if (this.configService.getAutomaticScreenSleep()) { this.displaySleepTimeout = setTimeout(this.service.turnDisplayOff.bind(this.service), 300000); } } + public ngOnDestroy(): void { + clearTimeout(this.displaySleepTimeout); + clearTimeout(this.connectErrorTimeout); + if (this.configService.getAutomaticScreenSleep()) { + this.service.turnDisplayOn(); + } + } + public reconnect(): void { + this.actionsVisible = false; this.connecting = true; if (this.configService.getAutomaticPrinterPowerOn()) { - if (this.configService.useTpLinkSmartPlug()) { - this.tpLinkSmartPlugService.changePowerState(true); - } else { - this.psuControlService.changePSUState(true); - } - setTimeout(this.checkConnection.bind(this), 5000); + this.enclosureService.setPSUState(PSUState.ON); + setTimeout(this.connectPrinter.bind(this), 5000); } else { - this.checkConnection(); + this.connectPrinter(); } } - private connectToPrinter(): void { - this.http - .post(this.configService.getURL('connection'), connectPayload, this.configService.getHTTPHeaders()) - .subscribe( - (): void => { - setTimeout(this.checkConnection.bind(this), 5000); - }, - (): void => { - this.setConnectionError(); - }, - ); - } - - private checkConnection(): void { - this.http.get(this.configService.getURL('connection'), this.configService.getHTTPHeaders()).subscribe( - (data: OctoprintConnection): void => { - if (data.current.state === 'Closed') { - if (this.connectionRetries <= 0) { - this.connectionRetries = 3; - this.setConnectionError(); - } else { - this.connectionRetries--; - setTimeout(this.connectToPrinter.bind(this), 500); - } - } else if (data.current.state.includes('Error')) { - if (this.connectionRetries <= 1) { - this.connectionRetries = 3; - this.setConnectionError(); - } else { - this.connectionRetries--; - setTimeout(this.connectToPrinter.bind(this), 500); - } - } else if (data.current.state === 'Connecting') { - if (this.connectionRetries < 0) { - this.connectionRetries = 3; - this.setConnectionError(); - } else { - this.connectionRetries--; - setTimeout(this.checkConnection.bind(this), 5000); - } - } else { - this.disableStandby(); - } - }, - (): void => { + private connectPrinter(): void { + this.systemService.connectPrinter(); + this.connectErrorTimeout = setTimeout(() => { + this.showConnectionError = true; + this.connectErrorTimeout = setTimeout(() => { + this.showConnectionError = false; this.connecting = false; - this.error = - "There is something really wrong, OctoDash can't get a response from OctoPrint. Please check your setup!"; - }, - ); - } - - private setConnectionError(): void { - this.connecting = false; - this.error = - "OctoPrint can't connect to your printer. Please make sure that the connection works, then come back and try again."; - } - - private disableStandby(): void { - if (this.configService.getAutomaticScreenSleep()) { - if (this.displaySleepTimeout) { - clearTimeout(this.displaySleepTimeout); - } - this.service.turnDisplayOn(); - } - setTimeout((): void => { - this.connecting = false; - this.notificationService.enableNotifications(); - this.router.navigate(['/main-screen']); - }, 1000); + }, 30000); + }, 15000); } public toggleCustomActions(): void { this.actionsVisible = !this.actionsVisible; } } - -const connectPayload: ConnectCommand = { - command: 'connect', - save: false, -}; - -interface ConnectCommand { - command: string; - port?: string; - baudrate?: number; - printerProfile?: string; - save?: boolean; - autoconnect?: boolean; -} diff --git a/src/app/update/update.component.ts b/src/app/update/update.component.ts index 3e4801c61..c7a147b8e 100644 --- a/src/app/update/update.component.ts +++ b/src/app/update/update.component.ts @@ -2,8 +2,9 @@ import { Component, EventEmitter, NgZone, OnInit, Output } from '@angular/core'; import { ElectronService } from 'ngx-electron'; import { AppService } from '../app.service'; +import { UpdateDownloadProgress, UpdateError } from '../model'; import { NotificationService } from '../notification/notification.service'; -import { OctoprintService } from '../octoprint.service'; +import { SystemService } from '../services/system/system.service'; @Component({ selector: 'app-update', @@ -29,13 +30,13 @@ export class UpdateComponent implements OnInit { constructor( public service: AppService, private notificationService: NotificationService, - private octoprintService: OctoprintService, + private systemService: SystemService, private zone: NgZone, private electronService: ElectronService, ) {} ngOnInit(): void { - if (!this.service.latestVersion || !this.service.getLatestVersionAssetsURL()) { + if (!this.service.getLatestVersion() || !this.service.getLatestVersionAssetsURL()) { this.notificationService.setWarning( "Can't initiate update!", 'Some information is missing, please try again in an hour or update manually.', @@ -95,24 +96,6 @@ export class UpdateComponent implements OnInit { } public reboot(): void { - this.octoprintService.sendSystemCommand('reboot'); + this.systemService.sendCommand('reboot'); } } - -interface UpdateError { - error: { - message: string; - stack?: string; - }; -} - -interface UpdateDownloadProgress { - percentage: number; - transferred: number; - total: number | string; - remaining: number; - eta: string; - runtime: string; - delta: number; - speed: number | string; -} diff --git a/src/assets/checkmark.json b/src/assets/checkmark.json new file mode 100644 index 000000000..4552c0ed1 --- /dev/null +++ b/src/assets/checkmark.json @@ -0,0 +1 @@ +{"ip":0,"fr":60,"v":"5.1.20","assets":[{"id":"precomp_1","layers":[{"ty":4,"nm":"check-mark","ip":0,"st":0,"ind":10,"hix":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[16.5,12,0]},"p":{"s":true,"x":{"a":0,"k":67.2080078125},"y":{"a":0,"k":64.622}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[14.6,14.6],"e":[96,96],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":24}]}},"shapes":[{"ty":"gr","nm":"check-mark shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[18,25.6129791],[15.1715729,28.4414062],[27.0334473,40.3032806],[47.3367279,20],[44.5083008,17.1715729],[27.0334473,34.6464264]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":1,"c":{"a":0,"k":[0.9607843137254902,0.9647058823529412,0.9803921568627451,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-15,-17]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"check-circle","ip":0,"st":0,"ind":9,"hix":10,"ks":{"o":{"a":0,"k":100},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[26.5,26.5,0]},"p":{"s":true,"x":{"a":0,"k":67.48},"y":{"a":0,"k":63.6215}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[0,0],"e":[100,100],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":24}]}},"shapes":[{"ty":"gr","nm":"check-circle shape group","it":[{"ty":"el","p":{"a":0,"k":[31,30]},"s":{"a":0,"k":[53,53]}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":1,"c":{"a":0,"k":[0.11764705882352941,0.7529411764705882,0.17254901960784313,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-5,-4]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-7","ip":0,"st":0,"ind":8,"hix":3,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[5,5,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[36.61257896015442],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79149999999998],"e":[25.164413837697136],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[-84.05290854569176],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"s":{"a":1,"k":[{"t":0,"s":[117,117],"e":[79.9,79.9],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-7 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[40.9496385,16.0000907],[39.9661291,16.419252],[36.4147663,19.9778517],[36.4147663,21.9882313],[39.9661291,25.5465463],[41.9724881,25.5465463],[45.5238511,21.9882313],[45.5238511,19.9778517],[41.9724881,16.419252],[40.9496385,16.0000907]],"i":[[0,0],[0.2608819999999952,-0.26267719999999883],[0,0],[-0.5530216999999951,-0.5555740999999976],[0,0],[-0.5544639000000018,0.5541249000000015],[0,0],[0.5530217999999962,0.5555742000000023],[0,0],[0.3834356999999997,-0.0043338000000012755]],"o":[[-0.36979209999999796,0.0061093999999997095],[0,0],[-0.5530216999999951,0.5555742000000023],[0,0],[0.5544638999999947,0.5541249000000015],[0,0],[0.5530217999999962,-0.5555740999999976],[0,0],[-0.27051540000000074,-0.27232139999999916],[0,0]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[40.9710977,19.4365299],[42.5125251,20.9810482],[40.9710977,22.5292683],[39.4260938,20.9810482],[40.9710977,19.4365299]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.592156862745098,0.6470588235294118,0.6666666666666666,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-36,-16]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-6","ip":0,"st":0,"ind":7,"hix":4,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6,6.5,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[99.17026711099871],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79150000000001],"e":[104.04103087693385],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[-516.7506354284895],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"s":{"a":1,"k":[{"t":0,"s":[117,117],"e":[64,64],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-6 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[11.9020922,24.0001107],[10.7293271,24.5120512],[6.4945794,28.8583278],[6.4945794,31.3136941],[10.7293271,35.659623],[13.1217678,35.659623],[17.3565158,31.3136941],[17.3565158,28.8583278],[13.1217678,24.5120512],[11.9020922,24.0001107]],"i":[[0,0],[0.31108329999999995,-0.32081939999999776],[0,0],[-0.6594392000000004,-0.6785475000000005],[0,0],[-0.6611589000000002,0.6767775],[0,0],[0.6594392000000013,0.678547499999997],[0,0],[0.45721979999999895,-0.0052930000000017685]],"o":[[-0.44095079999999953,0.0074617999999979645],[0,0],[-0.6594392000000004,0.678547499999997],[0,0],[0.6611588999999984,0.6767775],[0,0],[0.6594392000000013,-0.6785475000000005],[0,0],[-0.3225705000000012,-0.33259829999999724],[0,0]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[11.9276808,28.1971874],[13.7657234,30.0835765],[11.9276808,31.9744868],[10.0853735,30.0835765],[11.9276808,28.1971874]],"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.592156862745098,0.6470588235294118,0.6666666666666666,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-6,-24]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-5","ip":0,"st":0,"ind":6,"hix":5,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[5.5,5.5,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[113.00048828125],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79150000000001],"e":[57.709001953125],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[117,117],"e":[57.4,57.4],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-5 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[19.0790408,6],[14,11.2146038],[19.0790408,16.4290338],[24.1580816,11.2146038],[19.0790408,6]],"i":[[0,0],[0,-2.8595036400000016],[-2.7850236000000024,0],[0,2.8591559999999987],[2.785023599999999,0]],"o":[[-2.7850236000000024,0],[0,2.8591559999999987],[2.785023599999999,0],[0,-2.8595036400000016],[0,0]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[19.0790408,9.47622868],[20.7720538,11.2146038],[19.0790408,12.9526312],[17.3860278,11.2146038],[19.0790408,9.47622868]],"i":[[0,0],[0,-0.9806397000000011],[0.9550780000000003,0],[0,0.9806396999999993],[-0.9550780000000003,0]],"o":[[0.9550780000000003,0],[0,0.9806396999999993],[-0.9550780000000003,0],[0,-0.9806397000000011],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.592156862745098,0.6470588235294118,0.6666666666666666,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-14,-6]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-4","ip":0,"st":0,"ind":5,"hix":6,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[5.5,5.5,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[17.159],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79150000000001],"e":[56.846],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[117,117],"e":[39.5,39.5],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-4 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[27.0790408,13],[22,18.2146038],[27.0790408,23.4290338],[32.1580816,18.2146038],[27.0790408,13]],"i":[[0,0],[0,-2.8595035999999983],[-2.7850236000000024,0],[0,2.8591560000000023],[2.785023599999999,0]],"o":[[-2.7850236000000024,0],[0,2.8591560000000023],[2.785023599999999,0],[0,-2.8595035999999983],[0,0]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[27.0790408,16.4762287],[28.7720538,18.2146038],[27.0790408,19.9526312],[25.3860278,18.2146038],[27.0790408,16.4762287]],"i":[[0,0],[0,-0.9806396999999976],[0.9550780000000003,0],[0,0.9806397000000011],[-0.9550780000000003,0]],"o":[[0.9550780000000003,0],[0,0.9806397000000011],[-0.9550780000000003,0],[0,-0.9806396999999976],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[0.592156862745098,0.6470588235294118,0.6666666666666666,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-22,-13]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-3","ip":0,"st":0,"ind":4,"hix":7,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6,6,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[67.18799999999997],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24,"s":[67.18799999999997],"e":[30.21184837966107],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79150000000001],"e":[67.79150000000001],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24,"s":[67.79150000000001],"e":[91.65618836257104],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[-382.793102926903],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"s":{"a":1,"k":[{"t":0,"s":[117,117],"e":[61.6,62.1],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-3 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[27.1820633,24.0000004],[26.1024778,24.4903764],[25.7680091,25.6242639],[25.771292,25.64133],[26.1581565,28.178913],[23.6101894,27.7937886],[23.5935177,27.7937886],[22.017544,28.9849731],[23.1499568,30.6007311],[23.1666284,30.6007311],[23.2133177,30.6007311],[25.707924,31.0091791],[24.607363,33.1981875],[24.5506679,33.3048505],[24.5439593,33.3219166],[25.1703749,35.2298051],[27.0885934,34.6141028],[27.095302,34.5970367],[28.2792385,32.3184314],[29.9867771,33.9958843],[30.113499,34.1224577],[30.1267736,34.1366794],[32.1116608,34.103824],[32.1444698,32.1268647],[32.1311952,32.112643],[30.3202693,30.289133],[32.4146709,29.2095616],[32.6114396,29.1100095],[32.6114396,29.1100095],[32.6247142,29.1100095],[33.2020743,27.2210442],[31.3273846,26.5788263],[31.31411,26.5788263],[31.3108271,26.5788263],[29.0096538,27.7314974],[28.5994433,25.2434061],[28.5927346,25.1964744],[28.5894517,25.1794083],[27.1820662,24.0001426]],"i":[[0,0],[0.27138360000000006,-0.3117266999999977],[-0.058965700000001675,-0.4083943999999988],[0,0],[0,0],[0,0],[0,0],[0.11915249999999844,-0.7540207000000017],[-0.7517145999999997,-0.1485365999999999],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.7005520999999995,-0.3557460999999975],[-0.3601826000000017,0.6962165000000056],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.5444561000000014,0.5423294999999939],[0.5261629999999968,0.5599553999999998],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.3494458999999992,0.6817940999999976],[0.6965846000000049,-0.3234522999999996],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6947289999999988,-0.0003607999999992728]],"o":[[-0.4142507999999978,-0.0002936000000026695],[-0.2713834999999989,0.31172670000000124],[0,0],[0,0],[0,0],[0,0],[-0.7611813000000005,-0.08862889999999979],[-0.11915250000000199,0.7540206000000005],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.35415740000000184,0.6992761999999999],[0.7005520000000018,0.3557460999999975],[0,0],[0,0],[0,0],[0,0],[0,0],[0.5622490000000013,0.5240104000000017],[0.5444561999999991,-0.5423293999999999],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6715985000000018,-0.3722019000000003],[-0.3494458999999992,-0.681794],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.11853729999999985,-0.6818066999999992],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[1,0.4470588235294118,0.3568627450980392,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-22,-24]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-1","ip":0,"st":0,"ind":3,"hix":9,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6,6,0]},"p":{"s":true,"x":{"a":0,"k":0},"y":{"a":0,"k":0}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":-128.3425461093044},"s":{"a":0,"k":[0,100]}},"shapes":[{"ty":"gr","nm":"sparkles-1 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[5.18206331,10.0000004],[4.10247785,10.4903764],[3.7680091,11.6242639],[3.77129205,11.64133],[4.15815646,14.178913],[1.61018942,13.7937886],[1.59351774,13.7937886],[0.0175440154,14.9849731],[1.14995675,16.6007311],[1.16662844,16.6007311],[1.21331771,16.6007311],[3.70792395,17.0091791],[2.60736305,19.1981875],[2.55066791,19.3048505],[2.54395927,19.3219166],[3.17037487,21.2298051],[5.0885934,20.6141028],[5.09530204,20.5970367],[6.27923849,18.3184314],[7.98677712,19.9958843],[8.11349905,20.1224577],[8.12677359,20.1366794],[10.1116608,20.103824],[10.1444698,18.1268647],[10.1311952,18.112643],[8.32026931,16.289133],[10.4146709,15.2095616],[10.6114396,15.1100095],[10.6114396,15.1100095],[10.6247142,15.1100095],[11.2020743,13.2210442],[9.32738457,12.5788263],[9.31411003,12.5788263],[9.31082708,12.5788263],[7.00965376,13.7314974],[6.59944329,11.2434061],[6.59273465,11.1964744],[6.58945169,11.1794083],[5.18206616,10.0001426]],"i":[[0,0],[0.2713835800000002,-0.31172670000000124],[-0.05896568000000002,-0.4083944000000006],[0,0],[0,0],[0,0],[0,0],[0.1191524706,-0.7540206999999999],[-0.7517145510000001,-0.1485365999999999],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.7005520199999999,-0.35574610000000106],[-0.3601825700000001,0.6962164999999985],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.5444561399999994,0.542329500000001],[0.5261630000000004,0.5599553999999998],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.349445900000001,0.6817941000000012],[0.6965846300000003,-0.3234522999999996],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6947290800000001,-0.00036077999999939436]],"o":[[-0.4142508100000004,-0.00029361999999899524],[-0.27138357999999974,0.31172669999999947],[0,0],[0,0],[0,0],[0,0],[-0.761181344,-0.08862889999999979],[-0.1191524714,0.7540206000000005],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.35415734000000043,0.6992761999999999],[0.7005520199999999,0.35574610000000106],[0,0],[0,0],[0,0],[0,0],[0,0],[0.5622489599999998,0.5240104000000017],[0.5444562000000008,-0.5423293999999999],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6715985,-0.3722019000000003],[-0.3494458999999992,-0.681794],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.11853725000000015,-0.681806700000001],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[1,0.4470588235294118,0.3568627450980392,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[0,-10]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"sparkles-2","ip":0,"st":0,"ind":2,"hix":8,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[6,6,0]},"p":{"s":true,"x":{"a":1,"k":[{"t":0,"s":[67.18799999999997],"e":[67.18799999999997],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":24,"s":[67.18799999999997],"e":[96.7589111328125],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"y":{"a":1,"k":[{"t":0,"s":[67.79150000000001],"e":[67.79150000000001],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":24,"s":[67.79150000000001],"e":[20.89849853515625],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":24,"s":[0],"e":[611.8616294202061],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":42}]},"s":{"a":1,"k":[{"t":0,"s":[0,0],"e":[100,100],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":23,"s":[100,100],"e":[100,100],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":42}]}},"shapes":[{"ty":"gr","nm":"sparkles-2 shape group","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"v":[[29.1820633,3.60685727e-7],[28.1024778,0.490376402],[27.7680091,1.62426394],[27.771292,1.64133002],[28.1581565,4.17891299],[25.6101894,3.79378859],[25.5935177,3.79378859],[24.017544,4.98497307],[25.1499568,6.60073109],[25.1666284,6.60073109],[25.2133177,6.60073109],[27.707924,7.00917913],[26.607363,9.19818754],[26.5506679,9.3048505],[26.5439593,9.32191657],[27.1703749,11.2298051],[29.0885934,10.6141028],[29.095302,10.5970367],[30.2792385,8.31843143],[31.9867771,9.99588427],[32.113499,10.1224577],[32.1267736,10.1366794],[34.1116608,10.103824],[34.1444698,8.12686475],[34.1311952,8.11264302],[32.3202693,6.28913302],[34.4146709,5.20956163],[34.6114396,5.11000954],[34.6114396,5.11000954],[34.6247142,5.11000954],[35.2020743,3.22104421],[33.3273846,2.57882634],[33.31411,2.57882634],[33.3108271,2.57882634],[31.0096538,3.73149742],[30.5994433,1.24340606],[30.5927346,1.19647436],[30.5894517,1.17940828],[29.1820662,0.000142577969]],"i":[[0,0],[0.27138360000000006,-0.311726712],[-0.058965700000001675,-0.40839440000000016],[0,0],[0,0],[0,0],[0,0],[0.11915249999999844,-0.7540206399999994],[-0.7517145999999997,-0.1485365500000002],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.7005520999999995,-0.3557460999999993],[-0.3601826000000017,0.6962165000000002],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.544456100000005,0.542329500000001],[0.5261629999999968,0.559955350000001],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.3494458999999992,0.6817940499999997],[0.6965846000000013,-0.32345235000000017],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6947289999999988,-0.000360758155]],"o":[[-0.4142507999999978,-0.000293583593727],[-0.2713834999999989,0.311726712],[0,0],[0,0],[0,0],[0,0],[-0.7611813000000005,-0.08862885000000009],[-0.11915250000000199,0.7540206400000002],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.35415740000000184,0.6992762299999988],[0.7005520000000018,0.3557460999999993],[0,0],[0,0],[0,0],[0,0],[0,0],[0.5622490000000013,0.5240103999999999],[0.5444561999999991,-0.5423294199999997],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.6715985000000018,-0.3722019300000001],[-0.3494458999999992,-0.6817940600000001],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.11853729999999985,-0.681806651],[0,0]]}}},{"ty":"st","o":{"a":0,"k":0},"w":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":100},"r":2,"c":{"a":0,"k":[1,0.4470588235294118,0.3568627450980392,1]}},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-24,0]},"r":{"a":0,"k":0}}]}],"op":42},{"ty":4,"nm":"ring-01","ip":0,"st":0,"ind":1,"hix":2,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[0],"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"t":8,"s":[0],"e":[100],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":10,"s":[100],"e":[0],"i":{"x":[0.515],"y":[0.955]},"o":{"x":[0.455],"y":[0.03]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[26.5,26.5,0]},"p":{"s":true,"x":{"a":0,"k":67.48},"y":{"a":0,"k":64}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[100,100],"e":[100,100],"i":{"x":[0.515,0.515],"y":[0.955,0.955]},"o":{"x":[0.455,0.455],"y":[0.03,0.03]}},{"t":10,"s":[100,100],"e":[171.70000000000002,171.70000000000002],"i":{"x":[0.305,0.305],"y":[1.01,0.99]},"o":{"x":[0.015,0],"y":[1,1]}},{"t":24}]}},"shapes":[{"ty":"gr","nm":"ring-01 shape group","it":[{"ty":"el","p":{"a":0,"k":[31,30]},"s":{"a":0,"k":[51,51]}},{"ty":"st","o":{"a":0,"k":100},"w":{"a":1,"k":[{"t":0,"s":[4],"e":[2],"i":{"x":[0.515],"y":[0.885]},"o":{"x":[0.23],"y":[1.62]}},{"t":16}]},"c":{"a":0,"k":[0.11764705882352941,0.7529411764705882,0.17254901960784313,1]},"lc":3,"lj":1,"ml":1},{"ty":"fl","o":{"a":0,"k":0},"c":{"a":0,"k":[0,0,0,0]},"r":1},{"ty":"tr","o":{"a":0,"k":100},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"p":{"a":0,"k":[-5,-4]},"r":{"a":0,"k":0}}]}],"op":42}]}],"layers":[{"ty":0,"nm":"instance:precomp_1","refId":"precomp_1","ind":1,"ip":0,"st":0,"hix":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"e":[100],"i":{"x":[0.65],"y":[1.01]},"o":{"x":[0.23],"y":[1.62]}},{"t":24}]},"or":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[67.5,64,0]},"p":{"s":true,"x":{"a":0,"k":76.42950000000002},"y":{"a":0,"k":75.091}},"rx":{"a":0,"k":0},"ry":{"a":0,"k":0},"rz":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[111.9,111.9],"e":[100,100],"i":{"x":[0.65,0.65],"y":[1.01,1.01]},"o":{"x":[0.23,0.23],"y":[1.62,1.62]}},{"t":24}]}},"w":135,"h":128,"op":42}],"op":40,"w":153,"h":151} \ No newline at end of file diff --git a/src/assets/loading.json b/src/assets/loading.json new file mode 100644 index 000000000..cf188e5e1 --- /dev/null +++ b/src/assets/loading.json @@ -0,0 +1 @@ +{"v":"4.7.0","fr":30.0000305175781,"ip":0,"op":151.000153605143,"w":800,"h":600,"nm":"LEGO loader Lottie","ddd":0,"assets":[{"id":"comp_3","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"red 5","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":30,"s":[371.75,340.125,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":60,"s":[315.05,299.985,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[315.05,299.985,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[371.75,259.845,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[371.75,259.845,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[428.45,219.705,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":330,"s":[428.45,219.705,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":360,"s":[485.15,259.845,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":420,"s":[485.15,259.845,0],"e":[428.45,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":450,"s":[428.45,299.985,0],"e":[428.45,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":540.001,"s":[428.45,299.985,0],"e":[371.75,340.125,0],"to":[0,0,0],"ti":[0,0,0]},{"t":570.000579833984}]},"a":{"a":0,"k":[193.074,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[167.294,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.85,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[220.86,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[194.304,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.145,0.165,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[164.724,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.925,0.255,0.235,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.074,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[221.424,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":540.000549316406,"op":603.00061340332,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"orange 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[314.65,300.125,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[371.35,259.725,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[371.35,259.725,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[428.05,219.585,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":210,"s":[428.05,219.585,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":240,"s":[484.75,259.725,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":300,"s":[484.75,259.725,0],"e":[428.05,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":330,"s":[428.05,299.865,0],"e":[428.05,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":420,"s":[428.05,299.865,0],"e":[371.35,340.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":450,"s":[371.35,340.005,0],"e":[371.35,340.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":510.001,"s":[371.35,340.005,0],"e":[314.65,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":540.000549316406}]},"a":{"a":0,"k":[306.474,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[280.693,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.25,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.26,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.704,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.996,0.412,0.082,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[278.124,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,0.616,0.325,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[306.474,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.824,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":420.000427246094,"op":603.00061340332,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"yellow 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[371.55,260.125,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[428.25,219.725,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":90,"s":[428.25,219.725,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":120,"s":[484.95,259.865,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[484.95,259.865,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[428.25,300.005,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":300,"s":[428.25,300.005,0],"e":[371.55,340.145,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":330,"s":[371.55,340.145,0],"e":[371.55,340.145,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":390,"s":[371.55,340.145,0],"e":[314.85,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":420,"s":[314.85,300.005,0],"e":[314.85,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":480,"s":[314.85,300.005,0],"e":[371.55,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":510.000518798828}]},"a":{"a":0,"k":[419.874,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[394.094,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[420.65,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[447.66,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.331],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[421.104,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.89,0.184,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[391.524,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.699,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.922,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[419.874,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.349,40.14],[-28.349,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[448.224,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":300.000305175781,"op":480.00048828125,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"blue 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[485.35,259.875,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[428.65,300.015,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[428.65,300.015,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[371.95,340.415,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":270,"s":[371.95,340.415,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":300,"s":[315.25,300.275,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":360,"s":[315.25,300.275,0],"e":[371.95,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"t":390.000396728516}]},"a":{"a":0,"k":[646.674,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.619,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[620.894,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.849,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.45,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[674.46,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.904,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.31,0.678,0.808,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[618.324,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.392,0.827,0.953,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[646.674,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[675.024,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":180.000183105469,"op":360.000366210938,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"green 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[428.95,300.125,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[372.25,340.265,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":150,"s":[372.25,340.265,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":180,"s":[315.55,299.865,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[315.55,299.865,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"t":270.000274658203}]},"a":{"a":0,"k":[533.273,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[507.494,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.05,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.061,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.579,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.159,0]],"v":[[11.849,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.504,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.592,0.769,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[504.923,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.62,0.816,0.153,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[533.274,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.624,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":60.0000610351563,"op":240.000244140625,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"red","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":30,"s":[371.75,340.125,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":60,"s":[315.05,299.985,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[315.05,299.985,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"t":150.000152587891}]},"a":{"a":0,"k":[193.074,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[167.294,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.85,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[220.86,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[194.304,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.145,0.165,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[164.724,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.925,0.255,0.235,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.074,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[221.424,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":0,"op":120.000122070313,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"green","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[428.95,300.125,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90.0000915527344}]},"a":{"a":0,"k":[533.273,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[507.494,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.05,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.061,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.579,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.159,0]],"v":[[11.849,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.504,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.592,0.769,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[504.923,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.62,0.816,0.153,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[533.274,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.624,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":0,"op":60.0000610351563,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"blue","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":70,"s":[485.35,259.875,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[428.65,300.015,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[428.65,300.015,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"t":210.000213623047}]},"a":{"a":0,"k":[646.674,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.619,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[620.894,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.849,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.45,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[674.46,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.904,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.31,0.678,0.808,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[618.324,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.392,0.827,0.953,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[646.674,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[675.024,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":0,"op":180.000183105469,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"orange","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":10,"s":[314.65,300.125,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[371.35,259.725,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[371.35,259.725,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"t":150.000152587891}]},"a":{"a":0,"k":[306.474,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[280.693,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.25,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.26,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.704,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.996,0.412,0.082,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[278.124,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,0.616,0.325,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[306.474,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.824,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":0,"op":120.000122070313,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":4,"nm":"yellow","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[371.55,260.125,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[428.25,219.725,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":90,"s":[428.25,219.725,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":120,"s":[484.95,259.865,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":190,"s":[484.95,259.865,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[428.25,300.005,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":300,"s":[428.25,300.005,0],"e":[371.55,340.145,0],"to":[0,0,0],"ti":[0,0,0]},{"t":330.000335693359}]},"a":{"a":0,"k":[419.874,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[394.094,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[420.65,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[447.66,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.331],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[421.104,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.89,0.184,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[391.524,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.699,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.922,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[419.874,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.349,40.14],[-28.349,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[448.224,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":0,"op":300.000305175781,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":11,"ty":4,"nm":"orange 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[314.65,300.125,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[371.35,259.725,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[371.35,259.725,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[428.05,219.585,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":210,"s":[428.05,219.585,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":240,"s":[484.75,259.725,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":310,"s":[484.75,259.725,0],"e":[428.05,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":330,"s":[428.05,299.865,0],"e":[428.05,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":420,"s":[428.05,299.865,0],"e":[371.35,340.005,0],"to":[0,0,0],"ti":[0,0,0]},{"t":450.000457763672}]},"a":{"a":0,"k":[306.474,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[280.693,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.25,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.26,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.704,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.996,0.412,0.082,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[278.124,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,0.616,0.325,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[306.474,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.824,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":300.000305175781,"op":420.000427246094,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":12,"ty":4,"nm":"red 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":30,"s":[371.75,340.125,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":60,"s":[315.05,299.985,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[315.05,299.985,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[371.75,259.845,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[371.75,259.845,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[428.45,219.705,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":330,"s":[428.45,219.705,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":360,"s":[485.15,259.845,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":430,"s":[485.15,259.845,0],"e":[428.45,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":450,"s":[428.45,299.985,0],"e":[428.45,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":540.001,"s":[428.45,299.985,0],"e":[371.75,340.125,0],"to":[0,0,0],"ti":[0,0,0]},{"t":570.000579833984}]},"a":{"a":0,"k":[193.074,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[167.294,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.85,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[220.86,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[194.304,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.145,0.165,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[164.724,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.925,0.255,0.235,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.074,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[221.424,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":420.000427246094,"op":540.000549316406,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":13,"ty":4,"nm":"green 5","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[428.95,300.125,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[372.25,340.265,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":150,"s":[372.25,340.265,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":180,"s":[315.55,299.865,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[315.55,299.865,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[372.25,259.725,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":360,"s":[372.25,259.725,0],"e":[428.95,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":390,"s":[428.95,219.585,0],"e":[428.95,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":450,"s":[428.95,219.585,0],"e":[485.65,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":480,"s":[485.65,259.725,0],"e":[485.65,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":550.001,"s":[485.65,259.725,0],"e":[428.95,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":570.000579833984}]},"a":{"a":0,"k":[533.273,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[507.494,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.05,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.061,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.579,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.159,0]],"v":[[11.849,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.504,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.592,0.769,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[504.923,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.62,0.816,0.153,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[533.274,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.624,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":540.000549316406,"op":603.00061340332,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":14,"ty":4,"nm":"yellow 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[371.55,260.125,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[428.25,219.725,0],"e":[428.25,219.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":90,"s":[428.25,219.725,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":120,"s":[484.95,259.865,0],"e":[484.95,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[484.95,259.865,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[428.25,300.005,0],"e":[428.25,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":300,"s":[428.25,300.005,0],"e":[371.55,340.145,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":330,"s":[371.55,340.145,0],"e":[371.55,340.145,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":390,"s":[371.55,340.145,0],"e":[314.85,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":420,"s":[314.85,300.005,0],"e":[314.85,300.005,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":490,"s":[314.85,300.005,0],"e":[371.55,259.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":510.000518798828}]},"a":{"a":0,"k":[419.874,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[394.094,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[420.65,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[447.66,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.331],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[421.104,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.89,0.184,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[391.524,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.699,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.98,0.922,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[419.874,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.349,40.14],[-28.349,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.906,0.722,0.149,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[448.224,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":480.00048828125,"op":603.00061340332,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":15,"ty":4,"nm":"blue 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[485.35,259.875,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[428.65,300.015,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[428.65,300.015,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[371.95,340.415,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":270,"s":[371.95,340.415,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":300,"s":[315.25,300.275,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":370,"s":[315.25,300.275,0],"e":[371.95,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":390,"s":[371.95,260.135,0],"e":[371.95,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":480,"s":[371.95,260.135,0],"e":[428.65,219.995,0],"to":[0,0,0],"ti":[0,0,0]},{"t":510.000518798828}]},"a":{"a":0,"k":[646.674,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.619,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[620.894,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.849,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.45,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[674.46,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.904,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.31,0.678,0.808,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[618.324,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.392,0.827,0.953,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[646.674,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[675.024,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":360.000366210938,"op":480.00048828125,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":16,"ty":4,"nm":"green 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[428.95,300.125,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[372.25,340.265,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":150,"s":[372.25,340.265,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":180,"s":[315.55,299.865,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":250,"s":[315.55,299.865,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[372.25,259.725,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":360,"s":[372.25,259.725,0],"e":[428.95,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"t":390.000396728516}]},"a":{"a":0,"k":[533.273,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[507.494,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.05,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.061,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.579,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.159,0]],"v":[[11.849,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.504,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.592,0.769,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[504.923,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.62,0.816,0.153,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[533.274,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.624,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":240.000244140625,"op":360.000366210938,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":17,"ty":4,"nm":"red 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":30,"s":[371.75,340.125,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":60,"s":[315.05,299.985,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":130,"s":[315.05,299.985,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[371.75,259.845,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[371.75,259.845,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"t":270.000274658203}]},"a":{"a":0,"k":[193.074,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[167.294,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.85,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[220.86,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[194.304,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.145,0.165,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[164.724,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.925,0.255,0.235,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.074,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[221.424,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":120.000122070313,"op":240.000244140625,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":18,"ty":4,"nm":"orange 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":0,"s":[314.65,300.125,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":30,"s":[371.35,259.725,0],"e":[371.35,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[371.35,259.725,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[428.05,219.585,0],"e":[428.05,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":210,"s":[428.05,219.585,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":240,"s":[484.75,259.725,0],"e":[484.75,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":300,"s":[484.75,259.725,0],"e":[428.05,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":330.000335693359}]},"a":{"a":0,"k":[306.474,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[280.693,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 29","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.25,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 30","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.26,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 31","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[307.704,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 32","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.996,0.412,0.082,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[278.124,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 33","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,0.616,0.325,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[306.474,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 34","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.957,0.325,0.02,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[334.824,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 35","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":120.000122070313,"op":300.000305175781,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":19,"ty":4,"nm":"red 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":30,"s":[371.75,340.125,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":60,"s":[315.05,299.985,0],"e":[315.05,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":120,"s":[315.05,299.985,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":150,"s":[371.75,259.845,0],"e":[371.75,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[371.75,259.845,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[428.45,219.705,0],"e":[428.45,219.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":330,"s":[428.45,219.705,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":360,"s":[485.15,259.845,0],"e":[485.15,259.845,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":420,"s":[485.15,259.845,0],"e":[428.45,299.985,0],"to":[0,0,0],"ti":[0,0,0]},{"t":450.000457763672}]},"a":{"a":0,"k":[193.074,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[167.294,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.85,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[220.86,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[194.304,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 25","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.902,0.145,0.165,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[164.724,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 26","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.925,0.255,0.235,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[193.074,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 27","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.831,0,0.114,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[221.424,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 28","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":240.000244140625,"op":420.000427246094,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":20,"ty":4,"nm":"green 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[428.95,300.125,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[372.25,340.265,0],"e":[372.25,340.265,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":150,"s":[372.25,340.265,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":180,"s":[315.55,299.865,0],"e":[315.55,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":240,"s":[315.55,299.865,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":270,"s":[372.25,259.725,0],"e":[372.25,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":360,"s":[372.25,259.725,0],"e":[428.95,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":390,"s":[428.95,219.585,0],"e":[428.95,219.585,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":450,"s":[428.95,219.585,0],"e":[485.65,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":480,"s":[485.65,259.725,0],"e":[485.65,259.725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":540.001,"s":[485.65,259.725,0],"e":[428.95,299.865,0],"to":[0,0,0],"ti":[0,0,0]},{"t":570.000579833984}]},"a":{"a":0,"k":[533.273,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[507.494,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.05,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.061,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.579,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.159,0]],"v":[[11.849,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[534.504,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.592,0.769,0.188,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[504.923,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.62,0.816,0.153,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[533.274,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.447,0.58,0.098,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[561.624,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":360.000366210938,"op":540.000549316406,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":21,"ty":4,"nm":"blue 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":60,"s":[485.35,259.875,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":90,"s":[428.65,300.015,0],"e":[428.65,300.015,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":180,"s":[428.65,300.015,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":210,"s":[371.95,340.415,0],"e":[371.95,340.415,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":270,"s":[371.95,340.415,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":300,"s":[315.25,300.275,0],"e":[315.25,300.275,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":360,"s":[315.25,300.275,0],"e":[371.95,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":390,"s":[371.95,260.135,0],"e":[371.95,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":480,"s":[371.95,260.135,0],"e":[428.65,219.995,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":0.44},"o":{"x":0.56,"y":0.56},"n":"0p44_0p44_0p56_0p56","t":510.001,"s":[428.65,219.995,0],"e":[428.65,219.995,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.44,"y":1},"o":{"x":0.56,"y":0},"n":"0p44_1_0p56_0","t":570.001,"s":[428.65,219.995,0],"e":[485.35,260.135,0],"to":[0,0,0],"ti":[0,0,0]},{"t":600.000610351563}]},"a":{"a":0,"k":[646.674,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.619,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.33],[11.911,-1.57],[-0.009,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.009,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[620.894,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.561,0]],"o":[[0,0],[0,4.86],[-6.561,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.849,-6.33],[11.91,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.45,262.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.851,-6.33],[11.911,-1.57],[-0.01,7.23],[-11.911,-1.57],[-11.911,-7.23],[-0.01,1.55]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[674.46,282.323],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.62,4.44],[0,0],[6.58,0],[0,4.86],[0,0],[-6.56,0]],"o":[[0,0],[0,4.86],[-6.56,0],[0,0],[0,4.86],[6.16,0]],"v":[[11.85,-6.331],[11.91,-1.57],[-0.01,7.23],[-11.91,-1.57],[-11.91,-7.23],[-0.01,1.549]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[647.904,302.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-0.001],[28.35,40.141],[-28.35,-0.001],[-28.35,-40.141]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.31,0.678,0.808,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[618.324,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[56.7,-0.01],[0,40.13],[-56.7,-0.01],[0,-40.13]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.392,0.827,0.953,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[646.674,279.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[28.35,-40.14],[28.35,0],[-28.35,40.14],[-28.35,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.149,0.522,0.663,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[675.024,320.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group"}],"ip":480.00048828125,"op":603.00061340332,"st":0,"bm":0,"sr":1}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"LEGO loader","refId":"comp_3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[400,300,0]},"a":{"a":0,"k":[400,300,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"tm":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":150,"s":[20],"e":[20.033]},{"t":601.000611368815}]},"w":800,"h":600,"ip":0,"op":151.000153605143,"st":0,"bm":0,"sr":1}]} \ No newline at end of file diff --git a/themes/NOX/custom-styles.css b/themes/NOX/custom-styles.css index e00317e6b..d20c2b0ce 100644 --- a/themes/NOX/custom-styles.css +++ b/themes/NOX/custom-styles.css @@ -1,675 +1,697 @@ @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVE9eOcEg.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; - } - /* greek */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVFNeOcEg.woff2) format('woff2'); - unicode-range: U+0370-03FF; - } - /* latin-ext */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVGdeOcEg.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; - } - /* latin */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVF9eO.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; - } - /* cyrillic */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbS2lBkm8.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; - } - /* greek */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbTGlBkm8.woff2) format('woff2'); - unicode-range: U+0370-03FF; - } - /* latin-ext */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbQWlBkm8.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; - } - /* latin */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbT2lB.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; - } + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVE9eOcEg.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVFNeOcEg.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* latin-ext */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVGdeOcEg.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVF9eO.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, + U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbS2lBkm8.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbTGlBkm8.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* latin-ext */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbQWlBkm8.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbT2lB.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, + U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} /**************************************** GLOBAL ****************************************/ -[hidden]{ - display:block!important; +[hidden] { + display: block !important; } *:not(path):not(svg) { - font-family: 'Product Sans', sans-serif; + font-family: 'Product Sans', sans-serif; } app-root { - background-color: #000000; + background-color: #000000; } ::-webkit-scrollbar { - width: 1.5vw!important; + width: 1.5vw !important; } ::-webkit-scrollbar-track-piece:end { - margin-bottom: 1.8vh; + margin-bottom: 1.8vh; } ::-webkit-scrollbar-track-piece:start { - margin-top: 3.7vh; + margin-top: 3.7vh; } ::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.5); + background: rgba(255, 255, 255, 0.5); } .scroll__thumb-inactive { - background-color: rgba(127, 143, 166, 0.3); - width: 1.5vw; - height: 70.8vh; - position: fixed; - right: 2.5vw; - top: 26.5vh; + background-color: rgba(127, 143, 166, 0.3); + width: 1.5vw; + height: 70.8vh; + position: fixed; + right: 2.5vw; + top: 26.5vh; } /**************************************** BOTTOM BAR ****************************************/ -app-job-status ~ app-bottom-bar .bottom-bar{ - left: 4vw!important; - width: calc(100% - 4vw - 4vw)!important; +app-job-status ~ app-bottom-bar .bottom-bar { + left: 4vw !important; + width: calc(100% - 4vw - 4vw) !important; } -app-job-status ~ app-bottom-bar .bottom-bar td{ - font-size:3vw!important; +app-job-status ~ app-bottom-bar .bottom-bar td { + font-size: 3vw !important; } app-job-status ~ app-bottom-bar .bottom-bar__enclosure-temperature-icon { - width: 2vw!important; - display: inline-block; - margin-bottom: -0.8vh; - margin-right: 1vw; - } - - + width: 2vw !important; + display: inline-block; + margin-bottom: -0.8vh; + margin-right: 1vw; +} /**************************************** NOTIFICATION ****************************************/ .notification { - background-color: rgba(0, 0, 0, .85)!important; - backdrop-filter: blur(8px)!important; - border-radius: 1vw; - transition: top .2s ease-in-out!important; + background-color: rgba(0, 0, 0, 0.85) !important; + backdrop-filter: blur(8px) !important; + border-radius: 1vw; + transition: top 0.2s ease-in-out !important; } /**************************************** FILES ****************************************/ -ngx-spinner .overlay{ - background: rgba(255, 255, 255, 0)!important; - backdrop-filter: blur(5px); +ngx-spinner .overlay { + background: rgba(255, 255, 255, 0) !important; + backdrop-filter: blur(5px); } -.files__object{ - background-color: #222222!important; - width: 92vw!important; +.files__object { + background-color: #222222 !important; + width: 92vw !important; } .files__name { - font-weight: normal!important; - font-size: 3.1vw!important; + font-weight: normal !important; + font-size: 3.1vw !important; } .files::before { - display:none!important; + display: none !important; } .files__info { - float: right; - padding-left: .7vw; - line-height: 6vw; + float: right; + padding-left: 0.7vw; + line-height: 6vw; } -.files__info-value:first-of-type, .files__info-value:nth-of-type(2){ - display:none!important; /* hide size and filament use */ +.files__info-value:first-of-type, +.files__info-value:nth-of-type(2) { + display: none !important; /* hide size and filament use */ } .sorting { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 0, .7)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.7) !important; + transition: opacity ease-in-out 0.2s !important; } -.sorting-wrapper{ - background: transparent!important; +.sorting-wrapper { + background: transparent !important; } .sorting-close { - position: fixed!important; - right: 3.5vw!important; - top: 5.5vh!important; - width: 5vw!important; + position: fixed !important; + right: 3.5vw !important; + top: 5.5vh !important; + width: 5vw !important; } /**************************************** FILE ****************************************/ -.file{ - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 0, .7)!important; - left:0!important; - right:0!important; - top:0!important; - bottom:0!important; - width:auto!important; - height:auto!important; - transition: opacity ease-in-out .2s!important; -} - -.file__wrapper{ - left: 0!important; - top: 0!important; - right:0!important; - bottom:0!important; - width: auto!important; - height: auto!important; - padding: 6vh 5vw!important; - background: transparent!important; +.file { + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.7) !important; + left: 0 !important; + right: 0 !important; + top: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + transition: opacity ease-in-out 0.2s !important; +} + +.file__wrapper { + left: 0 !important; + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + padding: 6vh 5vw !important; + background: transparent !important; } .file__name { - width: 94%!important; + width: 94% !important; } .file__close { - position: fixed!important; - right: 3.5vw!important; - top: 5.5vh!important; - width: 5vw!important; + position: fixed !important; + right: 3.5vw !important; + top: 5.5vh !important; + width: 5vw !important; } .file__render { - height: 50vh!important; - margin-left: 0!important; - margin-right: 0!important; - margin-bottom: 1.5vh!important; - display:inline-block!important; - background: black; + height: 50vh !important; + margin-left: 0 !important; + margin-right: 0 !important; + margin-bottom: 1.5vh !important; + display: inline-block !important; + background: black; } .file__details { - width: auto!important; - height: 45vh!important; - display:inline-block!important; - position:relative; - top:-4vw; - margin-top:0!important; - margin-right: auto!important; - margin-left: 3vw!important; + width: auto !important; + height: 45vh !important; + display: inline-block !important; + position: relative; + top: -4vw; + margin-top: 0 !important; + margin-right: auto !important; + margin-left: 3vw !important; } .file__details td { - width: 100%!important; - margin-bottom: 1vw!important; - text-align: left!important; - display:block; + width: 100% !important; + margin-bottom: 1vw !important; + text-align: left !important; + display: block; } .job-info__filename { - position: fixed; - top:0; - left:0; - font-size: 4vw!important; - padding-left: 4vw; - padding-right: 4vw; - padding-top: 4vh!important; - width: 100vw!important; - text-overflow: ellipsis; + position: fixed; + top: 0; + left: 0; + font-size: 4vw !important; + padding-left: 4vw; + padding-right: 4vw; + padding-top: 4vh !important; + width: 100vw !important; + text-overflow: ellipsis; } /**************************************** PRINTER STATUS ****************************************/ .quick-control { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 0, .7)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.7) !important; + transition: opacity ease-in-out 0.2s !important; } .quick-control__controller { - border: solid 0.2vw!important; - border-radius: 1vw!important; + border: solid 0.2vw !important; + border-radius: 1vw !important; } .quick-control__controller-set { - border-top: solid 0.2vw!important; + border-top: solid 0.2vw !important; } /**************************************** FILE LOADED ****************************************/ .job-info__preview { - position:absolute!important; - top: 19vh!important; - left: 4vw!important; - width: 30vw!important; + position: absolute !important; + top: 19vh !important; + left: 4vw !important; + width: 30vw !important; } .job-info__preview-image { - width: 30vw!important; - margin:0!important; - display:block!important; + width: 30vw !important; + margin: 0 !important; + display: block !important; } .job-info__preview-discard { - font-size: 2.5vw!important; - width: 30vw!important; + font-size: 2.5vw !important; + width: 30vw !important; } .job-info__print-details { - position:absolute!important; - top: 19vh!important; - left: 39.6vw!important; - margin:0!important; - /* line-height: 1!important; */ + position: absolute !important; + top: 19vh !important; + left: 39.6vw !important; + margin: 0 !important; + /* line-height: 1!important; */ } -.job-info__actions-item-heat{ - position:fixed!important; - top: 22vh!important; - right: 22vw!important; - margin:0!important; - z-index: 10000000000; +.job-info__actions-item-heat { + position: fixed !important; + top: 22vh !important; + right: 22vw !important; + margin: 0 !important; + z-index: 10000000000; } -.job-info__actions-item-print{ - position:fixed!important; - top: 17vh!important; - right: 3vw!important; - margin:0!important; - z-index: 10000000000; +.job-info__actions-item-print { + position: fixed !important; + top: 17vh !important; + right: 3vw !important; + margin: 0 !important; + z-index: 10000000000; } -.job-info__print-details-value{ - margin-top: 0!important; - margin-bottom: 0!important; - padding-bottom: 0!important; - font-size: 3vw!important; - position: relative!important; - top: -1vh!important; +.job-info__print-details-value { + margin-top: 0 !important; + margin-bottom: 0 !important; + padding-bottom: 0 !important; + font-size: 3vw !important; + position: relative !important; + top: -1vh !important; } -.job-info__print-details-finish-state{ - display: none; +.job-info__print-details-finish-state { + display: none; } /**************************************** FILE LOADED - PRINTER STATUS ****************************************/ -app-job-status ~ app-printer-status .printer-status{ - position:absolute; - top: 0vh!important; - left: 0vw!important; +app-job-status ~ app-printer-status .printer-status { + position: absolute; + top: 0vh !important; + left: 0vw !important; } -app-job-status ~ app-printer-status .printer-status__set-value, app-job-status ~ app-printer-status .printer-status__actual-value{ - display:inline!important; - font-size: 4vw!important; +app-job-status ~ app-printer-status .printer-status__set-value, +app-job-status ~ app-printer-status .printer-status__actual-value { + display: inline !important; + font-size: 4vw !important; } -app-job-status ~ app-printer-status .printer-status__unit, app-job-status ~ app-printer-status .printer-status .unit{ - font-size: 3vw!important; +app-job-status ~ app-printer-status .printer-status__unit, +app-job-status ~ app-printer-status .printer-status .unit { + font-size: 3vw !important; } -app-job-status ~ app-printer-status .printer-status__value span:nth-last-child(2) .printer-status__unit{ - display:none!important; +app-job-status ~ app-printer-status .printer-status__value span:nth-last-child(2) .printer-status__unit { + display: none !important; } app-job-status ~ app-printer-status .printer-status__value img { - width: 6vw!important; - float: left; - padding-top: 1.7vh; - padding-right: 2vw; + width: 6vw !important; + float: left; + padding-top: 1.7vh; + padding-right: 2vw; } app-job-status ~ app-printer-status .printer-status__value-1 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 37vh; - left: 38vw; + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 37vh; + left: 38vw; } app-job-status ~ app-printer-status .printer-status__value-1 img { - margin-top:-3vh!important; + margin-top: -3vh !important; } app-job-status ~ app-printer-status .printer-status__value-2 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 37vh; - left: 69vw; - + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 37vh; + left: 69vw; } app-job-status ~ app-printer-status .printer-status__value-2 img { - margin-top:-3vh!important; + margin-top: -3vh !important; } app-job-status ~ app-printer-status .printer-status__value-3 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 53vh; - left: 38vw; - + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 53vh; + left: 38vw; } app-job-status ~ app-printer-status .printer-status__value-3 img { - margin-top:-1.6vh!important; + margin-top: -1.6vh !important; } /**************************************** FILE LOADED - LAYER PROGRESS ****************************************/ -app-job-status ~ app-layer-progress .layer-indication{ - position:absolute!important; - top: 57vh; - left: 68.8vw; - visibility: hidden; - width:auto!important; - margin:0!important; - letter-spacing: -1em; +app-job-status ~ app-height-progress .layer-indication { + position: absolute !important; + top: 57vh; + left: 68.8vw; + visibility: hidden; + width: auto !important; + margin: 0 !important; + letter-spacing: -1em; } -app-job-status ~ app-layer-progress .layer-indication__current-layer{ - position: relative; - top:-0.5vh!important; - visibility: visible!important; - font-size: 4vw!important; - letter-spacing: normal!important; +app-job-status ~ app-height-progress .layer-indication__current-layer { + position: relative; + top: -0.5vh !important; + visibility: visible !important; + font-size: 4vw !important; + letter-spacing: normal !important; } -app-job-status ~ app-layer-progress .layer-indication__total-layers{ - position: relative; - top: -0.5vh!important; - visibility: visible!important; - font-size: 4vw!important; - letter-spacing: normal!important; +app-job-status ~ app-height-progress .layer-indication__total-layers { + position: relative; + top: -0.5vh !important; + visibility: visible !important; + font-size: 4vw !important; + letter-spacing: normal !important; } -app-job-status ~ app-layer-progress .layer-indication::before{ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADaUlEQVRo3tXZTYhVZRgHcJ1JncyYGEyldKOZRB+QRtGiCVEioWRIQVdthNkKbdy2EHLbUsgWSghtpE0RUQYV1sawD/qAMFIKk/FjRKYanV+Le4Y5HJ/33HvPPddz54G7ued5/s//fd73/d/nuWfJkj4ZVuAojmNlv/L0i/wGfGPBzmJj07w6Jb8LU+60a5homl8Z8aU4hNvSNocjGGqab5H8GD7SuX2GNU3znie/FecDkrN4I/vMBs/PY2vT5F/HzYDc39iR83sBfwZ+/+BgE8TnJTKyL/BQELMGnyZi7p7UBhKZt6NYXhJ7T3aJ54LY/kuttETewL4ucCa0ZLVo/ZFa5RL5C56ogLkFPwR49Uqtcon8AA/0gH0/3k9g9y61eBq/BeC3sh1ZWlORJvFfkOcPPFcVtEwid9ZBvJBvXAWprXLOaql6l9gzVatSdoTerOMIZQJxsOQIPdtrglGcauASf4ixXguUr1JKRn/FkxUwt+DHAK9/HSu241KQ9Ab2d4EzgesBzhRerp14IfkGfJ3Y9k5bicju3tSm1cy9nSDypUFq5rAcjyWeHcBMQOgvjOf8xrPvijaDAwnsp8p2s1Py63FG68dkMuFT+0BjQVbPYH1V8i8GVTsRbbVyqY0slEiswsmC72W8VGUBh8V9+7fYFPgPaf24lQ31tzOfoSC+rDs9XHUXXsGVAPQ6XkvEpKQ2KZHYjatBzDT2VCKfA38E5xKVOYLhIKYotaFEYjjbkWinf5IQjyqLWJmd/8g+wYNBzAjeyT4jwfO1OJ3ADO9aHQuZxL9Bwgt4vgucZ/B7gDOLQ7UTLyTfJi2bbZOXFOFiN0XodRGr8XFi+9/DfUHMvXg3EfM51vWL7JhAh7ML+FbiAn6HzTnfR/F94DeXYURC8Kpe22kLA82cVu+zLPBJSe009mZEriae7wnw8g1fTzNx1OecxtrAd3NW9ajCbXcoh/Mwvir4JvuldgtIDfWXsD3wH8Ex7S11R1INX7IP6+YIFS2pONIqE8ZoeCY+hdEgpii1oUQakJn4ZzwexMxLbSiRGpqJU3/uTmNv4D8slsj9WnN00aawq3biheTtZuJlJbGLYiYe7BccBVJ1vGKqJpE1LmLxvuTLLWJUDTNx04tYvC+6CwvpeiYeONPhTDzQps1MXJf9D/8DEmah7Y5IAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA1LTIxVDE3OjUxOjUyKzAwOjAw6dTVAQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wNS0yMVQxNzo1MTo1MiswMDowMJiJbb0AAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC'); - visibility: visible!important; - background-size: 6vw 6vh; - display: inline-block; - width: 6vw; - height: 6vh; - content:""; - margin-right: 2vw; +app-job-status ~ app-height-progress .layer-indication::before { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADaUlEQVRo3tXZTYhVZRgHcJ1JncyYGEyldKOZRB+QRtGiCVEioWRIQVdthNkKbdy2EHLbUsgWSghtpE0RUQYV1sawD/qAMFIKk/FjRKYanV+Le4Y5HJ/33HvPPddz54G7ued5/s//fd73/d/nuWfJkj4ZVuAojmNlv/L0i/wGfGPBzmJj07w6Jb8LU+60a5homl8Z8aU4hNvSNocjGGqab5H8GD7SuX2GNU3znie/FecDkrN4I/vMBs/PY2vT5F/HzYDc39iR83sBfwZ+/+BgE8TnJTKyL/BQELMGnyZi7p7UBhKZt6NYXhJ7T3aJ54LY/kuttETewL4ucCa0ZLVo/ZFa5RL5C56ogLkFPwR49Uqtcon8AA/0gH0/3k9g9y61eBq/BeC3sh1ZWlORJvFfkOcPPFcVtEwid9ZBvJBvXAWprXLOaql6l9gzVatSdoTerOMIZQJxsOQIPdtrglGcauASf4ixXguUr1JKRn/FkxUwt+DHAK9/HSu241KQ9Ab2d4EzgesBzhRerp14IfkGfJ3Y9k5bicju3tSm1cy9nSDypUFq5rAcjyWeHcBMQOgvjOf8xrPvijaDAwnsp8p2s1Py63FG68dkMuFT+0BjQVbPYH1V8i8GVTsRbbVyqY0slEiswsmC72W8VGUBh8V9+7fYFPgPaf24lQ31tzOfoSC+rDs9XHUXXsGVAPQ6XkvEpKQ2KZHYjatBzDT2VCKfA38E5xKVOYLhIKYotaFEYjjbkWinf5IQjyqLWJmd/8g+wYNBzAjeyT4jwfO1OJ3ADO9aHQuZxL9Bwgt4vgucZ/B7gDOLQ7UTLyTfJi2bbZOXFOFiN0XodRGr8XFi+9/DfUHMvXg3EfM51vWL7JhAh7ML+FbiAn6HzTnfR/F94DeXYURC8Kpe22kLA82cVu+zLPBJSe009mZEriae7wnw8g1fTzNx1OecxtrAd3NW9ajCbXcoh/Mwvir4JvuldgtIDfWXsD3wH8Ex7S11R1INX7IP6+YIFS2pONIqE8ZoeCY+hdEgpii1oUQakJn4ZzwexMxLbSiRGpqJU3/uTmNv4D8slsj9WnN00aawq3biheTtZuJlJbGLYiYe7BccBVJ1vGKqJpE1LmLxvuTLLWJUDTNx04tYvC+6CwvpeiYeONPhTDzQps1MXJf9D/8DEmah7Y5IAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA1LTIxVDE3OjUxOjUyKzAwOjAw6dTVAQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wNS0yMVQxNzo1MTo1MiswMDowMJiJbb0AAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC'); + visibility: visible !important; + background-size: 6vw 6vh; + display: inline-block; + width: 6vw; + height: 6vh; + content: ''; + margin-right: 2vw; } -app-job-status ~ app-layer-progress .layer-indication__current-layer::after{ - content: '/'; - font-weight: normal; - padding-left: 0.5vw; - padding-right: 0.5vw; +app-job-status ~ app-height-progress .layer-indication__current-layer::after { + content: '/'; + font-weight: normal; + padding-left: 0.5vw; + padding-right: 0.5vw; } /**************************************** PRINTING ****************************************/ - .job-info__progress { - position: absolute!important; - top: 19vh!important; - left: 4vw!important; - width: 6vw!important; - margin: 0!important; - padding: 0!important; + position: absolute !important; + top: 19vh !important; + left: 4vw !important; + width: 6vw !important; + margin: 0 !important; + padding: 0 !important; } -round-progress svg path{ - stroke-linecap:butt!important; - stroke-width: 50!important; - transform: scale(0.9); - transform-origin: center; - stroke: rgb(31, 153, 0)!important; +round-progress svg path { + stroke-linecap: butt !important; + stroke-width: 50 !important; + transform: scale(0.9); + transform-origin: center; + stroke: rgb(31, 153, 0) !important; } -round-progress svg circle{ - stroke-width: 50!important; - transform: scale(0.9); - transform-origin: center; - stroke: rgba(255, 255, 255, 0.2)!important; +round-progress svg circle { + stroke-width: 50 !important; + transform: scale(0.9); + transform-origin: center; + stroke: rgba(255, 255, 255, 0.2) !important; } #progress-preview-circle .job-info__progress-preview-image { - position:fixed!important; - top: 32vh!important; - left: 4vw!important; - width: 30vw!important; - /* height: 30vw!important; /* test square thumbnail */ - margin:0!important; - display:block!important; + position: fixed !important; + top: 32vh !important; + left: 4vw !important; + width: 30vw !important; + /* height: 30vw!important; /* test square thumbnail */ + margin: 0 !important; + display: block !important; } #progress-preview-bar .job-info__progress-preview { - position:fixed!important; - top: 20.5vh!important; - left: 4vw!important; - width: 30vw!important; - /* height: 30vw!important; /* test square thumbnail */ - margin:0!important; - display:block!important; + position: fixed !important; + top: 20.5vh !important; + left: 4vw !important; + width: 30vw !important; + /* height: 30vw!important; /* test square thumbnail */ + margin: 0 !important; + display: block !important; } .job-info__progress-percentage { - position:fixed!important; - top: 18vh!important; - left: 12vw!important; - margin:0!important; - display:block!important; + position: fixed !important; + top: 18vh !important; + left: 12vw !important; + margin: 0 !important; + display: block !important; - font-size: 6vw!important; - text-align: left!important; - width: auto!important; + font-size: 6vw !important; + text-align: left !important; + width: auto !important; } #progress-preview-bar + .job-info__progress-percentage { - margin: 0!important; - font-size: 8vh!important; - font-weight: 500!important; - display:block!important; - position:fixed!important; - top: 76.3vh!important; - left: 4vw!important; - width: 92vw!important; - z-index:1!important; - color:white!important; - visibility: visible!important; - text-align: center!important; - text-shadow: -2px 0 2px black, 0 2px 2px black, 2px 0 2px black, 0 -2px 2px black; + margin: 0 !important; + font-size: 8vh !important; + font-weight: 500 !important; + display: block !important; + position: fixed !important; + top: 76.3vh !important; + left: 4vw !important; + width: 92vw !important; + z-index: 1 !important; + color: white !important; + visibility: visible !important; + text-align: center !important; + text-shadow: -2px 0 2px black, 0 2px 2px black, 2px 0 2px black, 0 -2px 2px black; } - .job-info__progress-bar { - height: 8vh!important; - border-radius: 0.5vw!important; - background-color: #105310!important; + height: 8vh !important; + border-radius: 0.5vw !important; + background-color: #105310 !important; } .job-info__progress-bar__wrapper { - position:fixed!important; - top: 78vh!important; - left: 3vw!important; - width: 92vw!important; - height: 8vh!important; - border-radius: 0.5vw!important; - background-color: rgb(127, 143, 166, 0.25); - border-style: solid!important; + position: fixed !important; + top: 78vh !important; + left: 3vw !important; + width: 92vw !important; + height: 8vh !important; + border-radius: 0.5vw !important; + background-color: rgb(127, 143, 166, 0.25); + border-style: solid !important; } -.job-info__filament{ - visibility: hidden; +.job-info__filament { + visibility: hidden; } -.job-info__time{ - position: absolute!important; - top: 18vh!important; - left: 38vw!important; - margin:0!important; - font-size:4vw!important; +.job-info__time { + position: absolute !important; + top: 18vh !important; + left: 38vw !important; + margin: 0 !important; + font-size: 4vw !important; } /**************************************** PRINT CONTROLL ****************************************/ .print-control__container { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 0, .7)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.7) !important; + transition: opacity ease-in-out 0.2s !important; } .print-control__adjust__controller { - border: solid 0.2vw!important; - border-radius: 1vw!important; + border: solid 0.2vw !important; + border-radius: 1vw !important; } .print-control__adjust__save { - border: 0.2vw solid!important; - border-radius: 1vw!important; + border: 0.2vw solid !important; + border-radius: 1vw !important; } -.print-control__cancel__action:first-child{ - background-color: rgba(194, 54, 22, 0.85); - text-align: center; - padding: 2vh 7vw!important; - margin: 9vh 6vw!important; - border-radius: 0.8vw; +.print-control__cancel__action:first-child { + background-color: rgba(194, 54, 22, 0.85); + text-align: center; + padding: 2vh 7vw !important; + margin: 9vh 6vw !important; + border-radius: 0.8vw; } -.print-control__cancel__action:last-child{ - background-color: rgb(31, 153, 0)!important; - text-align: center; - padding: 2vh 7vw!important; - margin: 9vh 6vw!important; - border-radius: 0.8vw; +.print-control__cancel__action:last-child { + background-color: rgb(31, 153, 0) !important; + text-align: center; + padding: 2vh 7vw !important; + margin: 9vh 6vw !important; + border-radius: 0.8vw; } /**************************************** SETTINGS ****************************************/ -.settings__made::after{ - content: " \00a0 | \00a0 NOX theme by NoxHirsch"; - width: auto!important; +.settings__made::after { + content: ' \00a0 | \00a0 NOX theme by NoxHirsch'; + width: auto !important; } -.settings__version::after{ - content: " \00a0 | \00a0 NOX theme v0.2.1"; - width: auto!important; +.settings__version::after { + content: ' \00a0 | \00a0 NOX theme v0.2.1'; + width: auto !important; } -.settings-wrapper{ - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 0, .7)!important; +.settings-wrapper { + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.7) !important; } -.settings-container{ - left:0!important; - right:0!important; - top:0!important; - bottom:0!important; - width:auto!important; - height:auto!important; - background:none!important; +.settings-container { + left: 0 !important; + right: 0 !important; + top: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + background: none !important; } .settings__content { - width: 95vw!important; - height: 95vh!important; + width: 95vw !important; + height: 95vh !important; } -.settings__scroll{ - height: 85vh!important; +.settings__scroll { + height: 85vh !important; } -.settings__save{ - background-color: rgba(194, 54, 22, 0.85); - width: 30vw; - text-align: center; - padding: 1vh 0; - border-radius: 0.8vw; +.settings__save { + background-color: rgba(194, 54, 22, 0.85); + width: 30vw; + text-align: center; + padding: 1vh 0; + border-radius: 0.8vw; } -.settings__input{ - margin-top: 1.5vh; - padding: 1.5vw 3vh; - border-radius: 0.5vw!important; - width: 82.5vw!important; - font-size: 3vw!important; - margin-bottom: 2vh; +.settings__input { + margin-top: 1.5vh; + padding: 1.5vw 3vh; + border-radius: 0.5vw !important; + width: 82.5vw !important; + font-size: 3vw !important; + margin-bottom: 2vh; } .settings__input-small { - width: 15vw!important; + width: 15vw !important; } -#octoprintURLName{ - width: 34.8vw!important; /* 23.2vw*1.5 */ +#octoprintURLName { + width: 34.8vw !important; /* 23.2vw*1.5 */ } -#octoprintURLPort{ - width: 12vw!important; /* 8vw*1.5 */ +#octoprintURLPort { + width: 12vw !important; /* 8vw*1.5 */ } -#accessToken, #printerName, #api-polling-interval, #action-command, #enclosure-ambient-id{ - width: 67.41vw!important; /* 44.94vw*1.5 */ +#accessToken, +#printerName, +#api-polling-interval, +#action-command, +#enclosure-ambient-id { + width: 67.41vw !important; /* 44.94vw*1.5 */ } -#xySpeed, #zSpeed, #defaultHotendTemperature, #defaultHeatbedTemperature, #defaultFanSpeed, #filament-feed-length, #filament-purge-distance, #filament-feed-speed, #filament-feed-speed-slow, #filament-thickness, #filament-density{ - width: 28.5vw!important; /* 19vw*1.5 */ +#xySpeed, +#zSpeed, +#defaultHotendTemperature, +#defaultHeatbedTemperature, +#defaultFanSpeed, +#filament-feed-length, +#filament-purge-distance, +#filament-feed-speed, +#filament-feed-speed-slow, +#filament-thickness, +#filament-density { + width: 28.5vw !important; /* 19vw*1.5 */ } .settings__input-label { - font-size: 2.5vw!important; - padding-top: 4vh!important; + font-size: 2.5vw !important; + padding-top: 4vh !important; } -#action-icon, #action-color{ - width: 21vw!important; /* 14vw*1.5 */ +#action-icon, +#action-color { + width: 21vw !important; /* 14vw*1.5 */ } -.settings__checkbox-descriptor{ - padding-right: 3vw; +.settings__checkbox-descriptor { + padding-right: 3vw; } -.settings__list li{ - padding-top: 1.8vw!important; - padding-bottom: 1.8vw!important; +.settings__list li { + padding-top: 1.8vw !important; + padding-bottom: 1.8vw !important; } .settings__close { - position: fixed!important; - right: 3vw!important; - top: 5.1vh!important; - width: 5vw!important; + position: fixed !important; + right: 3vw !important; + top: 5.1vh !important; + width: 5vw !important; } diff --git a/themes/theGarbz/Focus/custom-styles.css b/themes/theGarbz/Focus/custom-styles.css index f98410901..adcefdc2f 100644 --- a/themes/theGarbz/Focus/custom-styles.css +++ b/themes/theGarbz/Focus/custom-styles.css @@ -1,789 +1,808 @@ @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVE9eOcEg.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; - } - /* greek */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVFNeOcEg.woff2) format('woff2'); - unicode-range: U+0370-03FF; - } - /* latin-ext */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVGdeOcEg.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; - } - /* latin */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Product Sans'), local('ProductSans-Regular'), url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVF9eO.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; - } - /* cyrillic */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbS2lBkm8.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; - } - /* greek */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbTGlBkm8.woff2) format('woff2'); - unicode-range: U+0370-03FF; - } - /* latin-ext */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbQWlBkm8.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; - } - /* latin */ - @font-face { - font-family: 'Product Sans'; - font-style: normal; - font-weight: 500; - font-display: swap; - src: local('Product Sans Medium'), local('ProductSans-Medium'), url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbT2lB.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; - } + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVE9eOcEg.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVFNeOcEg.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* latin-ext */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVGdeOcEg.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Product Sans'), local('ProductSans-Regular'), + url(https://fonts.gstatic.com/s/productsans/v12/pxiDypQkot1TnFhsFMOfGShVF9eO.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, + U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbS2lBkm8.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbTGlBkm8.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* latin-ext */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbQWlBkm8.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Product Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: local('Product Sans Medium'), local('ProductSans-Medium'), + url(https://fonts.gstatic.com/s/productsans/v12/pxicypQkot1TnFhsFMOfGShd5PSbT2lB.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, + U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} /**************************************** GLOBAL ****************************************/ -[hidden]{ - display:block!important; +[hidden] { + display: block !important; } *:not(path):not(svg) { - font-family: 'Product Sans', sans-serif; + font-family: 'Product Sans', sans-serif; } app-root { - background-color: #000000; + background-color: #000000; } :root { - --dark-text: rgba(128, 128, 128, 1); - --light-text: rgb(245, 246, 250, 1); - --green: rgb(65, 170, 27); - --dark-green: rgb(65, 170, 27, 0.75); + --dark-text: rgba(128, 128, 128, 1); + --light-text: rgb(245, 246, 250, 1); + --green: rgb(65, 170, 27); + --dark-green: rgb(65, 170, 27, 0.75); } ::-webkit-scrollbar { - width: 3.7vw!important; + width: 3.7vw !important; } ::-webkit-scrollbar-track-piece:end { - margin-bottom: 1.8vh; + margin-bottom: 1.8vh; } ::-webkit-scrollbar-track-piece:start { - margin-top: 3.7vh; + margin-top: 3.7vh; } ::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.5); + background: rgba(255, 255, 255, 0.5); } - /**************************************** HOME PAGE *****************************************/ -app-main-screen .printer-status{ - margin-top: 6vh!important; +app-main-screen .printer-status { + margin-top: 6vh !important; } /**************************************** BOTTOM BAR ****************************************/ -app-job-status ~ app-bottom-bar .bottom-bar{ - left: 4vw!important; - width: calc(100% - 4vw - 4vw)!important; +app-job-status ~ app-bottom-bar .bottom-bar { + left: 4vw !important; + width: calc(100% - 4vw - 4vw) !important; } -.bottom-bar__printer-name, .bottom-bar__current-status { - color: var(--dark-text); +.bottom-bar__printer-name, +.bottom-bar__current-status { + color: var(--dark-text); } -app-job-status ~ app-bottom-bar .bottom-bar td{ - font-size:3vw!important; +app-job-status ~ app-bottom-bar .bottom-bar td { + font-size: 3vw !important; } app-job-status ~ app-bottom-bar .bottom-bar__enclosure-temperature-icon { - width: 2vw!important; - display: inline-block; - margin-bottom: -0.8vh; - margin-right: 1vw; - filter: brightness(0.5); + width: 2vw !important; + display: inline-block; + margin-bottom: -0.8vh; + margin-right: 1vw; + filter: brightness(0.5); } app-job-status ~ app-bottom-bar .bottom-bar__enclosure-temperature { - color: var(--dark-text); + color: var(--dark-text); } /**************************************** NOTIFICATION ****************************************/ .notification { - background-color: rgba(60, 0, 0, .85)!important; - backdrop-filter: blur(8px)!important; - border-radius: 1vw; - transition: top .2s ease-in-out!important; + background-color: rgba(60, 0, 0, 0.85) !important; + backdrop-filter: blur(8px) !important; + border-radius: 1vw; + transition: top 0.2s ease-in-out !important; } /**************************************** FILES ****************************************/ -ngx-spinner .overlay{ - background: rgba(255, 255, 255, 0)!important; - backdrop-filter: blur(5px); +ngx-spinner .overlay { + background: rgba(255, 255, 255, 0) !important; + backdrop-filter: blur(5px); } -.files__object{ - background-color: #555555!important; - width: 89vw!important; +.files__object { + background-color: #555555 !important; + width: 89vw !important; } .files__name { - font-weight: normal!important; - font-size: 3.1vw!important; + font-weight: normal !important; + font-size: 3.1vw !important; } .files::before { - display:none!important; + display: none !important; } .files__info { - float: right; - padding-left: .7vw; - line-height: 6vw; + float: right; + padding-left: 0.7vw; + line-height: 6vw; } -.files__info-value:first-of-type, .files__info-value:nth-of-type(2){ - display:none!important; /* hide size and filament use */ +.files__info-value:first-of-type, +.files__info-value:nth-of-type(2) { + display: none !important; /* hide size and filament use */ } .sorting { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 40, .8)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 40, 0.8) !important; + transition: opacity ease-in-out 0.2s !important; } -.sorting-wrapper{ - background: transparent!important; +.sorting-wrapper { + background: transparent !important; } .sorting-close { - position: fixed!important; - right: 3.5vw!important; - top: 5.5vh!important; - width: 5vw!important; + position: fixed !important; + right: 3.5vw !important; + top: 5.5vh !important; + width: 5vw !important; } /************************************** FILAMENT **************************************/ .filament-filaments::before { - display:none!important; + display: none !important; } -.filament tr{ - background-color: #555555!important; - width: 87.5vw!important; +.filament tr { + background-color: #555555 !important; + width: 87.5vw !important; } .filament-filaments { - width: 95.5vw!important; + width: 95.5vw !important; } .filament-filaments__name { - width: 59.5vw!important; + width: 59.5vw !important; } app-filament .scroll__thumb-inactive { - background-color: rgba(127, 143, 166, 0.3); - width: 3.7vw; - height: 61.7vh!important; - position: fixed; - right: 2.5vw!important; - top: 35.8vh!important; + background-color: rgba(127, 143, 166, 0.3); + width: 3.7vw; + height: 61.7vh !important; + position: fixed; + right: 2.5vw !important; + top: 35.8vh !important; } - - /**************************************** FILE ****************************************/ -.file{ - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 40, .8)!important; - left:0!important; - right:0!important; - top:0!important; - bottom:0!important; - width:auto!important; - height:auto!important; - transition: opacity ease-in-out .2s!important; -} - -.file__wrapper{ - left: 0!important; - top: 0!important; - right:0!important; - bottom:0!important; - width: auto!important; - height: auto!important; - padding: 6vh 5vw!important; - background: transparent!important; +.file { + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 40, 0.8) !important; + left: 0 !important; + right: 0 !important; + top: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + transition: opacity ease-in-out 0.2s !important; +} + +.file__wrapper { + left: 0 !important; + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + padding: 6vh 5vw !important; + background: transparent !important; } .file__name { - width: 94%!important; + width: 94% !important; } .file__close { - position: fixed!important; - right: 3.5vw!important; - top: 5.5vh!important; - width: 5vw!important; + position: fixed !important; + right: 3.5vw !important; + top: 5.5vh !important; + width: 5vw !important; } .file__render { - height: 50vh!important; - margin-left: 0!important; - margin-right: 0!important; - margin-bottom: 1.5vh!important; - display:inline-block!important; - background: black; + height: 50vh !important; + margin-left: 0 !important; + margin-right: 0 !important; + margin-bottom: 1.5vh !important; + display: inline-block !important; + background: black; } .file__details { - width: auto!important; - height: 45vh!important; - display:inline-block!important; - position:relative; - top:-4vw; - margin-top:0!important; - margin-right: auto!important; - margin-left: 3vw!important; + width: auto !important; + height: 45vh !important; + display: inline-block !important; + position: relative; + top: -4vw; + margin-top: 0 !important; + margin-right: auto !important; + margin-left: 3vw !important; } .file__details td { - width: 100%!important; - margin-bottom: 1vw!important; - text-align: left!important; - display:block; + width: 100% !important; + margin-bottom: 1vw !important; + text-align: left !important; + display: block; } .file__details td:nth-of-type(1)::before { - content: "File Size: "; - font-size: 3vw; - color: var(--dark-text); + content: 'File Size: '; + font-size: 3vw; + color: var(--dark-text); } .file__details td:nth-of-type(2)::before { - content: "Est Print Time:"; - font-size: 3vw; - color: var(--dark-text); + content: 'Est Print Time:'; + font-size: 3vw; + color: var(--dark-text); } .file__details td:nth-of-type(3)::before { - content: "Est Filament Use:"; - font-size: 3vw; - color: var(--dark-text); + content: 'Est Filament Use:'; + font-size: 3vw; + color: var(--dark-text); } -.file__details-name, .file__directory, .file__creation-date { - color: var(--dark-text); +.file__details-name, +.file__directory, +.file__creation-date { + color: var(--dark-text); } .job-info__filename { - position: fixed; - top:0; - left:0; - font-size: 4vw!important; - padding-left: 4vw; - padding-right: 4vw; - padding-top: 4vh!important; - width: 100vw!important; - text-overflow: ellipsis; + position: fixed; + top: 0; + left: 0; + font-size: 4vw !important; + padding-left: 4vw; + padding-right: 4vw; + padding-top: 4vh !important; + width: 100vw !important; + text-overflow: ellipsis; } app-files .scroll__thumb-inactive { - background-color: rgba(127, 143, 166, 0.3); - width: 3.7vw; - height: 71.4vh!important; - position: fixed; - right: 2.5vw!important; - top: 27.8vh!important; + background-color: rgba(127, 143, 166, 0.3); + width: 3.7vw; + height: 71.4vh !important; + position: fixed; + right: 2.5vw !important; + top: 27.8vh !important; } /**************************************** PRINTER STATUS ****************************************/ .quick-control { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 40, .8)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 40, 0.8) !important; + transition: opacity ease-in-out 0.2s !important; } .quick-control__controller { - border: solid 0.2vw!important; - border-radius: 1vw!important; + border: solid 0.2vw !important; + border-radius: 1vw !important; } .quick-control__controller-set { - border-top: solid 0.2vw!important; + border-top: solid 0.2vw !important; } /**************************************** FILE LOADED ****************************************/ .job-info__preview { - position:absolute!important; - top: 19vh!important; - left: 4vw!important; - width: 30vw!important; + position: absolute !important; + top: 19vh !important; + left: 4vw !important; + width: 30vw !important; } .job-info__preview-image { - width: 30vw!important; - margin:0!important; - display:block!important; - height:50vh!important; + width: 30vw !important; + margin: 0 !important; + display: block !important; + height: 50vh !important; } .job-info__preview-discard { - font-size: 2.5vw!important; - width: 40vw!important; - position:fixed!important; - top: 74vh!important; - left: 31vw!important; + font-size: 2.5vw !important; + width: 40vw !important; + position: fixed !important; + top: 74vh !important; + left: 31vw !important; } .job-info__print-details { - position:absolute!important; - top: 19vh!important; - left: 37vw!important; - margin:0!important; - overflow:hidden!important; - height:15vh!important; + position: absolute !important; + top: 19vh !important; + left: 37vw !important; + margin: 0 !important; + overflow: hidden !important; + height: 15vh !important; } - - -.job-info__actions-item-heat{ - position:fixed!important; - top: 17vh!important; - right: 20vw!important; - height: 11vw!important; - width: 11vw!important; - margin:0!important; - z-index: 10000000000; - background-color: var(--dark-green)!important; - border-radius: 2vw!important; +.job-info__actions-item-heat { + position: fixed !important; + top: 17vh !important; + right: 20vw !important; + height: 11vw !important; + width: 11vw !important; + margin: 0 !important; + z-index: 10000000000; + background-color: var(--dark-green) !important; + border-radius: 2vw !important; } -.job-info__actions-item-heat-icon{ - width: 6vw!important; - padding: 2.5vw!important; +.job-info__actions-item-heat-icon { + width: 6vw !important; + padding: 2.5vw !important; } -.job-info__actions-item-print{ - position:fixed!important; - top: 17vh!important; - right: 5vw!important; - height: 11vw!important; - width: 11vw!important; - margin:0!important; - z-index: 10000000000; - background-color: var(--dark-green)!important; - border-radius: 2vw!important; +.job-info__actions-item-print { + position: fixed !important; + top: 17vh !important; + right: 5vw !important; + height: 11vw !important; + width: 11vw !important; + margin: 0 !important; + z-index: 10000000000; + background-color: var(--dark-green) !important; + border-radius: 2vw !important; } -.job-info__print-details span br{ - display: none; +.job-info__print-details span br { + display: none; } -.job-info__print-details-value{ - margin-top: 0!important; - margin-bottom: 0!important; - padding-bottom: 0!important; +.job-info__print-details-value { + margin-top: 0 !important; + margin-bottom: 0 !important; + padding-bottom: 0 !important; } -.job-info__print-details-finish-state{ - display: table; - position: relative; - left: 5vw!important; - margin-bottom:2vh!important; +.job-info__print-details-finish-state { + display: table; + position: relative; + left: 5vw !important; + margin-bottom: 2vh !important; } - - /**************************************** FILE LOADED - PRINTER STATUS ****************************************/ -app-job-status ~ app-printer-status .printer-status{ - position:absolute; - top: 0vh!important; - left: 0vw!important; +app-job-status ~ app-printer-status .printer-status { + position: absolute; + top: 0vh !important; + left: 0vw !important; } app-job-status ~ app-printer-status .printer-status__set-value { - display:inline!important; - font-size: 3.5vw!important; - color: var(--dark-text); + display: inline !important; + font-size: 3.5vw !important; + color: var(--dark-text); } -app-job-status ~ app-printer-status .printer-status__actual-value{ - display:inline!important; - font-size: 5vw!important; +app-job-status ~ app-printer-status .printer-status__actual-value { + display: inline !important; + font-size: 5vw !important; } -app-job-status ~ app-printer-status .printer-status__unit, app-job-status ~ app-printer-status .printer-status .unit{ - font-size: 3vw!important; - color: var(--dark-text); +app-job-status ~ app-printer-status .printer-status__unit, +app-job-status ~ app-printer-status .printer-status .unit { + font-size: 3vw !important; + color: var(--dark-text); } -app-job-status ~ app-printer-status .printer-status__value span:nth-last-child(2) .printer-status__unit{ - display:none!important; +app-job-status ~ app-printer-status .printer-status__value span:nth-last-child(2) .printer-status__unit { + display: none !important; } app-job-status ~ app-printer-status .printer-status__value { - height: 11vh!important; + height: 11vh !important; } app-job-status ~ app-printer-status .printer-status__value img { - width: 6vw!important; - float: left; - padding-top: 1.7vh; - padding-right: 2vw; - filter: brightness(0.8); + width: 6vw !important; + float: left; + padding-top: 1.7vh; + padding-right: 2vw; + filter: brightness(0.8); } app-job-status ~ app-printer-status .printer-status__value-1 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 37vh; - left: 38vw; + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 37vh; + left: 38vw; } app-job-status ~ app-printer-status .printer-status__value-1 img { - margin-top:-3vh!important; + margin-top: -3vh !important; } app-job-status ~ app-printer-status .printer-status__value-2 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 37vh; - left: 69vw; - + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 37vh; + left: 69vw; } app-job-status ~ app-printer-status .printer-status__value-2 img { - margin-top:-3vh!important; + margin-top: -3vh !important; } app-job-status ~ app-printer-status .printer-status__value-3 { - width: auto!important; - padding-left: 0!important; - padding-right: 0!important; - position: absolute; - top: 53vh; - left: 38vw; - + width: auto !important; + padding-left: 0 !important; + padding-right: 0 !important; + position: absolute; + top: 53vh; + left: 38vw; } app-job-status ~ app-printer-status .printer-status__value-3 img { - margin-top:-1.6vh!important; + margin-top: -1.6vh !important; } /**************************************** FILE LOADED - LAYER PROGRESS ****************************************/ -app-job-status ~ app-layer-progress .layer-indication{ - position:absolute!important; - top: 60vh; - left: 68.8vw; - visibility: hidden; - width:auto!important; - margin:0!important; - letter-spacing: -1em; -} - -app-job-status ~ app-layer-progress .layer-indication__current-layer{ - position: relative; - top:-0.5vh!important; - visibility: visible!important; - font-size: 5vw!important; - letter-spacing: normal!important; -} - -app-job-status ~ app-layer-progress .layer-indication__total-layers{ - position: relative; - top: -0.5vh!important; - visibility: visible!important; - font-size: 3.5vw!important; - letter-spacing: normal!important; - color: var(--dark-text); -} - -app-job-status ~ app-layer-progress .layer-indication::before{ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADaUlEQVRo3tXZTYhVZRgHcJ1JncyYGEyldKOZRB+QRtGiCVEioWRIQVdthNkKbdy2EHLbUsgWSghtpE0RUQYV1sawD/qAMFIKk/FjRKYanV+Le4Y5HJ/33HvPPddz54G7ued5/s//fd73/d/nuWfJkj4ZVuAojmNlv/L0i/wGfGPBzmJj07w6Jb8LU+60a5homl8Z8aU4hNvSNocjGGqab5H8GD7SuX2GNU3znie/FecDkrN4I/vMBs/PY2vT5F/HzYDc39iR83sBfwZ+/+BgE8TnJTKyL/BQELMGnyZi7p7UBhKZt6NYXhJ7T3aJ54LY/kuttETewL4ucCa0ZLVo/ZFa5RL5C56ogLkFPwR49Uqtcon8AA/0gH0/3k9g9y61eBq/BeC3sh1ZWlORJvFfkOcPPFcVtEwid9ZBvJBvXAWprXLOaql6l9gzVatSdoTerOMIZQJxsOQIPdtrglGcauASf4ixXguUr1JKRn/FkxUwt+DHAK9/HSu241KQ9Ab2d4EzgesBzhRerp14IfkGfJ3Y9k5bicju3tSm1cy9nSDypUFq5rAcjyWeHcBMQOgvjOf8xrPvijaDAwnsp8p2s1Py63FG68dkMuFT+0BjQVbPYH1V8i8GVTsRbbVyqY0slEiswsmC72W8VGUBh8V9+7fYFPgPaf24lQ31tzOfoSC+rDs9XHUXXsGVAPQ6XkvEpKQ2KZHYjatBzDT2VCKfA38E5xKVOYLhIKYotaFEYjjbkWinf5IQjyqLWJmd/8g+wYNBzAjeyT4jwfO1OJ3ADO9aHQuZxL9Bwgt4vgucZ/B7gDOLQ7UTLyTfJi2bbZOXFOFiN0XodRGr8XFi+9/DfUHMvXg3EfM51vWL7JhAh7ML+FbiAn6HzTnfR/F94DeXYURC8Kpe22kLA82cVu+zLPBJSe009mZEriae7wnw8g1fTzNx1OecxtrAd3NW9ajCbXcoh/Mwvir4JvuldgtIDfWXsD3wH8Ex7S11R1INX7IP6+YIFS2pONIqE8ZoeCY+hdEgpii1oUQakJn4ZzwexMxLbSiRGpqJU3/uTmNv4D8slsj9WnN00aawq3biheTtZuJlJbGLYiYe7BccBVJ1vGKqJpE1LmLxvuTLLWJUDTNx04tYvC+6CwvpeiYeONPhTDzQps1MXJf9D/8DEmah7Y5IAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA1LTIxVDE3OjUxOjUyKzAwOjAw6dTVAQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wNS0yMVQxNzo1MTo1MiswMDowMJiJbb0AAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC'); - visibility: visible!important; - background-size: 6vw 6vh; - display: inline-block; - width: 6vw; - height: 6vh; - content:""; - margin-right: 2vw; - filter: brightness(0.7); -} - -app-job-status ~ app-layer-progress .layer-indication__current-layer::after{ - content: '/'; - font-weight: normal; - padding-left: 0.5vw; - padding-right: 0.5vw; - color: var(--dark-text); +app-job-status ~ app-height-progress .layer-indication { + position: absolute !important; + top: 60vh; + left: 68.8vw; + visibility: hidden; + width: auto !important; + margin: 0 !important; + letter-spacing: -1em; +} + +app-job-status ~ app-height-progress .layer-indication__current-layer { + position: relative; + top: -0.5vh !important; + visibility: visible !important; + font-size: 5vw !important; + letter-spacing: normal !important; +} + +app-job-status ~ app-height-progress .layer-indication__total-layers { + position: relative; + top: -0.5vh !important; + visibility: visible !important; + font-size: 3.5vw !important; + letter-spacing: normal !important; + color: var(--dark-text); +} + +app-job-status ~ app-height-progress .layer-indication::before { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADaUlEQVRo3tXZTYhVZRgHcJ1JncyYGEyldKOZRB+QRtGiCVEioWRIQVdthNkKbdy2EHLbUsgWSghtpE0RUQYV1sawD/qAMFIKk/FjRKYanV+Le4Y5HJ/33HvPPddz54G7ued5/s//fd73/d/nuWfJkj4ZVuAojmNlv/L0i/wGfGPBzmJj07w6Jb8LU+60a5homl8Z8aU4hNvSNocjGGqab5H8GD7SuX2GNU3znie/FecDkrN4I/vMBs/PY2vT5F/HzYDc39iR83sBfwZ+/+BgE8TnJTKyL/BQELMGnyZi7p7UBhKZt6NYXhJ7T3aJ54LY/kuttETewL4ucCa0ZLVo/ZFa5RL5C56ogLkFPwR49Uqtcon8AA/0gH0/3k9g9y61eBq/BeC3sh1ZWlORJvFfkOcPPFcVtEwid9ZBvJBvXAWprXLOaql6l9gzVatSdoTerOMIZQJxsOQIPdtrglGcauASf4ixXguUr1JKRn/FkxUwt+DHAK9/HSu241KQ9Ab2d4EzgesBzhRerp14IfkGfJ3Y9k5bicju3tSm1cy9nSDypUFq5rAcjyWeHcBMQOgvjOf8xrPvijaDAwnsp8p2s1Py63FG68dkMuFT+0BjQVbPYH1V8i8GVTsRbbVyqY0slEiswsmC72W8VGUBh8V9+7fYFPgPaf24lQ31tzOfoSC+rDs9XHUXXsGVAPQ6XkvEpKQ2KZHYjatBzDT2VCKfA38E5xKVOYLhIKYotaFEYjjbkWinf5IQjyqLWJmd/8g+wYNBzAjeyT4jwfO1OJ3ADO9aHQuZxL9Bwgt4vgucZ/B7gDOLQ7UTLyTfJi2bbZOXFOFiN0XodRGr8XFi+9/DfUHMvXg3EfM51vWL7JhAh7ML+FbiAn6HzTnfR/F94DeXYURC8Kpe22kLA82cVu+zLPBJSe009mZEriae7wnw8g1fTzNx1OecxtrAd3NW9ajCbXcoh/Mwvir4JvuldgtIDfWXsD3wH8Ex7S11R1INX7IP6+YIFS2pONIqE8ZoeCY+hdEgpii1oUQakJn4ZzwexMxLbSiRGpqJU3/uTmNv4D8slsj9WnN00aawq3biheTtZuJlJbGLYiYe7BccBVJ1vGKqJpE1LmLxvuTLLWJUDTNx04tYvC+6CwvpeiYeONPhTDzQps1MXJf9D/8DEmah7Y5IAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA1LTIxVDE3OjUxOjUyKzAwOjAw6dTVAQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wNS0yMVQxNzo1MTo1MiswMDowMJiJbb0AAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC'); + visibility: visible !important; + background-size: 6vw 6vh; + display: inline-block; + width: 6vw; + height: 6vh; + content: ''; + margin-right: 2vw; + filter: brightness(0.7); +} + +app-job-status ~ app-height-progress .layer-indication__current-layer::after { + content: '/'; + font-weight: normal; + padding-left: 0.5vw; + padding-right: 0.5vw; + color: var(--dark-text); } /**************************************** PRINTING ****************************************/ .job-info__progress { - position: fixed!important; - width: 27vw!important; - height: 28vw!important; - top: 14vh!important; + position: fixed !important; + width: 27vw !important; + height: 28vw !important; + top: 14vh !important; } -round-progress svg path{ - stroke-linecap:butt!important; - stroke-width: 50!important; - transform: scale(0.9); - transform-origin: center; - stroke: var(--green)!important; +round-progress svg path { + stroke-linecap: butt !important; + stroke-width: 50 !important; + transform: scale(0.9); + transform-origin: center; + stroke: var(--green) !important; } -round-progress svg circle{ - stroke-width: 50!important; - transform: scale(0.9); - transform-origin: center; - stroke: rgba(255, 255, 255, 0.2)!important; +round-progress svg circle { + stroke-width: 50 !important; + transform: scale(0.9); + transform-origin: center; + stroke: rgba(255, 255, 255, 0.2) !important; } .job-info__progress-preview { - position:fixed!important; - top: 18vh!important; - left: 4vw!important; - width: 29vw!important; - margin:0!important; - display:block!important; + position: fixed !important; + top: 18vh !important; + left: 4vw !important; + width: 29vw !important; + margin: 0 !important; + display: block !important; } .job-info__progress-percentage { - position:fixed!important; - top: 35vh!important; - left: 9vw!important; - margin:0!important; - display:block!important; - font-size: 9.5vw!important; - width: 20vw!important; + position: fixed !important; + top: 35vh !important; + left: 9vw !important; + margin: 0 !important; + display: block !important; + font-size: 9.5vw !important; + width: 20vw !important; } #progress-preview-bar + .job-info__progress-percentage { - margin-top: -1.4vh!important; - margin-left: 0vw!important; - font-size: 8.7vh!important; - font-weight: 500!important; - display:block!important; - position:fixed!important; - left: 40vw!important; - top: 77vh!important; - z-index:1!important; - color:white!important; - visibility: visible!important; - text-shadow: -2px 0 2px black, 0 2px 2px black, 2px 0 2px black, 0 -2px 2px black; + margin-top: -1.4vh !important; + margin-left: 0vw !important; + font-size: 8.7vh !important; + font-weight: 500 !important; + display: block !important; + position: fixed !important; + left: 40vw !important; + top: 77vh !important; + z-index: 1 !important; + color: white !important; + visibility: visible !important; + text-shadow: -2px 0 2px black, 0 2px 2px black, 2px 0 2px black, 0 -2px 2px black; } - .job-info__progress-bar { - height: 8vh!important; - border-radius: 1.7vw!important; - background-color: var(--green)!important; + height: 8vh !important; + border-radius: 1.7vw !important; + background-color: var(--green) !important; } .job-info__progress-bar__wrapper { - position:fixed!important; - top: 78vh!important; - left: 3vw!important; - width: 92vw!important; - height: 8vh!important; - border-radius: 2vw!important; - background-color: rgb(127, 143, 166, 0.25); - border-style: solid!important; + position: fixed !important; + top: 78vh !important; + left: 3vw !important; + width: 92vw !important; + height: 8vh !important; + border-radius: 2vw !important; + background-color: rgb(127, 143, 166, 0.25); + border-style: solid !important; } -.job-info__filament{ - visibility: hidden; +.job-info__filament { + visibility: hidden; } -.job-info__time{ - position: absolute!important; - top: 18vh!important; - left: 38vw!important; - margin:0!important; - font-size:4vw!important; - color: var(--dark-text)!important; +.job-info__time { + position: absolute !important; + top: 18vh !important; + left: 38vw !important; + margin: 0 !important; + font-size: 4vw !important; + color: var(--dark-text) !important; } .job-info__time-left { - color: var(--light-text)!important; - font-size: 8vw!important; + color: var(--light-text) !important; + font-size: 8vw !important; } -.job-info__time-left::after{ - content: " "; +.job-info__time-left::after { + content: ' '; } .job-info__time span:first-of-type { - color: var(--dark-text); + color: var(--dark-text); } /**************************************** PRINT CONTROLL ****************************************/ .print-control__container { - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 40, .8)!important; - transition: opacity ease-in-out .2s!important; + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 40, 0.8) !important; + transition: opacity ease-in-out 0.2s !important; } .print-control__adjust__controller { - border: solid 0.2vw!important; - border-radius: 1vw!important; + border: solid 0.2vw !important; + border-radius: 1vw !important; } .print-control__adjust__save { - border: 0.2vw solid!important; - border-radius: 1vw!important; + border: 0.2vw solid !important; + border-radius: 1vw !important; } -.print-control__cancel__action:first-child{ - background-color: rgba(194, 54, 22, 0.85); - text-align: center; - padding: 2vh 7vw!important; - margin: 9vh 6vw!important; - border-radius: 1vw; +.print-control__cancel__action:first-child { + background-color: rgba(194, 54, 22, 0.85); + text-align: center; + padding: 2vh 7vw !important; + margin: 9vh 6vw !important; + border-radius: 1vw; } -.print-control__cancel__action:last-child{ - background-color: var(--dark-green)!important; - text-align: center; - padding: 2vh 7vw!important; - margin: 9vh 6vw!important; - border-radius: 0.8vw; +.print-control__cancel__action:last-child { + background-color: var(--dark-green) !important; + text-align: center; + padding: 2vh 7vw !important; + margin: 9vh 6vw !important; + border-radius: 0.8vw; } /**************************************** SETTINGS ****************************************/ -.settings__made::after{ - content: " \00a0 | \00a0 Focus theme by theGarbz"; - width: auto!important; +.settings__made::after { + content: ' \00a0 | \00a0 Focus theme by theGarbz'; + width: auto !important; } -.settings__version::after{ - content: " \00a0 | \00a0 Focus theme v0.2"; - width: auto!important; +.settings__version::after { + content: ' \00a0 | \00a0 Focus theme v0.2'; + width: auto !important; } -.settings-wrapper{ - backdrop-filter: blur(8px); - background-color: rgba(0, 0, 40, .8)!important; +.settings-wrapper { + backdrop-filter: blur(8px); + background-color: rgba(0, 0, 40, 0.8) !important; } -.settings-container{ - left:0!important; - right:0!important; - top:0!important; - bottom:0!important; - width:auto!important; - height:auto!important; - background:none!important; +.settings-container { + left: 0 !important; + right: 0 !important; + top: 0 !important; + bottom: 0 !important; + width: auto !important; + height: auto !important; + background: none !important; } .settings__content { - width: 95vw!important; - height: 95vh!important; + width: 95vw !important; + height: 95vh !important; } -.settings__scroll{ - height: 85vh!important; +.settings__scroll { + height: 85vh !important; } -.settings__save{ - background-color: rgba(194, 54, 22, 0.85); - width: 30vw; - text-align: center; - padding: 1vh 0; - border-radius: 0.8vw; +.settings__save { + background-color: rgba(194, 54, 22, 0.85); + width: 30vw; + text-align: center; + padding: 1vh 0; + border-radius: 0.8vw; } -.settings__input{ - margin-top: 1.5vh; - padding: 1.5vw 3vh; - border-radius: 0.5vw!important; - width: 82.5vw!important; - font-size: 3vw!important; - margin-bottom: 2vh; +.settings__input { + margin-top: 1.5vh; + padding: 1.5vw 3vh; + border-radius: 0.5vw !important; + width: 82.5vw !important; + font-size: 3vw !important; + margin-bottom: 2vh; } .settings__input-small { - width: 15vw!important; + width: 15vw !important; } -#octoprintURLName{ - width: 34.8vw!important; /* 23.2vw*1.5 */ +#octoprintURLName { + width: 34.8vw !important; /* 23.2vw*1.5 */ } -#octoprintURLPort{ - width: 12vw!important; /* 8vw*1.5 */ +#octoprintURLPort { + width: 12vw !important; /* 8vw*1.5 */ } -#accessToken, #printerName, #api-polling-interval, #action-command, #enclosure-ambient-id{ - width: 67.41vw!important; /* 44.94vw*1.5 */ +#accessToken, +#printerName, +#api-polling-interval, +#action-command, +#enclosure-ambient-id { + width: 67.41vw !important; /* 44.94vw*1.5 */ } -#xySpeed, #zSpeed, #defaultHotendTemperature, #defaultHeatbedTemperature, #defaultFanSpeed, #filament-feed-length, #filament-purge-distance, #filament-feed-speed, #filament-feed-speed-slow, #filament-thickness, #filament-density{ - width: 28.5vw!important; /* 19vw*1.5 */ +#xySpeed, +#zSpeed, +#defaultHotendTemperature, +#defaultHeatbedTemperature, +#defaultFanSpeed, +#filament-feed-length, +#filament-purge-distance, +#filament-feed-speed, +#filament-feed-speed-slow, +#filament-thickness, +#filament-density { + width: 28.5vw !important; /* 19vw*1.5 */ } .settings__input-label { - font-size: 2.5vw!important; - padding-top: 4vh!important; + font-size: 2.5vw !important; + padding-top: 4vh !important; } -#action-icon, #action-color{ - width: 21vw!important; /* 14vw*1.5 */ +#action-icon, +#action-color { + width: 21vw !important; /* 14vw*1.5 */ } -.settings__checkbox-descriptor{ - padding-right: 3vw; +.settings__checkbox-descriptor { + padding-right: 3vw; } -.settings__list li{ - padding-top: 1.8vw!important; - padding-bottom: 1.8vw!important; +.settings__list li { + padding-top: 1.8vw !important; + padding-bottom: 1.8vw !important; } - .settings__close { - position: fixed!important; - right: 3vw!important; - top: 5.1vh!important; - width: 5vw!important; -} \ No newline at end of file + position: fixed !important; + right: 3vw !important; + top: 5.1vh !important; + width: 5vw !important; +}