From af260ad22917b30a819f1a0d2ef788b546d82364 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sun, 3 Jan 2021 12:23:13 +0100 Subject: [PATCH 001/189] front: add AnimatedTiles plugin --- front/package.json | 1 + front/src/Phaser/Game/GameScene.ts | 5 +++++ front/tsconfig.json | 1 + front/yarn.lock | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/front/package.json b/front/package.json index 09f27ec5..d429bd42 100644 --- a/front/package.json +++ b/front/package.json @@ -27,6 +27,7 @@ "generic-type-guard": "^3.2.0", "google-protobuf": "^3.13.0", "phaser": "^3.22.0", + "phaser-animated-tiles": "Informatic/phaser-animated-tiles#2d5c66a9bc426dd4cb2d856c1d599494a74f8067", "queue-typescript": "^1.0.1", "quill": "^1.3.7", "simple-peer": "^9.6.2", diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 181592e2..ab9232d4 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -68,6 +68,8 @@ import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCha import {TextureError} from "../../Exception/TextureError"; import {TextField} from "../Components/TextField"; +import AnimatedTiles from "phaser-animated-tiles"; + export interface GameSceneInitInterface { initPosition: PointInterface|null, reconnecting: boolean @@ -114,6 +116,7 @@ export class GameScene extends ResizableScene implements CenterListener { Layers!: Array; Objects!: Array; mapFile!: ITiledMap; + animatedTiles!: AnimatedTiles; groups: Map; startX!: number; startY!: number; @@ -189,6 +192,7 @@ export class GameScene extends ResizableScene implements CenterListener { file: file.src }); }); + this.load.scenePlugin('AnimatedTiles', AnimatedTiles, 'animatedTiles', 'animatedTiles'); this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); }); @@ -400,6 +404,7 @@ export class GameScene extends ResizableScene implements CenterListener { this.initCamera(); + this.animatedTiles.init(this.Map); this.initCirclesCanvas(); // Let's pause the scene if the connection is not established yet diff --git a/front/tsconfig.json b/front/tsconfig.json index 3fce57ea..fbfc8c07 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -8,6 +8,7 @@ "downlevelIteration": true, "jsx": "react", "allowJs": true, + "esModuleInterop": true, "strict": true, /* Enable all strict type-checking options. */ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ diff --git a/front/yarn.lock b/front/yarn.lock index a31409a6..ea50cc4d 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -3663,6 +3663,10 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +phaser-animated-tiles@Informatic/phaser-animated-tiles#2d5c66a9bc426dd4cb2d856c1d599494a74f8067: + version "2.0.2" + resolved "https://codeload.github.com/Informatic/phaser-animated-tiles/tar.gz/2d5c66a9bc426dd4cb2d856c1d599494a74f8067" + phaser@^3.22.0: version "3.51.0" resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.51.0.tgz#b0c7ee2b21e795830d74f476dd30816a42b023bd" From 3c099ea7830f619e9f042d010c0439b7700548f2 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Thu, 7 Jan 2021 19:09:53 +0100 Subject: [PATCH 002/189] back,pusher,uploader: cleanup dependencies Move typescript/ts-node-dev to dev dependencies, remove unused dependencies. --- back/package.json | 10 +- back/yarn.lock | 209 +-------------------------------- pusher/package.json | 11 +- pusher/yarn.lock | 214 +--------------------------------- uploader/package.json | 10 +- uploader/yarn.lock | 262 +----------------------------------------- 6 files changed, 22 insertions(+), 694 deletions(-) diff --git a/back/package.json b/back/package.json index 09d6794a..a6ff7319 100644 --- a/back/package.json +++ b/back/package.json @@ -38,23 +38,17 @@ "homepage": "https://github.com/thecodingmachine/workadventure#readme", "dependencies": { "axios": "^0.21.1", - "body-parser": "^1.19.0", "busboy": "^0.3.1", "circular-json": "^0.5.9", "debug": "^4.3.1", "generic-type-guard": "^3.2.0", "google-protobuf": "^3.13.0", "grpc": "^1.24.4", - "http-status-codes": "^1.4.0", - "iterall": "^1.3.0", "jsonwebtoken": "^8.5.1", "mkdirp": "^1.0.4", - "multer": "^1.4.2", "prom-client": "^12.0.0", "query-string": "^6.13.3", "systeminformation": "^4.31.1", - "ts-node-dev": "^1.0.0-pre.44", - "typescript": "^3.8.3", "uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0", "uuidv4": "^6.0.7" }, @@ -71,6 +65,8 @@ "@typescript-eslint/eslint-plugin": "^2.26.0", "@typescript-eslint/parser": "^2.26.0", "eslint": "^6.8.0", - "jasmine": "^3.5.0" + "jasmine": "^3.5.0", + "ts-node-dev": "^1.0.0-pre.44", + "typescript": "^3.8.3" } } diff --git a/back/yarn.lock b/back/yarn.lock index 501146cb..889d642f 100644 --- a/back/yarn.lock +++ b/back/yarn.lock @@ -257,11 +257,6 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -append-field@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" - integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -370,22 +365,6 @@ bintrees@1.0.1: resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= -body-parser@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -427,14 +406,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -busboy@^0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" - integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= - dependencies: - dicer "0.2.5" - readable-stream "1.1.x" - busboy@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" @@ -449,11 +420,6 @@ bytebuffer@~5: dependencies: long "~3" -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -622,26 +588,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -678,7 +629,7 @@ dateformat@~1.0.4-1.2.3: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -753,24 +704,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -dicer@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" - integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= - dependencies: - readable-stream "1.1.x" - streamsearch "0.1.2" - dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -804,11 +742,6 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1255,28 +1188,12 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - http-status-codes@*: version "2.1.4" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798" integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg== -http-status-codes@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" - integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== - -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1323,16 +1240,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - ini@~1.3.0: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" @@ -1507,11 +1419,6 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1534,11 +1441,6 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - jasmine-core@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" @@ -1743,11 +1645,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -1788,18 +1685,6 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -1862,20 +1747,6 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -multer@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a" - integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg== - dependencies: - append-field "^1.0.0" - busboy "^0.2.11" - concat-stream "^1.5.2" - mkdirp "^0.5.1" - object-assign "^4.1.1" - on-finished "^2.3.0" - type-is "^1.6.4" - xtend "^4.0.0" - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -1997,7 +1868,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -2025,13 +1896,6 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -on-finished@^2.3.0, on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2207,11 +2071,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - query-string@^6.13.3: version "6.13.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.4.tgz#b35a9a3bd4955bce55f94feb0e819b3d0be6f66f" @@ -2221,16 +2080,6 @@ query-string@^6.13.3: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -2258,17 +2107,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2.0.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -2444,11 +2283,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -2590,11 +2424,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - streamsearch@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" @@ -2640,11 +2469,6 @@ string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -2807,11 +2631,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -2889,19 +2708,6 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@^1.6.4, type-is@~1.6.17: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typescript@^3.8.3: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" @@ -2921,11 +2727,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" diff --git a/pusher/package.json b/pusher/package.json index 03fd761d..306cc830 100644 --- a/pusher/package.json +++ b/pusher/package.json @@ -38,23 +38,16 @@ "homepage": "https://github.com/thecodingmachine/workadventure#readme", "dependencies": { "axios": "^0.21.1", - "body-parser": "^1.19.0", "busboy": "^0.3.1", "circular-json": "^0.5.9", "debug": "^4.3.1", "generic-type-guard": "^3.2.0", "google-protobuf": "^3.13.0", "grpc": "^1.24.4", - "http-status-codes": "^1.4.0", - "iterall": "^1.3.0", "jsonwebtoken": "^8.5.1", "mkdirp": "^1.0.4", - "multer": "^1.4.2", "prom-client": "^12.0.0", "query-string": "^6.13.3", - "systeminformation": "^4.30.5", - "ts-node-dev": "^1.0.0-pre.44", - "typescript": "^3.8.3", "uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0", "uuidv4": "^6.0.7" }, @@ -71,6 +64,8 @@ "@typescript-eslint/eslint-plugin": "^2.26.0", "@typescript-eslint/parser": "^2.26.0", "eslint": "^6.8.0", - "jasmine": "^3.5.0" + "jasmine": "^3.5.0", + "ts-node-dev": "^1.0.0-pre.44", + "typescript": "^3.8.3" } } diff --git a/pusher/yarn.lock b/pusher/yarn.lock index f7de8093..21fe642a 100644 --- a/pusher/yarn.lock +++ b/pusher/yarn.lock @@ -257,11 +257,6 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -append-field@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" - integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -370,22 +365,6 @@ bintrees@1.0.1: resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= -body-parser@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -427,14 +406,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -busboy@^0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" - integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= - dependencies: - dicer "0.2.5" - readable-stream "1.1.x" - busboy@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" @@ -449,11 +420,6 @@ bytebuffer@~5: dependencies: long "~3" -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -622,26 +588,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" @@ -678,7 +629,7 @@ dateformat@~1.0.4-1.2.3: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -753,24 +704,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -dicer@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" - integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= - dependencies: - readable-stream "1.1.x" - streamsearch "0.1.2" - dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -804,11 +742,6 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1255,28 +1188,12 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - http-status-codes@*: version "2.1.4" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798" integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg== -http-status-codes@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" - integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== - -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1323,16 +1240,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - ini@~1.3.0: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" @@ -1507,11 +1419,6 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1534,11 +1441,6 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - jasmine-core@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" @@ -1743,11 +1645,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -1788,18 +1685,6 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -1862,20 +1747,6 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -multer@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a" - integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg== - dependencies: - append-field "^1.0.0" - busboy "^0.2.11" - concat-stream "^1.5.2" - mkdirp "^0.5.1" - object-assign "^4.1.1" - on-finished "^2.3.0" - type-is "^1.6.4" - xtend "^4.0.0" - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -1997,7 +1868,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -2025,13 +1896,6 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -on-finished@^2.3.0, on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2207,11 +2071,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - query-string@^6.13.3: version "6.13.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.4.tgz#b35a9a3bd4955bce55f94feb0e819b3d0be6f66f" @@ -2221,16 +2080,6 @@ query-string@^6.13.3: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -2258,17 +2107,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2.0.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -2444,11 +2283,6 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -2590,11 +2424,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - streamsearch@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" @@ -2640,11 +2469,6 @@ string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -2723,11 +2547,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -systeminformation@^4.30.5: - version "4.30.5" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.30.5.tgz#2219c305c8be56a2cfa527a5519c45bc81d4916c" - integrity sha512-aYWs8yttl8ePpr6VOQ/Ak8cznuc9L/NQODVhbOKhInX73ZMLvV2BS86Mzr7LLfmUteVFR36CTDNQgiJgRqq+SQ== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -2807,11 +2626,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -2889,19 +2703,6 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@^1.6.4, type-is@~1.6.17: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typescript@^3.8.3: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" @@ -2921,11 +2722,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" diff --git a/uploader/package.json b/uploader/package.json index 27e1d146..62b55c07 100644 --- a/uploader/package.json +++ b/uploader/package.json @@ -37,18 +37,12 @@ }, "homepage": "https://github.com/thecodingmachine/workadventure#readme", "dependencies": { - "body-parser": "^1.19.0", "busboy": "^0.3.1", "debug": "^4.3.1", - "http-status-codes": "^1.4.0", - "iterall": "^1.3.0", "jsonwebtoken": "^8.5.1", - "multer": "^1.4.2", "mkdirp": "^1.0.4", "prom-client": "^12.0.0", "query-string": "^6.13.3", - "ts-node-dev": "^1.0.0-pre.44", - "typescript": "^3.8.3", "uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0", "uuidv4": "^6.0.7" }, @@ -64,6 +58,8 @@ "@types/mkdirp": "^1.0.1", "@types/uuidv4": "^5.0.0", "eslint": "^6.8.0", - "jasmine": "^3.5.0" + "jasmine": "^3.5.0", + "ts-node-dev": "^1.0.0-pre.44", + "typescript": "^3.8.3" } } diff --git a/uploader/yarn.lock b/uploader/yarn.lock index 1591fa3e..aa917ced 100644 --- a/uploader/yarn.lock +++ b/uploader/yarn.lock @@ -205,11 +205,6 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -append-field@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" - integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -247,22 +242,6 @@ bintrees@1.0.1: resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= -body-parser@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -288,14 +267,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -busboy@^0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" - integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= - dependencies: - dicer "0.2.5" - readable-stream "1.1.x" - busboy@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" @@ -303,11 +274,6 @@ busboy@^0.3.1: dependencies: dicer "0.3.0" -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -404,26 +370,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -455,13 +401,6 @@ dateformat@~1.0.4-1.2.3: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" @@ -484,19 +423,6 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -dicer@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" - integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= - dependencies: - readable-stream "1.1.x" - streamsearch "0.1.2" - dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -530,11 +456,6 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -815,28 +736,12 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - http-status-codes@*: version "2.1.4" resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798" integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg== -http-status-codes@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-1.4.0.tgz#6e4c15d16ff3a9e2df03b89f3a55e1aae05fb477" - integrity sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ== - -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -876,16 +781,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - inquirer@^7.0.0: version "7.3.3" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" @@ -961,26 +861,11 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - jasmine-core@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" @@ -1134,11 +1019,6 @@ map-obj@^1.0.0, map-obj@^1.0.1: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -1155,18 +1035,6 @@ meow@^3.3.0: redent "^1.0.0" trim-newlines "^1.0.0" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== - dependencies: - mime-db "1.44.0" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -1196,11 +1064,6 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -1211,20 +1074,6 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multer@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a" - integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg== - dependencies: - append-field "^1.0.0" - busboy "^0.2.11" - concat-stream "^1.5.2" - mkdirp "^0.5.1" - object-assign "^4.1.1" - on-finished "^2.3.0" - type-is "^1.6.4" - xtend "^4.0.0" - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -1255,18 +1104,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -object-assign@^4.0.1, object-assign@^4.1.1: +object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -on-finished@^2.3.0, on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1370,11 +1212,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -1392,11 +1229,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - query-string@^6.13.3: version "6.13.7" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.7.tgz#af53802ff6ed56f3345f92d40a056f93681026ee" @@ -1406,16 +1238,6 @@ query-string@^6.13.3: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -1433,29 +1255,6 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.2.2: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readdirp@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -1540,11 +1339,6 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -1567,11 +1361,6 @@ semver@^7.3.2: dependencies: lru-cache "^6.0.0" -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -1647,11 +1436,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - streamsearch@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" @@ -1680,18 +1464,6 @@ string-width@^4.1.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -1790,11 +1562,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -1873,19 +1640,6 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@^1.6.4, type-is@~1.6.17: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - typescript@^3.8.3: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" @@ -1895,11 +1649,6 @@ uWebSockets.js@uNetworking/uWebSockets.js#v18.5.0: version "18.5.0" resolved "https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/9b1605d2db82981cafe69dbe356e10ce412f5805" -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - uri-js@^4.2.2: version "4.4.0" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" @@ -1907,11 +1656,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - uuid@8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" From f7c45929449fae5e424f754475cae732496ebf5a Mon Sep 17 00:00:00 2001 From: Valdo Romao Date: Wed, 24 Mar 2021 23:10:02 +0000 Subject: [PATCH 003/189] Updated favicons --- .../images/favicons/android-icon-144x144.png | Bin 4239 -> 12409 bytes .../images/favicons/android-icon-192x192.png | Bin 4504 -> 17138 bytes .../images/favicons/android-icon-36x36.png | Bin 1654 -> 2405 bytes .../images/favicons/android-icon-48x48.png | Bin 2023 -> 3211 bytes .../images/favicons/android-icon-72x72.png | Bin 2483 -> 5023 bytes .../images/favicons/android-icon-96x96.png | Bin 3093 -> 7334 bytes .../images/favicons/apple-icon-114x114.png | Bin 3397 -> 9081 bytes .../images/favicons/apple-icon-120x120.png | Bin 3541 -> 9776 bytes .../images/favicons/apple-icon-144x144.png | Bin 4239 -> 12409 bytes .../images/favicons/apple-icon-152x152.png | Bin 4302 -> 13449 bytes .../images/favicons/apple-icon-180x180.png | Bin 5132 -> 16382 bytes .../images/favicons/apple-icon-57x57.png | Bin 2199 -> 3804 bytes .../images/favicons/apple-icon-60x60.png | Bin 2223 -> 4034 bytes .../images/favicons/apple-icon-72x72.png | Bin 2483 -> 5023 bytes .../images/favicons/apple-icon-76x76.png | Bin 2596 -> 5410 bytes .../favicons/apple-icon-precomposed.png | Bin 5078 -> 17710 bytes .../static/images/favicons/apple-icon.png | Bin 5078 -> 17710 bytes .../static/images/favicons/favicon-16x16.png | Bin 1221 -> 1499 bytes .../static/images/favicons/favicon-32x32.png | Bin 1596 -> 2150 bytes .../static/images/favicons/favicon-96x96.png | Bin 3093 -> 7334 bytes front/dist/static/images/favicons/favicon.ico | Bin 1150 -> 1150 bytes .../images/favicons/ms-icon-144x144.png | Bin 4239 -> 12409 bytes .../images/favicons/ms-icon-150x150.png | Bin 4283 -> 13082 bytes .../images/favicons/ms-icon-310x310.png | Bin 10098 -> 33026 bytes .../static/images/favicons/ms-icon-70x70.png | Bin 2451 -> 4858 bytes 25 files changed, 0 insertions(+), 0 deletions(-) diff --git a/front/dist/static/images/favicons/android-icon-144x144.png b/front/dist/static/images/favicons/android-icon-144x144.png index b0463804a94f2be528dc1a20b5d6b3a3b5ab996d..eefafe8d4852f9df83447e8d6e2e0baf2cfc085e 100644 GIT binary patch delta 12027 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 delta 3830 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 L`njxgN@xNAz+}yz literal 4504 zcmcJTS2WyR+lT)%qmN#rjS`|ojR#Q&qqiXlqDDpuB6^QOv=Jo;Li8YclqioDVFtrQ zNz`Z&y+j`+N}{~pgJ*pw-{JQi?7i38>pt0g-Rt^Y>rO-(>(EefPyqlyqo<27yFPLM zT@+;3yVr)0}Y5IG-s5Q#kmst;$ zU0Kp%hQcbCoDmMlR|M(a`5L*tisoe4|ZTq>xMn_u*hc zFUg7mJ?`cJX6*l`Aa}{ho9L3SQGYUDaH2eu_KfpJ1vNPpjyxQyKMC+TnpsA#>#f!m zbIRW8Urs1IWIB7wt=Y^Kk17I|`lYwJlEvcob=#GQUVWwHiwPlzY5hFwohZX23Z1H( z@mb%i#Cl~vhrtdDE@f{tQ`6={1f*RQmwmjogT@hR2U$9r&0xc2*q2;|4}CIR@s_>t=90W%8}())RQdoN|$Q^kWv|DqO#BU`W+oC(my8Z|(K><_7?>8n@|V z^|ziqRqXbF_Y4VWdsmO!Iue{b@d%}m34kF4QR1!=v6Kg1NA-`{pvCy@Ift0S4svV@ zrGv`z_RwRMC~33l)Z1OJpu~0W?!pL842oCxZmM9*A?f*-`L4*hve^JwISQKUbWMl(lB36-3huvo3B525$u{Pz)R1^%J!E z!+pN#eEO5gy?v=zZ=ykYC?=MX%OTq1{$lkWkn~paKt{QZI`V30BS?bGs;X=Ckl1fP z{K8iJ3DM*{;m%0uxWzEey4X31ln7e)TAq0M@>Zu4#STCP+GtLJk$9b@1h>y`oqsL} zrfJPb!JwwFI~+xvOg~ELZ9tijHDf@1xLU~lAO2EG-oJTc)BM{kO=_~M&hHWY#gI8Z zu!c9qaf!-lfiM?60dz|We(UmLPSKMgRRBOW9p%z(z~FSD+b>Q$tSo@LoqIm_O0|8` z`G~Xh>)83PPp~QXNz<5?RMKO9gvr+DZUtO9?K7sX_{Cjn-eQ3p>&{tCKKRp3j0>k7 zkJIS-a`z05_gk*OP#w9)lIU0bV_5+0;d&WUeL83 zly|%`e(Gf^_sa!^%=xQ>e3g-_x--#Yil&Gpzw=px2u)}0z=kOL4a1G#ax%4GCi{*! z*$^*x;C}XEtk~0C>-PeF4dg&RYllsg!TLg&H}1^U$ytemz*hX@Io%ccvtvHb9d(}s zZ8&M#of-HJMfg=4F$0U(b$nF67=k4BH1!QF5Qhh)k?(bT)WSIIBLzoBCE*_T53V|C zg6rjNS1my+^z#`QWKEq3kl#@1_eo+CWY2IOLs;lX9^+NrG8YTm!BQEViqrjX1IBnW z>~eKcCSz`rbVt(rZrVvespAispG8JVA$(8Xy_$Be2G(9pZTin0zGkapLYEja{fmrk zJ5n0WlvkkNfiGfPUmszhY|MV+K)R)m?e&2g?wbgIez3MFQw=l+UE^0lPw@ zXr4tAg+6J~wvaEypJ1kEKF~QVNInvhDz^&%DvZBbFjh&dR*O@MV3`YN>9?r5TlE2q z3?23C>?RP;>`s4G)V9iBHo~gA?^HhZg4lQ+7p}gM76r3`$fSJ5Cay07HpJHFg> zfl2Uo{ZO`2XiEXqbN+q@#JSS8o3DA(77eC^RGz10z<6l^ zhCCTg99{8LrY_&kRL9+ou5MlUs>{8UlO9vVLou_$&#^7O!tK#RM#~Ljylh~iGG*X` z7M(MmF1(SSu!GsRRvEk4(Q;w@hEYCunKUn1F1$xji%<8wr>yO)Hreew?Fe^;{lE@6_d=`#Uq)A>^n^n{Iw>4Hf{ZLr^%QH zIa7^BrNA<)$P1e?so5)T%yvnkRn+>|?g`c^Zw)6rQ(ztCz=lPOKdohUu{ln3=#eEQ z4sonh4c`u061=qJ9f}vZZO3ubph*3Q8!);lrxjJezqS3A$02&}6ZMcC8XK$=8tv0; zB#N@Kj>`~3Dn(m#i0m++Uq*lQr?qb-b2aHQwxhZ@cMrZSL9mP9#XslFn^xnd?-7$L z`QwsRg#Xm~GZ(Z8=XrGqc5J!EMfFhGD$-?3NVW2%ZtT~RD3Lg#;Wmju^U;$Xl*wcy z#hGD^)B^?&=a3?I?4gV-=Y1Bzhu?{#&?R|cw*fP&I+8{$g@`4zbu7P?x%(KN7KA z|EiKsxCat8Sx(F!|DYOoqKe*$$n3?p!oGUx) zEj`on_;xdi8At*v;E88?QIY` zo+OOSS3Et25`sBjOTGTXG(>>e2bL2~<4m#gmYa-WWj5mozSebl>jIU87 zGgT=VaQH+o`;o|Dc$+nOwe%qWM$4KFAeVBNrR_68;It@-mgf`w-`d8UEL1A0jFPEY zPQ}!j(>&Iyfg{B)5TiA&!^aqTe3<7oj3~gAIdzk1et#Fg%wK3H3lE`_Yc5FH`$n~} zr9(W+uC1diV|3& z&&HWNF_`_Jar6>Q{3(5Yq|$Ph_pU^z9Y4)P6q4*}REu7hgqLBCNu1MU{dW5jU;-|& z7htK{MzKrx%L~QxZHU$UZa#4(_tyliEtYh$bbV&zP*Rn=8rdanrwn1?VZkN1(Mfrg z48PwIjuwEY1-E9Obl7*gP|Lh|-26>dm%*107-I5Ud&tKzF!@JFc^Z1^Pf9O;P*!4? zd+|xuRKI*h1Lz+0sGQS;IEr1omIMX2)5VGCtF49JG&H5v{MYi^)`0!dsArg zM}lsnJ)A=s84r6(xUwqnV+6QIz)Ku*=Q(r;COwI=ZA%CsTX?U^2)I^G^6ssN^wBT^MTMijk7| zA~$}5Zoe4v-s{>&P0c0Aef7VwLUK%juAzx+rT#`m(zd}V*^kBhbVVOxp0Ri zF#_(AUl5a=LF9osXWLTQDG@JRUh70ghr8XdmN=GFsxz|3su z*drzrN>+Y0p>E4GCru)CL*&B9FWDb`&ND0?>c;;Vaa46{dcL;e#n|WjDn{tJ5-uNi zZS6H+F#}CTALIY(M|!FkE7SU(zl&66ZO+(SkH;$s4?c)-0KdroQlQ-~apH85IAziZ z-r&o4)O1NVhpq)oD<`r8ndg?A|z|F-W7;j+xviCLF6*{;<-__>u+o__@MIXjcsIyLt zL2_r;dsoSXiF;I$~#P&k*%YAF@9oWdM9ZPvJ+fI_jxfPCCfKuxAyczs>f!< z3y(N@^PH9^V)jX-w#-eUKCSr7Y`pOw!8Q3d`ck|V9@8K#dhy&#{PgWRAhRxqjgR^b z1iuDpn3LMvUU5mI$U9IV20)5Q^Mdw+c$x+kst74ni30;%2ch$98CX}X3Bu(;n$81D xVwsL^nY{ts@hTD<@O diff --git a/front/dist/static/images/favicons/android-icon-36x36.png b/front/dist/static/images/favicons/android-icon-36x36.png index cc93c290293f18d9f534aec0afc382cb4ee8bc0c..79f0c6abe7ebec763a715a6df60050344bacb306 100644 GIT binary patch delta 2025 zcmVb<(}-s7U)Ypa{4yBS%|Ok0$@UZx}0AB}w0_+4n23kEZUjPmQ z-!DM#0b$SfVfJhvX5_}`l0eZCZGSPa6*vG?i;2g8HZTahT&Qpz7zG{`YV-lSf$tUV zqrl@*ssBeI3dx(mK%s^dO0|JT(Y~hu{|J~a#wA7FSBgFlig|Q7h0J1=x%XHRZ>+s9 z#@vvuk}m>7Kw_+&GS*&4Q zkmo}ogv;LhKQ(7(Z~f-Yw>o{zCSxOFs^Xj2Hd-uQ8?yJ}JSAVa)Hu&JffA8wA#C+oihelrf&MUKPH-6FAR;}V+7cRtq zedCQC&Dq(()mw(fUj5n0TibT-%#AUingeO+Pay<`hK3dessVcolV}{rBuRoxQ`?%F zvQnw$Q4)IqRh3S=ZCX>4u{B2P8wN9DEvhOCXb7|?C!@UMq`JDESAS|X6%hdf-N3k} zst-g&Rh3PfHq8TyR25(qa1{715Q;i#^?IoG_iL7A(&=uU4y1m@LY&47yG`1PqG^d7k5(!x)2xfDeH@ z&nZEdD_udlCUMS@rhh5k`!;Y#L@KH(-h1)hbMfNEvabR}&be})P?!V}!I*9UmJln2 z>Fw*ir`c@MXf#OEGysw$$-ugG>o!&3iBi)66bkNtJRV$%Mg))N~N-|Ua#M`*8c6OXW3`* zouvRp1n)g*nt!S>W+F|~v39%t&{`WON%AG&TdI09TFHdZ0}8-7$JEqRE+QYQ>aV@` z7gnuWHPGMRe@sO7s%m9fpyvexgb+eIgwPO?TfkVQQn@uaIJh>1(4dI&MS*(5);Y(* zjqfv-HZY>9zZH=YV0`oD%^N}pJAh3T2mMoly!V6<=6@Xdc_;)-s_M1<`}e=sXf&kV zZvPZG4r~Etfv_l0=-HW9y8k?FVLfB5F=lmNU*8Mk~3c$J^@l`j18AWf94MeX44J_krJu$h%91{j2x~ec|P~_Dpl;6jaCGx* zvm8wM(ei!aQ<|(Wqk8Y1s-|h0PE1Tpd^#{N;PX7^H3cO4AzBLRCE<8ZX zm6sp$-p`%tz?}2uc|K>pGC^y%+cVC&YrrKDd6cH9s;ahHEsh^QKJPmv&@Au=U;;QU zB7bW{#EOVnsEBiJ?!6bNEZ%$C?KaJ3vxL+T!l$ZwPDIWDx1%Tu-g_2JVGE~os(OQN z?z^$m>5ygF*Sz=ZOY@bETjVkGHqXU?vMfVYJ0fydRo@2QQPuybYFe7;$dMyY013do zd-n=1>Cduk>;3!p56;ZY9L@857sb`6*MC=fopm8l@3CX8ownA#gbF(d>R+2H6{gWioIF7wB#_ij;FMnLQ za)kp24lFzN^RiU=FF=Wdd9~>$U;qFBC3HntbYx+4WjbSWWnpw>05UK#F)c7NEiyDz zGBY|bFgh|dD=;uRFfjC1*kS+x03~!qSaf7zbY(hiZ)9m^c>ppnGBGVMGc7VSR5CL< zFfckYH7hVMIxsMW3t-*=002gGMU(CX@(ngIHa0RgI5IV8$YRrz?FC6dF)c7NEiyDO zVP-ZsW;8K0Gd40cV`elnWHVx6GG=BtH928oVK*~nE@@+LE^uyV?%bt(00000NkvXX Hu0mjfoo&fD delta 1263 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 jpUg|)vr~P&JvOY%@Q_NUjWAJr9bg)DHsy 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 delta 2023 zcmZ{lX*?5*1IO7B8**l&$=SpjGt5vq7h{_H_-u|Llxu{RmCaB&dRj)VVj?QnXyh!> z;i@EODMu*LBY#39|L4W?_IdIBd|!M&pWoYGiS|Qz?q!yUy@<#^oa_xhAtEA%B-&cJ zGv0qM@{Kq^P6ZD_Q4NfX_@Ke*gFx=e{8 zSMFITYwS%t?IMCYKc&Y;I`+%v8XX2N3JcpnkqG!H| zmnPJ)-J!)70L33gu>885!SnkPlEiKDe(y9xN2}R2Z=Mb)ed;HQt50u>Uu-e{w67bG0VJj{U^5ysaEL;JrhfO$(_ zgoFO>oBi#e)Gxx1x_39IcU6S00R^Fnk@vR(!)>{#@!_;ZIq&ztNOW$lMWYY-LksIW zT?k9s0>5}Sv9Yb)!*N=o^@lXLRk_|Q=f~?tP{j_Gq;^osEK-AnXy;Rnp7*%0;An%MA$&v~#t&7cOh{Vj#i2Qy37wkKEZJk%tE{+?YMJLZBY(Ts1ent!L3;lE=d1NFJFQXr zU;?wVJOdK9%tiSyp59a;2S*$q@OSya%v3t#w(^{0g%g$U|bs>toz^ajW8 zy)k?Y=WImO8>7N^S?yDwzsY5)c`f2!CUmPVGcHXkZ{2B9Y_6nSLA1CHc+f+|NSR8B zIb<%U&79VMGT&5X;nnH|!BG9+cH`hj2r6%%_A&|p``cGiwOzEy>1~K{?ojJ!7GF%2 z?a_ZO_QeU%s{*io^oWzIdx09i1+wty3J)$;U*W9-RJ44+8dX}+CCyVbKZ;JI`p85r zr7D@ZBy6{TItpu6E3EA7`i1HEnQ+*?tMs!V2!{CnPFsCnt%R?{%qy>%nUP@}&65l# zcXtx-=F{_)l2%`Nnf0rTSd^V}sqYvZX@Kk{a|@0@N!YNA!uk zS?{dpjWiZMvOA9%u!du7%ESM2r3N$2e!R^4l_?^0rpX$;CT> zIvFBq($$~%jIz+7DNz8O8lkvuR_&QJ1>{6qS!>TpZ+5M^(H9+7q3Y~|CNrH@DzoSH zImKyGNnuR!@e)-R8R6)7g&GQ8-t1Ap18 z_Y*fUP0BdB2F*8?Ul`bbQ=9!Z2G2azPhx`a0P;0xe&z#Lw|-AA9HGJoFQ^wq_(O!J zl3UL44{MbjNj)@{Cc5H{vJ*QEx|^zqn8#uX5(@zIU^~Kwo1RYUQ`coUUSMS`$PLde z&e=|utV#lgT0j?C@w#T;X^$DM!4TbTKa#khZ%ZrV$a6vyKr1Q^)iDN-XN_x|fz;Tv z*eejfjN+=;Q`+=%{<2!gp3-rX{4<4ZLr$Jsa_)WXtTkxk`&$?3M64q|t2%_)3(8F- zQD5iaMisn5Q9=Pt!~N5xWdJF_!4Y+_X6s>w#ssH=vxllgj@waWg-wR0)y zbrrmx{LW`z=Q_1s4-fB?;%E%29Rd8SJs@MsQolQoG|sD&g(+ju7#td7>W;yg85o&i z@hA+&41@8A$*|^4|7X@Ziv7crmD`dsHZ{QE4Y4>pTC?sgPf?y|`R|^7kg>t(5F@-X z4ucJ*nV6h52sAXs1kyqRalxhrr}4&mXM&>j=ux4BoHpb?k1j$aoU*O84&eMB1ILP} diff --git a/front/dist/static/images/favicons/android-icon-96x96.png b/front/dist/static/images/favicons/android-icon-96x96.png index 43324e2c02b98a2a5230a59d167979addbef1c7f..1a5048088a7e9d12ee967cb01c045ceed11b4045 100644 GIT binary patch delta 6949 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 P-hjEu72{Wi?(zQv2}%3r delta 2675 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 NBH$gYXqMgy{{XbX*V+I8 diff --git a/front/dist/static/images/favicons/apple-icon-114x114.png b/front/dist/static/images/favicons/apple-icon-114x114.png index f205a3ada377bdab3e75beb06330727312702bef..0fe16ec58742918975ff08ee35af0bb63df5a7a0 100644 GIT binary patch delta 8710 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 diff --git a/front/dist/static/images/favicons/apple-icon-144x144.png b/front/dist/static/images/favicons/apple-icon-144x144.png index b0463804a94f2be528dc1a20b5d6b3a3b5ab996d..eefafe8d4852f9df83447e8d6e2e0baf2cfc085e 100644 GIT binary patch delta 12027 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 delta 3830 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 Jg{A}MKL7@B_@w{< diff --git a/front/dist/static/images/favicons/apple-icon-57x57.png b/front/dist/static/images/favicons/apple-icon-57x57.png index bd72841f5166b2a4211de6d9536a23deb5d2a060..e356d09ebd0945fc3ed2c733d058c73462b63b0b 100644 GIT binary patch delta 3433 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 C3xdV~ delta 1800 zcmZuwc{mh`9z8Rbv6C%puCWd?jKSEVtnn-%*(D6py(GL>+?Z05+pRE`lC6^HURD*=K9`u|9pS^zVrRgcg}bIIcGw>cuTIbhyZ~0C&_p6G~L-m zp0|ge^Cm$AHhBR82!Id)62g!cg#-yAL`_cgfIbQ6$H7X{4~A{ zq3b4M17K~8)^e!H;YKd@?!t0E)_=qLI7&`IR1m6isLqAID?SaO^fWepV`JeN-gV(m z9#&uAKm9ls2PPFv8qBHKv^Yk-KD zA7G&uRcB$Kh2j&~7(-zOgavUr37lgP5yYuPtdHVxEn)&-L4yzx3<{$5;@(wM{Rn9Z zh>PN4CiuTYRua-;*qFq7F4`;cPZq>Uh!4dF9yC>;rHZoCXsv*<92=_g_%w{g=UD2; zQXlFHp(G0xIV|^~>_-P-bB~`olEz(cAIUtV!Jun`?+?_y?7Ts zL{}m$GK-^JcY9BS+^m_Qlm?%Ba!zDEM=VLIYCfkuK}hfQl@C zJ)W0p8~pZY??UhO-OKUcS5$i{RqH$ZJR+Lwx{B+1KI~sN)-94U`~IlG(lV3M^~*(R z+R?;i5%jZF=sPidleDO9 zeo**klmDDbl4j+3>8Bmvc;6{6JaWDzLqNtOTI7({D^+Wj*7g1I9#w9~Jxj=!lf9d# z(abOW?rc$A@c6B`!P{jPiA7iD!dOaq9@&c`TMwL_8Le%eF1ZpG%3=o?`_8;5n=1nNNrjuHT#vftuo0e zPn}uH+miYR*XP>Z&Tf;auE$L+6UF$kg6<=jmAk~z-F?ZLme^Kas_7b7YULjOy-*{~ACeu*b7xQj5urB5NPbug8#|jq+N#WI} z<~=cnkblFs=ee}TP`bg#2V;3B{9+ugHio9__wJlFT`N#y+a;OZ^OjY&$skY8 zBpkLoqPiuO@y3rAmrnUZtN&8-yJz98M=4?a5-KZ3rTb|>CF=JL7L$WUCA8bN{Yzl~ z?DUxsu5C_2?9`IZ^8CG?H7>1NZwHqye$g~`duZ2IZ@VU*M#i6S^r)!|R$j-(Tq&W_ zd)}Jb#En@|FCID@`DKpz>noS_FDV@;x*uMdr7^`)=vk%QNzPbjItr(`43_U`7+OZrm!MXqOGHnqBj8yI)hH5Gih`yKRVOe#LSvuX-KDA)9HH;|KRYq zfuk)cqw@b%+Em5{$4l~yq`8#|)6$f|w4`Y@^mFz|x$XShU>s#`5*=e^Y0jiGSP>Q$ s(I%0mR`ke-m`Ene$|Ty-+$b*UkWpentaCxT?q(p|oV}dt9rkDb1r(LEB>(^b diff --git a/front/dist/static/images/favicons/apple-icon-60x60.png b/front/dist/static/images/favicons/apple-icon-60x60.png index 89238b40509ae1d3d36f364d2dd405a11c5c02e0..ca4616de04a6e694305794055b979ac264290c18 100644 GIT binary patch delta 3625 zcmV+^4%YFn5yBsk83+ad0027t*>aH~OMd_cVoOIv0RI600RN!9r;`8x010qNS#tmY zE+YT{E+YYWr9XB601Y)sL_t(&-tC&pj~&N#hrd(R-S^Im9Fn3q95RwjSrQ#Nf$flv z;v|R!7%-e<;YA=VCD?`oB+KMK2@GT!#y$!BH82Uh5Bw`|6Yyz)Hnr$pCB75D za9iyrh!UAi!1pB(gLFyaZ2^1I{UGotPyjt(ov7x`v0K1i;1OUW@lO*~JAbg%baqU3 zJBDvQ{nYS;rji6oV3{b{b^;Q(ZKuArQX1o68mE(hYh&#F3G76Az67kMF>9>| z0H@A>^uPg2`e+xpp1`(%r-2hho9!gYbcvE)0X`wB^5ejt0pB1>{W8%`Yl&$C)PCRy zaDb>uC9syp^!EdJY?T%f6@MrZSyHG})uMVRN$klq);nntFvfHgt^&)d+C%k^fM?SG z*OCU*q#`l^mJ}9HT_(F)?E6G@)er(kL=c$(<^-Npk$tFc5VhmK(|_0-?1Bw%3;2!K zf6kwL=i7X8;R3TWd$P$^F`J8dLW~?zYgfhEi`JN1s9yKZUF!`7tKCjVrzR(-@+>=? z8TpDaW{((qQL^keK&h%XtFpX)`SNA`^plS{`qa}L-nY-T^L&pHvkzs-Ef-#KhndFKX_ z=bhKy`Y*vdPQCwu{__uiP)<9yW{tU`dA6!qzHIXRy=b_Dsk?B2(GGReSdMW*tmH!2hn0?+RYp|;3j5f zych$jb!>M;d%i)879Emp&(F{A2yhO39r$hn9srCn=bGoa+AIqq;=T8jWogR6 zz*bddHYcC7LPUZw#v5xrpx(JWgkTfju-Rz()+WEIn&5q=swOR_h=?J^?nR>GJ41As z13(WQI)Ah+;HJ|uM6dd7;7d&=RYg@bgaFP!9#;3&8vt&%~odG!K>Pbukhl!ztTEYnc-g`tOs%;2(?>DcZ zN$nbi5H_#0FdHJ$1!hFVCX>^IVLZT9RW%m%&VQ8>5sWdEWr;~nsa}8@cnINvfvu{F z!C*jHmV{{g9;ig50)nbytu8VqvM$JWQ4SMdm=kAbj6Z9RFY?7v98g<`Isx_)C zOFEqnyL7-Nkw6YX|;YI1VYs%p^NCQ}3TM0MW;nBB{SYv~R@+YOMax~WCp zdw-mBR8>X4-)Arw;JvpZ($2E%k*TSv$BUv6Yi(adG&wa%POu_+@I_T!s|A?>iIoP-c^W6Xh~D8ABew{4bXOCsV#M2#`E zC$Ec~%fMSAvc4_g8niKnq9`bef-H+py??4IoO4@%-!EY29K+$wT1%_d+H{UUVT{?A z=XsuG*_?sdYUC~5+$uYcj^ z_2ll?Q`ca(n+LZWghoX26zeI=vi9WlJGr&?XuI7$sc{wF0T#BcmhLu*QG88@vlANU zo#s4}jZ1xZ&V{lpwcqcn_rCVxQWVABR;%^<@fGa>VW&N|6fuqW$!)xejo3>8e`T~^_=(qZB>0c zgs^0-&9W@p-)gmvXIb`wsnpKS6Bu7Q`xWe89tC>jYsqN%%Y{6#+fq67Z&~ z{)dQsOzd5+Pft(x+U@oXv6DJSZ1=Y6*T)7tTpiW-yYW6?3aZ*w)oZHyfrwn_^?L64 z=bz`sjT>!ZpZx2@GWRiJZ-0BU4j)UUYc<{u(1Qk>oR$%h0+_JYPEAfuP8>aYw70yx z?1?)a-vIuG*cvVp;OnH`*H{v+y<+`)6tLX{yG@#EM5M6R&a~U@12Z!-%UPCny!UbH(FL#LBrQtf!sg+{`u2s0H&JR+eO*0x=03#xkd7dAfoSZz?YJar~V@wa|h{zs| zyCIWAbL|mx=<~pWh^*XmSb7j(httOqC8!XqrTs-w950HZFvhHiNF^dY;`Yo}Rdtfs zguDs73H*w@T}InDFjkL|Q}voab6 zJF0tfw{NJbSJi$9VHH?W)t+-M^!xpyEXxgR?XQh7zihQy%YUj`?`8W|tHp^ECw7*2 z>=vo&7Ld-laka>)>YDfdVhG{9s^0S6yRs~cUa!~l-oM%F^-do+9>Cm6a9u$}6vI z`Mw!7r`-lQ9Dh^qR)CD+Z7xLe!Xbpvuc~TsZEfvbr_(trB4@0%r;RaZvMjqgF)S>h?Pb$F5qF?Ykx|zSw;>!r}!e41Go}G=xuCltSv1q<^6vDfcO6B&>rj^QXWnicCwE=9GZ+VVvOeZ^-?LO+ge^gbcG#(4Q!)rIo#@*Od zOXNi4mNDi$a9%_%8e?v%YTtVw?qz)V9e?rl)mLBT%$YNsJb7}eD2m5K4 zC6%WjIu1>iGdOn3kO{eEL(gBMK9W(2^rWgvy=TJ=tufqjD?EnRA}=Pk(&R`+VQ?z0do{@B8kn*HSJhONaoF*{x@t ztKrBeK6E+4wigZvfG7c?01+S&Kp;T4rmlnoCisg9)VD#L03rdBqS&hmD^naWg}E^( zQXm0hL}>58emcYmIQcDJ_u)++{^&ud2PBBtN=8{076!1;kEeG)*M$TLXa~kVoSb2gdUpQGK>pS%Pg3WP!9z{zj(xPEy0&yZpL|i<}hu{S^ zrV-0Qqz_(p!_)w|33&YwQ}-~{hUt4q1IiJ}xNk3dWW=`n~2fVe0m#gM^+ zgeZ<$;Y*mZi=!|ZOHbh80BJE?;=`SVZL*M+gqk8Qr(yXC0$ia;249K45z#xEs2@}e0ql3ONjD=i5{E} zA~6g@b%^i*g^XV=V)-dVh3sYF>jHTh91OMjX#5-G$+(%1 zjVXK@N6jS&W+8ZvXg_4dVto=8#)uC=d?-!_gJB3Z3unS`CKM6AP*nuW5(#054Fb~$ zc1*;DKp+sXV%}x^_oM?HS$1#T@1^Dl8%eIi@fe{x{I9<14L<;gxbhF#9b`LnzkT+H z?}+twaqewtKkF`ASyz{>N?)aweNDTJS%y5oDMxm(5Vml8plZYjfmZEy_zp`epn@UI5bS~gR~ z__nlTC->%$%E3x{H3g)7{5!w-RO%bCKU9(BuI&$RzFYOph_b%p@mkLrX2a{%9!tx$ zXVvLaNlU8#jtdt2kkjfGI#r>^{_YyFIFtG4+oGtx_FZ0&Nli9mIg!&kc5M6EMzspt z%F?50X{y}ahochIj9yvt?21G-FI%XxDJ^!x)_#K2#R0F;i0Oo?TUYtPwKHdv#aQDL zcOrk?EIX*Wk(|=1!U|u!(y?7u@@pga^W}-IaYf$E-H-igG+O7zj*fsriYAA{VdaoD z{P*cKMtNn&U8-E~){VPqHU|-nAXSzQRoW_IKcy~HLC1-1k(H;j=Q_k`c^2B{GSqL> zIu49n8!R#pU*17<66K@+GOK<5gVNsq9TOv$|&3Wot z6FGGz(F?;8vj(jKetSf#;6-`2w5Ijo9_P~eH(iwZtF4qWmW*KCer>UR_q^gVz1Y?{ zQG)dR^Pgr$ug=ltw#+(=G|e1dolXd4Z{5Y&OuaD{NLS>q+nG@FZ6b3j27O&RJ}yn3 z7JH#?RoPKH>lzY&zf?XnDl>gOY3|3v*_|TEo-$df?Ngh`;9H7(FbxZ+qH8KkCFhEe zB&E)|>Nzy?R5&3&4F`~8_1L;HYWJgK+%oILZDRtD9M?bheczEnr-OG?%M9~eLeX?(E?1&sR8~c0vLhjv>>LLQ79+Uh#L`X TpWmV*%*G*mC%YOOzjOZqfQGnM diff --git a/front/dist/static/images/favicons/apple-icon-72x72.png b/front/dist/static/images/favicons/apple-icon-72x72.png index 9ae8c47aef9accdc911bf95d20fbd09ee867b86e..910ad552c889adfaaf06a69feedb7c5061f6695e 100644 GIT binary patch delta 4620 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 delta 2023 zcmZ{lX*?5*1IO7B8**l&$=SpjGt5vq7h{_H_-u|Llxu{RmCaB&dRj)VVj?QnXyh!> z;i@EODMu*LBY#39|L4W?_IdIBd|!M&pWoYGiS|Qz?q!yUy@<#^oa_xhAtEA%B-&cJ zGv0qM@{Kq^P6ZD_Q4NfX_@Ke*gFx=e{8 zSMFITYwS%t?IMCYKc&Y;I`+%v8XX2N3JcpnkqG!H| zmnPJ)-J!)70L33gu>885!SnkPlEiKDe(y9xN2}R2Z=Mb)ed;HQt50u>Uu-e{w67bG0VJj{U^5ysaEL;JrhfO$(_ zgoFO>oBi#e)Gxx1x_39IcU6S00R^Fnk@vR(!)>{#@!_;ZIq&ztNOW$lMWYY-LksIW zT?k9s0>5}Sv9Yb)!*N=o^@lXLRk_|Q=f~?tP{j_Gq;^osEK-AnXy;Rnp7*%0;An%MA$&v~#t&7cOh{Vj#i2Qy37wkKEZJk%tE{+?YMJLZBY(Ts1ent!L3;lE=d1NFJFQXr zU;?wVJOdK9%tiSyp59a;2S*$q@OSya%v3t#w(^{0g%g$U|bs>toz^ajW8 zy)k?Y=WImO8>7N^S?yDwzsY5)c`f2!CUmPVGcHXkZ{2B9Y_6nSLA1CHc+f+|NSR8B zIb<%U&79VMGT&5X;nnH|!BG9+cH`hj2r6%%_A&|p``cGiwOzEy>1~K{?ojJ!7GF%2 z?a_ZO_QeU%s{*io^oWzIdx09i1+wty3J)$;U*W9-RJ44+8dX}+CCyVbKZ;JI`p85r zr7D@ZBy6{TItpu6E3EA7`i1HEnQ+*?tMs!V2!{CnPFsCnt%R?{%qy>%nUP@}&65l# zcXtx-=F{_)l2%`Nnf0rTSd^V}sqYvZX@Kk{a|@0@N!YNA!uk zS?{dpjWiZMvOA9%u!du7%ESM2r3N$2e!R^4l_?^0rpX$;CT> zIvFBq($$~%jIz+7DNz8O8lkvuR_&QJ1>{6qS!>TpZ+5M^(H9+7q3Y~|CNrH@DzoSH zImKyGNnuR!@e)-R8R6)7g&GQ8-t1Ap18 z_Y*fUP0BdB2F*8?Ul`bbQ=9!Z2G2azPhx`a0P;0xe&z#Lw|-AA9HGJoFQ^wq_(O!J zl3UL44{MbjNj)@{Cc5H{vJ*QEx|^zqn8#uX5(@zIU^~Kwo1RYUQ`coUUSMS`$PLde z&e=|utV#lgT0j?C@w#T;X^$DM!4TbTKa#khZ%ZrV$a6vyKr1Q^)iDN-XN_x|fz;Tv z*eejfjN+=;Q`+=%{<2!gp3-rX{4<4ZLr$Jsa_)WXtTkxk`&$?3M64q|t2%_)3(8F- zQD5iaMisn5Q9=Pt!~N5xWdJF_!4Y+_X6s>w#ssH=vxllgj@waWg-wR0)y zbrrmx{LW`z=Q_1s4-fB?;%E%29Rd8SJs@MsQolQoG|sD&g(+ju7#td7>W;yg85o&i z@hA+&41@8A$*|^4|7X@Ziv7crmD`dsHZ{QE4Y4>pTC?sgPf?y|`R|^7kg>t(5F@-X z4ucJ*nV6h52sAXs1kyqRalxhrr}4&mXM&>j=ux4BoHpb?k1j$aoU*O84&eMB1ILP} diff --git a/front/dist/static/images/favicons/apple-icon-76x76.png b/front/dist/static/images/favicons/apple-icon-76x76.png index fbd0c29c2005bd9c8e541205a36357de5dca4ff1..f681020df642ee19e80fb288fae8f0cf841404c7 100644 GIT binary patch delta 5010 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 KEW2s{?0*2`Voap~ delta 2174 zcmaKtX*AT00*41qOTQ zC8M&vG1(KL&AvowUhCV3d(J)g!@VDV=lS%U=i{$brA#yklk%Nt=r%b*&VC7w!!&)V1S$rSOC_<#wMTA%HOj3&y2<$>8GAjeQkvDk~@~ zoQyG>nFn#wXo6^{oO(Nmr;Ym#p5vUIxGb-nERpVRup1dwql^0$N~xe!v=%(6KPu1c zoz-rrlzDZQvNT<$9H;)OJk5KYnO3-qQuv6a~-+7 zA||%6e=IZwaY%4tWATeTNg$C7IWV8eRGR4R&>)Y*aV?e3;nuZ9w(vJsOZbo7G4Yz% zCz{m!e1)6|PVc~k^4l51lk9u3XpW)cgsicyTHhMkyo48utoNBHLZW0FNyzi=(S5^I zpxU)pJn~ymef}JUx5P32mvP*1cmlqzk@g28=JZ-LFQkFcD4 zRbJJbkVYf8d@FaxDXw(=eR#Lj=F3Nq*+{Abk$~7+c;ojyLRQC9)$s)mPG?N3uf#t3 z7tq#_bW21@J;4VOA?}TMzNa$9Kyg>7$N)y%>+2gkh?`ID0?O~wt04qz)PWslB&UgJ zusFEJPrn z0y`3Shj(!C5k)gJ3_W?)#1zGIXhk?cUN4TXuAa#Fl;b6h$(@-NskB&~>>j+_!;-CA z;ZcCq$NdWLPSj*Cg;3ess}q6_%L0W39Ypa8(a?x){!5Gn$Qqu@-$$xpRQtH`1s6fJ z&_Df7vPXNC6O(AZe2lLqe|?B8!j7nMMvXV&+Qw^tK%3XEVLOn@e%WWs>pSyU5cl`O zQ*9iOp{rlAu!~uU{m<~hC7Lq8oi@XnR~gn_-!=R&En2{W8ju*zU3(QB81dOs8?njfQk{|=*((q0lVpTx8Ad;JU|on#xx#t}p`$>~o4=m=p@ZMQgPdMxKgg_M ze}FMfoC_qG4LvPZr}=B38f{S$^G*}jn;7kBOqjLx-)x}#QelI@(k=QqO1Dr&>?Soa z!Z=O~)$BnXc8m1oF>KN+u5~2QI0}v6#`lRl9=f`gBz!Juw2ut=MC{1RRWuULM03Z6e?ieGHG4~Zx8Xsr*p^SUpO?mt_c@*fs6e0TmA6iU&6M1JgoYmA|&?t&O=RUJ;?DvrOgrj z^VZC2l*pFI2f_zWmv(RN!ap6IFxFF3-~+=GU1ugd3SP3o2f&Hh)cKD>9jjx3N|#RV zp)QZhb-nLXVK(m1@60lM_0nbxBix&lggq^vhwg4v0xqm(H!%WwZvPX4y)D(|E`f>` zdG_E+MR5pC`A6xSzhI)N8{!=KE*)A_FvhC!g;+gXEWVwl!Zf?`>S_Q8J+$j=`ZjU& z23f#pJlkb4CO_BFuF;-(Yftc~wHAsH{c&_fjNvFpL+NW7Y3)C|*|b_@hgFn#IObg9 zVWQacls;4yt9V#YI-wRgkzTJ<89ynL8^7$+rb~GEk?+$WYjY{|*(l=x4l zRY~*KsNikQuVuo?lUU%`L*wJ_Py`Au4{&^Dhee&4B%k`fq0luyb7g0f-1x0>~VJ)2A+a+&Y7&#}|Q=fv*D#U1l4PjvRE1q(UDAPX`Sqcx3#D&wmWN zsCJIKVxu;5BB-$#Xr}vIg01C1Iw0SGtm`uzXTCJVknq_e5dn5u05SR;83~PB?7i4v z0QJp7AH7}20ZX7ehz(?Vt7aRzCtKB=H*D#2R3MmPRHJc7TUP_ldQ%kVnzsvH*^SF!!Fh)p!)sz(DPFeufU86YqF;KLN~>X4RTl>4eWqh^MTO{3S| znlK~~&lykx-62A5c>=H2Fnq?%nu6tS$scb?)J~MFPd11Suw z3YZkGiLil8t<`$I3ViuB2h`!C-gu_@d)Q#v7FJqf$U+r!QuvHq^MI^;UnG3U_#NTr2TEa7%w3<0}F zhWIW}^yV-HFRFkTg9k3*A%qyfDYH{G{xp)RlXE{!Odh={6g0!wsn2hVh{}3%5h|6p2|dL=jk`a4i^vfflszk9_#Q#N zG!-U4O~C)k_A&E?1Cp%Wd_RxvHp=gd$X81ZH@#J)KgpHOQpanDPr3Q8N3bEt`d{D% zHyTlb-m7m7JL+9djG%m9^L`+TQE3nnVy7wAjs(dTYJv^lgl$~JwD(JY7oajsMlO!8 zy{Xs8p2{`DpMY8cw|ZMck%Bcy$fACSFT|e;EhVM)d8@Y>debs z-oI%Dg=%D;Z|+f?2~j}Hmd^=8-BkczlPPZLi{>7t)d%84$Kb%v9wm4S&?S$cg|`%8 zWTTqlwnHvG%EcuKQo?{|Y6mylBb9>MkiQ3rxIv?b54jnB+l}twH__Fk1~#$HWu!UD zzH8*xBv!b8{Qu68JyFCE-uH9;i#yf-F(7h`WbjiqF4}Kvve&Y{UFlBm2ZuX}yWRWB zMHK{GYrd_8YTUcdvFAsJw{=qmC9J?SQ&&y8}!LbeLY?s7A$<` zU{6bgp7e2OpDBW5;f4*dfkdiC2&&LnGWJwxy2C>#~dxNlqiRy&)bG&u~%vyZCXn=?H~}QR&!J2}Jy~BnTSUWLjyZWMGC`kc2*c zn#g3H{rV_zSHf-aIYj-OvKBq`R*8a#8v`x!ed`H8lemY>VhseN|1AuWb1quLV3K!o z$NU%ApovX}noxs8Z%}GLW?>^2`=M`Rl!)Z4Lq0OJnmX=UJ<;VWN9ar&lXl?GG|Ba~ zFne9LK4M2QSc7Yu{6K@C)RG5gi{_R#-fvvWh$YI*8v-0plAEAKIZ#SQ+`p&g+=v!d zJT#!@h1t+GQAEgqY+nSXz!F#j4K^L`+p^4I-OUgvr^V>3s-z#WPz$Mzz#6UG_?YF` z!9iWcUH7(u#`EH5P6#y{2vr(}j@q(bg&Bf^4^_*B^T(rzqg$bF^9M4bQKrkay!yrv zNzb6@bb~GU8D`+ffX5*pRe~d8#ZV|Z9thmOR(v~3na;YukRoDON@G&H zWynDR?;a%;AcANuOL;gFopoJBiZp2l5+g1G7&Rd|+moy_^ncU%($>`#qF01aYN&rk z-4KJ+V6pjvtkxiWY;p8o5v6Wx`;fCCCX_B?H`;%2EvEck(D-_Vv>gJCj!5%oSbnx=Vf@AGpVgPO{15#sN0uh9 z?5^aUb>t-q4Y-Ezm?VZj1mn>tTWOGsajL+N{!Y^SZ(KjgOC)&ASq!z=Ip0Um-PpD` z9}!q>fM6egQ z=N&B(5lm)Bc>nVy`bK|&SQGE+9uqB{6{mQQZ(1ZKB_X|lFH&;mg?Xh( z+Lty=^EiiKaB-%bGZecP%jRy*tzKG!Dd)@Ou&Fec6*o*FIlwY-t_~^`@z&C}$lfpw zl#iYuLOiZHj?`F>kd6n!L`zFl$(wa*5OlUPIo2`c=Nx*9(r%F>a!c zhBnO5NC5+`0MPmLcy}$;d1^za!J7P)<3l1}+t^psA{mdKPda1EuL_UI8LL<#)Jsxt z%z}5ZK7r70Xm!ka=A6PR8wMzNPP513;%<1KR*y`nO~nK5uNRK@1da{uK#gQ!lrt10 z-UJN{_g^enp^q)Tn3vsO6vb)coDz%P!GA_-3p3W?^Z`*_=zKw3SYeT%g5XFp2E*%z zs0cUtZ%}i2*z4Em`a$0Pbq3$-2DXa0qJO&?&`9~ddu#%3hDO`l?}4X%JFlm1v@F|< z--broQKUmeL6H%pkm#0SK|9=n;D}U)%%Ev(4iAh17Aza?f!WFY(Kd7V&Oo|+hv6R$ z;GF5q40!s(^thFzLFJ!n6y13}(`3LJ^yDGBp-AsH_KB5PP>JYEN?p_tIDs)Ay#!?O zq5vJH&g=FcHJBTe4LYaU`U4bLfr>jMs?1_IMhe)^{`6$i(r0Nr-Z0%s-Q#tQ>KjC- zY2+?ZOqsGRrDJWy9-LM`94WGW@cLj$r@`iM1gv$%g!Q^57xioIL3PR|g6EJVFbvoX zQDypc&&$kOZFkm&w^6B4_J5kP1C3E$*Z+*I4dsX~(Ero##?L$c>C*_kq_0H)7RAR? ze$X6a!o%?2jOFj1<9K0cUp%xO3UMmmR*{k#YJDal9cGjmf^-qV1fd={g`YlOU?-dA ze*%644bqQ{7QV98CF^&1oyVPbzpL2)XV z`s_E`M=3PlLz|}wa@PPqKOKAb1BAP1ARtErQpaY6N@DDv+>CbkN(zSG{W?X6yu6}; zRA|eqsyTe78DM$y)=-=Ci~YNo9?r>`MulWi(<+>X?+c8D|A4EwPIX%{c}H*lD&O4i zP6rV3?PD}SHtSHY2ib}*wG7fvytIo9GK)oj5Ldo?U!WJMJp$7z%kIo)4rVNH2Lm}l z(;S>0s5vxpd#^*@T%_Rf)i(^J*Rc=(aeOEKbe^>Fl)8LxW`@Nir%4C2NZB$vz3v3d2<3thC{>P3Vswf7YL3 zUbD=d9o)0=z@P0_u}r*6Qxp{SY8gP`BL07}pdiJ;BPs$#Nz4kvZPo_%BxYWvzoeXo ztoftwvA%L?y^kOZ)vlK~pt#|sJW&Oi^Is?k=#&dzvq$FaAtej%o+R*`TNgDG059Xr*4hJ2!xru@ji7YQw z3&}#?)u*W2jtFItzi)k0=lF^WFY1T=+kFkzKkW|>r;`u9wn8+niLBXQDeZbu2o!s*UAZ0~Gsdy%`0aH*&_0;0Uhi%FqJQ$@%ljE-lMrYA9Gr9j8_wpN^7m!- zyt+caqrwamSPQf{UNIG#mN9!L;Dzyq-G#IH#z_g%zqxcg*k=GklHMsLPTTgP#1;8o z9gbgL&f+dNa@Azghic=>N31s($=8i7_Wn zqjZRHXilzX8PlpqdH@y$L{{ip>z4*E$J9V8w^i77lv8sF2R7$d9`2$&fzz{_$KG&Z zYCLZ~np1P3jdib>$q&Ox?fx-WMHK3+;xw@d_~Aoga_k3{z!*7*DPSMk3e#d-fU^28?|d?DH(ddV}n<88v5^F6bdEJ z$RgjM@CRc(ZLdDK2vNi)9RWLHf7zsNwR}!D`NLo^mD(v4c#bq1_J_opnJN?h7zHN3 z$KIzGA>Cbfs&t!D_qWpiN5viS;x~i9n>gS&#QO2R<)y74j~=JhNS!&`uLLHLZk_gP zq8y#Xszfd${DDnNpQBv=>uY|=t9q&OfZKAj-{Em|9EBu9zy&@hRC9ti=zA{OGWVDs zLEK^#u-y9BiW)Uy^9M`UzP8O1^DVcUj?eWmW9)#H&-0CHf4Z*qIXNv1xH&fv@V#Zu z0&d^e`JBk6*x5Of;aZJM@d@hhCDxBx3RyNZY22=S9ws2X=zh5S5fV;#vb)Z7v74iK zyWSgq`S@@Lyo2L^agx^zH$Q-j>iWFL;m-BH?RPVg(#Gw* zhN?4$`c~$#u7fiLYPbwg=JzVFzTlX+74PuO~*D-s?@%bpkC^Pc=J=ksnk+Md?Kl|^al&T-S> zm@I2i5_dGJBBA?e55%fh*lRf3bfqp0?Z3FY92yQ^1dK0-OHSM(ApV{vi6`sd$gj_C2K|Qxam#|9!X%Iolb(I6Wu1v9xe95UtP|)=o5(7}6)iNdBbY z@U1EB4dKyA_m}Vw&*zlX>$yU?EA$HMHk9{Ll|nuWbYo>rIIDzJ?t(Pk;^W#Hu*jlh z04kKYGSmgAu^bOr*+7vqUsGf=i-aif_^4v1A6MuqpKs1-cZjvCTVj>EMv|YT9_x6{ zZzZ^P?`QRa&F5p}$U0>C>t!AGC4u(YOY!(3Kebr{)z;m<&ttxFcS`v>Jhc8g`}yD} zBM1(cb>_|UuLuaH-GqOY-x!lehw`KXxF%I()@Mr#bwcQ@8X)nNMUA4XBf?Ai_UOsS z0NWV;He)x5CA^QH@dCCj>Xu^89S@jz-LNk0EBUG7Qhcs8ZIlz=TwNvge?KZJKRf%X z&y(^hEFEPkid{K*OdtmjBN;E;fsbx)-8%8p<>jcC%Xm>pP{WL22LAe@9)1ZNFp^th zf%4jz9Jhw+*4oeuxBrV=MD@p(whiRtQE*TV%XqU$9Hb$X0FqAC~EduY;Ug1*U$1pih;zh zS&3EZVic0FQ@quS*oR0$1>~#V09x!uWKppw=?3rRMSp$}rm_h+ff2GM$t2p$P+3(r zU^T-ZsH)@(8b2C?ss+032f^}L*G#f~E}S%E8!$($)>j*vW)Sv@CMMU{L`h6HB}V-*KzNZx87U9J zc)iVWUtlaF9B+<-jT3jutH~Xm&%%^UPO}1-Q#aEsk$G*MZ<;ncdyLFc z-qAIpG}-brs$vQ|N&B}iC;tvrpb1d>4(H`aJTo@F0+W6{{WlFHr6pF#2~OpC1M+i{ zb}W**b?!fljZf0-hgijF00lb-HoYm^XNsn=pqig};F%Gr^DO4vE7m}YlZV_$td-NQ zfc!aM1L|=bULB+AQA7BTnJ5;1L2qcn)2xlIM`J>=TlQFvxywVuWrEu^* z&!yWa?!mu3a%I8}Ka-2NC>;}0iUI=Jq&xLY>HmG(da*gJ0CJsI0oHGEg_8csnRF?P zH@hAZIu@g=UWCXs8=e#1Kec1!6M0PZJhbbHFrX9IqVHYdL64N((4W&83S_{`mv+d| z$ZqbsJ&meoyU!_xbo}LhzD@ntWHwYc*xHtzO{MOP;R`q^%_;Hgpqqb8q?Z|YtNjWs z9f<*T9eKgL9)i$WKmqh81tGr-V-R%J^Rd=n{Dvb0GZBv|fIBH>}eTz#WP>^|BE8uWr%v^{}G~<-VJ+` z%h6@X!Js(~fIf31wZFibQYVvbKAvjE*NyO5PDPN?aSZ#0Z5ITog504vKmUA&`g58y zpQZ;P|rKY^LSRRXv|d5qU=KwmDeD2PkY`%iV|_Ls(qR!`5I zv!aexe1dsnIS1JtbD>g;S(o9bSp$=xa!HSa^(YEp>na+m`2`<^5nYaig1&8q7nuDAfsdKsp4*$z=T{ljj0kMC$m+LP69o zaLYL7S7o!wqfxyWY~5;SRz9wD@h|t$8?C8A>$v@0UG?Dq%w`#V)Nf!kW>WoUDx4oZ zf`j=kD7GyV<^D!kRm%&QQ|90BbXqrGk>3>q%0nmmPkaS%6YkMZh}{a`Z=hOR+{vB^ z!z)h|fpf*{3$v#S>Vxkcf`NV?C`cDdw;DXM5f}00SQ{f`W2iENCKTBewRhkyldus# ztC-!rbcK<#%?Ygh_ZZc}r!yQfeuX6PN^d@j$-e6+!7QN5PfiQ zrC;X*gLaFQ`P>+O+$en(SbOpQIrsE{r}=CJ!(CG>Xy#hzC6Nb8H*H*w5_5~YpmkNBXz5xOMj`o+p$d+_a@CN>ja{sSr=qor zV6(<}uwmcGOl_S1dwW}O)GH;u3@>&1{KiJloW0xg-E^Zd&mJ4BHSLL_`;Y0syePM{ z|H73p6rirytJXiqPLO0pB3O^FeolrpgmfPGWffHXOWK`;B~nl zU(*I}8X(fwZNl&g-Q26PML)g#=(}*5Rf>>0E@~LqlwNXBF5(=0{O@{#8Al3xAyK8r zMvA$dhf-whf}#YaKJ`?1fdO!Yh@MpkosR0;9$1YWE~e6=e3PSYIv@&ZwGHB1LWc|z zf~6P>-g2a%4kc?-LMRJKI0|2)=8LX@?R^U0<4X#~cgnLtc1gW&RsNwm$#w~!*o7}G z_BQ(0j@=S-_SH&GY*-K`m|+g(y)4v*4oBGUHpz0xZ#l3VxRAZb#s(Tbb1802hiYJ5 z?jI4R)hvh}oTh-K&1$y==tgP3$>{-2uZjQ5i2Ke3JMHZ3*tn&;3Ei_B6=yDhKw?w0 zIV)fJYL#fJ%tzdXw_tYs_&M6qHOYD>teT9z+uyzM;b7q8x>7^C+^$vvuF|z`}HZ$0IwRKL*qBA9zy0k`__ZXKvyo&mXaz z6kvy6d7|{V7_vPzWn@^zulAlC;21;(Bv~`@`xe#J0da2mDcTv@4kgK%=tC}0euae} zwey14dBN^P0m}mqijNDVke{Gze)rQW;OXjmVYZ{OQKLE()arP1awEJ&7%9E-TOMQq zRhxB0=wUO!Zh5v`1W7)G<`3T0JZ;)FIwr1^$a~|*OJQT>ANvF`I&hJacI2V`(aYz~ zGs0p3xPCxK+HtP(1kWgq6&8-+W_OttkCc*MQ2fhf&s&S)PN|{oRpmmS1i=iQ_bVyr z#Dp`f*51GJ2~S-%b+Gf;o(Aht1kKDf1H@&kc}p<(ql>mu5l;AtxT}*hD-%>C*#tjx zWkI;p<>te;6Kn`{KDGh@?Ka-G6&+-#yJCSr?dZHP8WL@4V6wOSJyY;?$MI4YUM)w< zK~uS(m171mr=}w*P8I&h)X)>rbrH%}l+*u$r$w`v3gh!cVZ-w$);w+%6!ND(z6)*om$;8|ECX{Nkw1gIjx>BN(akR0O4DJDNzXA5bL zRSKR$co5tTS-JV<^sdq9{=RB;A)Z;X>635RL0cu52}o;pU#^$-k`!e#e*N~H+zY+F zFLT5rOVBDeRnj;zXmopLVk&$+!UD*P*k0Mn^j(I^wcW$NvEOoBKvAX)TVX{P7tc_RC_D%ZGGu%Pjt36A_)N|0PVHq>ZVf z1GCvHKRBXDr4&s>Rr4=E-^B|W8?EE>X$Cd>7m7+(ST}g=w{CjWIXNz4tpf8imujhH zd$-$rVICM^d+$!I$~DP#qWTzQM(1?!zUiCHb-(C48kUY;nG`8%{kR_=!HO8-eZ(lW zVTo=*mQzQ1*bAZ<53Yqi4brw8Hp8W7)b92oEQlGGZT0QO+QxROeQhzV^6gV&)zU7c z_CgLsSc8vgyU$?fP?7dtB4AP)E@8RN5twLl@Gdx7C$Saw+4S=o>1LJzYr~);nDEW) zgMYS*lkkb!QFH8Z>q3k2>cR%)^kobIG+zY29t~Fd?$oa^xnYK?`Z_94hD%!j-Zvuj z2V_c!(uR{@DaU3~7VClvX>)FV$@oEL1aBfUcz%VM=tS{DNK8bJJkVYkk@c~9!)sZf zYaI2zChdDtvFd~7gQpR3cTDp2GT4Oe!(WxY_mgN;PVw#k<#2)wIZ|$R!iO|Utir5E zw2CeN&B}uON8?SlhlMfq^>#ik*N4m!*6K-$46aMYKa{tFVbsWtjE2+{?YgeKw|r~> z*E{G5#rPV|6_3_9D$pN03gQoL%#fH}cBegB?!J&s^E8cLGV2|6l&BLFTwKdeaSyOv zYozSTGGTdSZzO|ci+o+j>h@8bL$As|1AS6*^MZOY!SW>|zRMkEg=n@#+T2Ko*U+uw z3sT1&7dFi3!&Pm09=w^71G`)mV3tm08}V%gMl9Q1p=J>+fIF5QgbFelm?3CO@bfda zX#HL!CID|dn?#28M zmbJJD`!}#U#Fyl=@${C{7w8)asQDk!YeH6PIJQ_)7w6@ZR357>wrQlDD@_E>5;MqW z7G4XE-wR*u0Pg58(A)A6_CK=kh}|H?rG(#~aiPl;ZA>U#x84^kTQ%6iI2rlN%p)vw z%=Y||_wz)ZI<%@^dH>-|y%6MG-?$uq_~=k6VPT7Hl^P$48VD&)#l%kwelBJhDy5%i zd@34Nei`!m^+cBQukm#nHzlh4(kMOk3lFfNICUNvz`6Yg~H!o*8Zm@vlRt4bt#p;XyZ?;0-O>?7X}}ZZWD&Q!vR(|Eylx4W{_pdluB*5e2@m)ck96?-lu*7^E0L zCQ?7cGhD~jR!MINPhnOTrNEmKQVUm3j7iZBoylzHK}c6o!46k@?G5BaAH$5)K#S?Z zo}clm$%Hw&)?G!&R-Acp-cwAoW|+JVX3=X0pyGl9TDmThj8k@jmxDM}MB=jAgy4!=9ULfK#YiJYrHQj1%+obT#~>RD8|BP2=>F&GJ-)&h2(^{SF>|!N$E4E|abvY_a|o?SM1o#V>|)mk$I9PO z5Q8$2sJM9Fq|&A#RBx0T9l6dvMRgo)N?G5hcm zsTM0V9=F>v!>mASkgHG)7O@<-~Xl@s4ayX3d9 zo*3FR;X1RRAahn4`a7HOrU*+@5eVXgo5PR)q?X8pR*1F&wxO+_d12+JES;dlV zpp&e%zO7v@CFD7_R@R(Tpp2!6Kr+BIaZvUT4kpd{0{foW3(G=95R<*WSGJ&hi75o_ z&gvgjWBLkJRhYY0luZqHy0<#aT_moWX8f7(Y;>PScio871K|`VKO6v7@j~jvUd0}4X!diUC5}Kz3VU49Jvw{QRiVK7zC*g>B5t& zlQkdB3O*urZ&4tm%87I92qlA5h#=fWK`rC;SwjF7B)5Bp^6b}(CN~WG5mdP9mqo^# zSQ(0i8rg%N5|_D4JFs(_F5K%043RC<$Yx{_@telrh~aMYE`wAcL0d)8eZ%RIGB8N- z9>uur3FMI&4VHTYf+uXH5KHfq7QgYu$m5Ctinq*o%LJBI>L4AZhFW*9|fg;W^Aj`?3N>oGg#KF5N znvKPGr^laU?4PPdnh90e{kj&3x~2@jPZ;vr)n_RGA_3lKT8hxLhNB0$8^Z7J$DhQ3 zJ)>1^)9DP52s#2}PX7sv{zDEba=bYG#8VI-yMQBW3_4?XakE3gZ!G%4*=~wFW zpwOqe;Q%Lx5gc*W%osi%dUnD)?*H&MrFN%r>odsvPTCQ6p@9fdmad)%wW3Aq1pbh8 zNj%+Q0T*0g-y#=1A$xk8MoxaKB=yOUPr{uC=G;iq)gBg|-U}3KRnRV>)V=1>!9m7v z2VIEt(783n@n?K0g2}7(_$U5A&$Z@ztcGmfAID50TdP-tbwv%4d_(#Yk^QsjYNpnwqWxxkj87aP49o6@K9)W%OWWz*6S!-K4A0? z?{>_yLvEDo^ht6F@0gATvLvSlT1S0mOT2{S)j+5wCkl9NVU*@3v3bJGasJO)<+Xmu zbzPbVi224iUMiGRE0LoR!*DOiOfse8x}P_d9=NY%fd)K1TsfuMq}Wt*scw1m{H6iI z5Lo_LYmjFH;c_2hS@ks5`sgMJVUL~QvY_oZ2zN@0TGXY%&mOesCykKbq9*@v{5eN5 z5)~i$SQUx2bQ>6-a|JxdXN_4oS$o)_(kXYRkv$5B(Vtp&-n2se4uO2u1A<60AtfYB zYz1-Y`n~4gmP3;r{6@dpOp6%zt6ONpPBkT zv&YWepfDL>D`QPb11Useg&~x9izXlrFaGmW(8m`&e;Xd^>eRNZ#16}2AFJ~FHPYdZ zc|g^@Hl(dA zfD2N?H2GtpP%rx774cFt7P=65SM;f}?>MR$GvF~X*@RCEdWA`l0IZFqZ7C;8KTliQ z1H2AeEI+;|ypbiI>=ntIsAE>=fjv9C8d3Z514<`fSm&Yb@Rz1g#ScGGodouI9sytd z!3W;SIM?0Uu=1JIYaILxV8&;+DWQ7)%kyykJKA;-{;1M#t7Xgb9K+rpxeJFU>zRe* z8egIehFiV$>5d%(`M+~XfP23Cd|;7eKi{~z;Z1s~+Al2fYbP*5L4~7qQOCaW2NST~ z0$8=^OlMQBpa{$V+M~v7>5s+de1n`UEk?-r?AQ|pM=1XHU0NXvc#wMZCqMLiK#)R@ zCo}`*D+jYshrSwr)^^ZWVF_8HN0xVSiD9Mk(IRReHylMT(RjYS<}9Qi!FK*VDYc}1NH$NIevG%;A0 ztYqd!0Gb$Yv;dGGY9D=J=U815wgkQOJ?!HmFFmm76Y;~(2fJ(Ud0Vixeb2X(*C-Zd z3Kk0aOpzrkW1%k&T5laq=q_6KzGnt4oO7tNGueP8W@lAON7FcswcGvP@5bP83m2e$ zg$Y?~V}j_wlahji>-f5YTJFz!yJCP~En}7b?tny+4M2Hy1ze1Lb*36p+qpxpZ~qCt zQp@Y=6yEBDty$PyBF*f3!Uf}3(QgLnZa9&>{c|+L52+vu?>-<JJ1_cP#;570>H=Rmqt2m6Ma0q*F(?n!E0STB!lUJ4aUI*4*!v^GV;8Qq zxOKh2@PrFtkPfI!CPJmaZi*#Y#XwOS`ZkLVYN806zDh%~amr?@vQ)LN$$c23OXaXoX*VGwBHfNN?y% zLe{tRZ9$hG1GonxEKeS;-Hs(?9;?XRzep6dG1{5R{EY?h|H=uX+PjIl?hq~zXEBF{HtvymeRq3=8}TwtL0!Ukd#ql z*f3l_VMBbbZ_F%Il0;rhy;w)w`xO1|?ry3mYaIJfklmB^Z%{Pc#feC#b>nN#YGWvO z%34j%=QnEhSJS5UZ(+@(j7X%6GoaNzWt5N#l7(wGFT^BUw`f{I0(0K5@(rx@5=!;e z+l^C{lqsV%clYSm?$diXdOSKY1oP5`v80%w5Et1k zGUAfCr~WbCXmdeO?oZov_2TPp!hpc`_I8zfqWkY!5c@3nDh70JE9jsOSoh?QEf+dI5mh zX*xCi#e#eA9pX_HuZJ4fzpZiImHetRMt8SNE$)-mT>y(SXt_18A+@Jnaes;F4sYdK zX@jJU)07a5nMEH)h}90X#~Og7xCOiZo@k8S;9QfZ` zu`M+d(HQv)%Oh7?|EvNK%T?)ELx!pY6wh=? zE`y3l%Tu4B@7IO^1(-&}Zj1ImyapXk0wl3i7tK#fbMB=GqNS$Zqn8_={zlZNVS}y~ zYaS|Yi()g7UKW~o(!ndsXoi4>3EE8Tzp3yNm1W<)*#U}!&T8{*caWk=>CWi0D2h#` z)Na(TEV*pU*BGeKZkOgpotLC{{X%JR!q8ySbolfi?JYE*O4k)o}U$o%@^ z2-_n{q*g(j-e{ICdi|Y#&;rS375oUbqJ9Cnvk?h=K@*1kq3cHDXem-t#Z-4a*O_!YLvy19_wF4%;Fp(sR=_t zhjhVL58F=Gx017AH_kriG= zLukWg43J^t6l4VzzaS2uzzL>hYsR_q^{hhnl7nbUZAw$*YHe#hEK*x4)3$_ zvj?c(FA5(JCOXf#pGMuG>GPlU7>d=;`WVqNr{OW-T$k8ba*6uIwqVQ2KYSDkE!xGjmp)&C7dyy*KRv%2Y#=D z!|k|o8%NPU&uP_hhIZ7=@PM+7;2ISTg9GWrl@|sKIFS_AA)ap=1Z6)}_6otDi%)M}0pl&_9+udTG7*~-?u(@Gido(-E=6%DAkzKb_@biwg_T_%G z)d3u{p*8R0XEWp%56!OHc)sE+Fb~1S2dhZTp_$ZHV-dT}Tq9{JrA$y!%$m0&E{AuXuplUi5@5Sqc*;>M{U+|#Z@%$K0j@4cfk?QvFLuZ=A!`n zU6kx20~<8l%b4-WD0<)0**OlJvH`MYw^M0U`16a4Av3pAo9-EuYucP{od7pGvvO53(NWFYIIx7AEeN}oFDS0t zzS3KqZu5WKcp}z$CZ@~ucpdjd(Yp@rJfZG%E#?0ng>^ndENiB|P;~F?lM7ax#jE3n zoV$vL9nIxy#OvvEu;MTR81TyJJA-b6h)oc>4viezcMyu#BG9o8AmqUx9~=u&#I(!r#%) z3hp|_>QC-hq{b(7Ts8XJrCBb@Yp%DBa@WgJ3${t4kB$ydtZ&R1!W(9uC8W=KAcxA& z$(AyYC2Ge1wVymSbT^_;ke&Hw_`1YkRekvfBZqu&y%lCYR2A8yv2q$;I6v5fm3d@$ zhGO}+TDJ^TV=n<-dbv9jhVEdTpX(BCEiQMQ*yM9zpqIbMGb4YbO}=oB!CD}hayrD1 zy8}xvit$>l&m-^sKZH2NORd1rPwtw#-jY5Y$$jaCQP>XN^7;Wx6-Ite}oKQFb0?LRUviW6#oLxdM`J%;h^r8_u-%nDXQ*!=sSxVM=}|w zvhqZsFF`Gvk3Yk~^>FxR`l4f&ZHUK_DO=IEhFY}_!vE+Ku&wa!ej37K<0gO1hfCB% zUmDk)fkptb>H*6+wqbpEB|nCZfm`lQn=#K#_2a*4XK|dmaXj##aX2nGW=&--v}%9A z?R5YlOl3+<#*AQ|wQ;BecXCDo$ie#d13Jx8hTPfMlw2hTG)8YKF*i%{*DvIMg35#6 z!k8!Xbg{lQ?fjQ)!1zt-u3oBl_3>b}!U_45Kphak8;nCfwJ%9 z*;8|sRGM4!bkR$yq5drV=c1o^QIP#gh2Tl-e>VRFg~<7n5Gc% z41WGQE23Y;qaf&2y{cQOh}6G^W^3LQN?D2g2BFp&s?KBFPDJ6!L*?piCFk-g;E55j zSBoX|^5SIyms;M`?VLZPajItIkxkY0wchW7Jkyk9)bM8?- z2bEUS=nO+Fbj4V>S zC{ysc4~)LAVHwTtfyiuN?i*T$e?42I(dQ3e64IQFyk~TTA{!~qb9U?3jVL_4WGQCo z6g;Em+;P@k7-#fYP0!>`%>RyRYC;cZ_@s}IK<6+gb*ehXvN0O^GZqs}4k(=uKNFMH;!P8D8P!Bx#Q zYY^yQ9zo_!J^34-tS4+56s3$F9gy89P1b9Ch;FtNvfDhc-_mstY_|4t9lJ+awon8w zint6Q=dEj=Vw+j0<+t6xVi8Ldi+-RCw8Ttv(AUFwmvu^I)^r)-JNI-aUVQZ5HwiYf zJ>j7{r*V9{z^TD~uJ!gdMB}47RMckM>KfXBKu2s~Gc{iF30m<{FO(q?8yfirl5GqY>bSI0S#Da7BO3tW z6X--kTGwtS_U+uj_uQs~eb<~-NTUTUcf)Uyihwv1FJON#~U3lHT9LVWT58q@M!L`uugq!_|D3z!DJ1%4L zG43x{lB3>HqJLZk8fZ83q}65r9y?P%H7o2slisrRfkTOO%BlcCuCHDzir`M}8M(Yx zy7;&jiM%#Re?Hep0)NplBz%VOD|^@N%ZT4Ly=f1P1tX$R?;P6>57%TtMtsgij?5I6PIXPh?7ncl)aQpX-u zFm#r!SDrF{`3%abcqc-#h8t~#46p0?(ydv0>5|9;wfbC9{gxJKBZb3f z;+!LHj+GL2+Z^9XVPT`$-QJP?iPr0FKhiESD~x>iUoJfrStNU4_ZpMKQ*TdaiELdN3Kk6|o z-iEUJ9j74|S*kyv-EUc|d3LkJm8MD}|GE8aFD7Gfl#5@M$dgB_Saq6|&6Lup1>bVC z{QvF8G(M#X6?%m=x(_UV&*aY$4t~xlIM?{I&bm(z(w|N0=rK&(*gorK2P+3d-P`MR zZVOjUjI=XSOiUcZh6UMX}yVWq^7Ia$|J?I z83jF+Y=863+w8qLOrgWUfvUxW@6o8bw*UWG`uDTfE#AThGE8<|___EZ2XJIt(C+ih^C9*Eg8$#W z|F^F4&yPY&sopTpNoQ;oHP$!O>pon=tN(C9{33VNjy&x*x5`e=dHvv9{)HaJbL+b} zF6fjLyxAVCna`xI7ka{8g6D_-|1bXezpU5st^+O*u)dzw{2w@H=3DpSLF36yYk<=V zbFTL27_Z-R$I@kPu+4#^4!iDcaAV8c`%SlLo5VT;J`J6s(9|-{Pr?&Jy$YwLhSx_; ze7f!6QqBe1Eep5cTv7k%q#}GUoVtp z@7@PYQ|(%Gz-+02&#$T1{jh8G*0pc1$i8_{dU*Epoxt-a)(L{ zMaz2z0|SFRdP`(kYX@0Ff!CNFxE9P2{AIZGBB_*GSxQVFaWZ?gxyG* ztSclgg((k`Zskt6H#ttIQbinOWJpG7ZjzOiXKrG8s+CnnYG!&y34^iGD%PrSpsiw) z{|HI285>=Qwy2yeEo{weW@u(+WM*MxnsFlO^5kS;XM@BvGmA76Lla{&Bh%zG6XO)) iq(q~%Gz(M9#H2)X*pFx+n>Ph`ve?(R+T2Xe-zt2+>25S4r?{(R+kM zl<3h*^i`rH%Ju&7&YgSb-hb}Q{o~A;dFFZMJLk-q&+|P`1r9PMh>rmQ9RRpmT7B*+ z06=f6i&irYn%d5pPUYzJk8NcGDDB97G8z{(n^GByQr>lmSYj-Fm~=52rG@o(Fs*V% zr@i~6%L26Te2P;{3*{=%DQvO452_p=c<7}y@E7Ctcepaz{or4z5RF71>IVSjp9g04 z67^IcLw}EtkE{iOSTz&Q?mT}e6DIvF!1TrhB4k(uHGZW}ApyM7$Xc}bA~@%$R~^sg9xF}ZpKx4zLq$r_MjA$`HxBUH-7$|`(_N`7;E=iT zc_}XMfbsM(mqs0DEG8dV{4BZIktiCor_-!R@a!uhU5E=lz<=gmYsVNIl4+M+k4>L0 z6YY`t6be7cy^y(9M@5qZECHR*tx%YiioU(%&lx@KF z&*zvP3anR&C=?b{lHF_4gI`*%)cIH*P_^H?p65c}rO_g@(Ps=rpxyzjM(yty=TBeT zcEDve2*0ieRgov&cxpM;g`QQ)H;sJAY*^Oz*(V^lY`2|zr}MYg+B?&Iz_`3^!`tF7 zP}hbcdaK`SiU_i`qswIpLKDZFFmh=C6xJ(3*ij@Daic0J{=PF{HhOc`HY%@$w6&hx zR{3dj$dPh{bWZw+reFZH3 zaGh;9p8RBVYhEnS9jjIvjEZL9w2gGXw@|(dB)pc`mr`n^0xt*G1I0-!$~smK2%q%{ zUswy8(6x?ZZVcphoAjeB3+>~^;(=?POJmQU-)Ofd+Xg5g>vc(RBG1#Lpk{Dx^XyY@ z5OqTi22N=LmuAoBVEj=;X9Y=vtr`Mq-^vBu{^lzp=lP2#8t>O=Zd8#`c6PVdPt-Wm z8(#gYASPZ39{_jO<;T`1b!}dp&nkG(C-VcC+QTf`bvTMPWb4_nyM-Ab-@fa8w@Ax7 zg_kfxx7IrM^-*imJz_lLBB-1a^&?cKDr?jK(teL2dD%DSLgNNA%1~$4V*LJ}PC`r= z&1j6CH|I9QCr+|TJ@j$Jo7pr>huc>E;LTlhf0LN2%xkKwJxZMf8>bU$Q)U#6Fw?w_ z<$$c+rQu^w6XY*vjB)0z7Sa_4&hqwnvkB^aqMY_8)xy;6ANtotu;45DYe6L>szHo4 zEip2|o^HUsjD={?$2*qq_sBN;a%SJ+KD|*MyscIqEn9yC@H#krDHXv#IPN!Qnl-&jt7#fy9x!>Er zY^M&YlC@qjhb+_0fvGs-ib^9Or@F|uNqhrhLw^?4JOA1Es7u8)Z6U82ib&;9nEd?O ze}pIXL6#22Xv9^5_E2)qRVx7~vil+RGyir%Fz=(cFD4z!fz=li8-B9~FImeNv4sYV z|Dt2-0r4GYqhZGheo=1{_j|IYfF8K`Ss^+5A-xC)thgyn{9qpBv{lU-IFEz;h4CKu z*=Lih5y>{ICDS9$-xBm8`xC_Y#G7)q6(S45l94N@uR>kdb4N-E<*G5N;mosP%%9E5 zkkz4_1}dr<=~@02cm>nB`E?F3+4(sk5dY~P16LH z4grvN|1`SLdJtKfZcWbfU8}QJ(Vlmf_cGZp(d~B#S3%0M9)M^iRZjD}_Wi3!AQanI z`0*`oRto<(^x7NgpXltD{x_IJKNSmism)2?q{JJTu!XNR#bZ(5l!aKd#MMKn-6)1M z1i$L3`Uqp|_y0V%y)3##{&+!v6GI|4F%tv+`2DQeP}DqCA7TgCo-Mvo5r#9&1_|Ic zhSROX{kbpp)*c^#_M!LBR@{y9Ir%f7aiLfTdh_)8nv4ZO)u)T}%h(g>%mtH5BaC~F zrBhsUT~nO+1Fey@6VoCD6l$d;PRy_1G!(xVk@8~dnrj^0wTE{Nhuo}MJZQPzEs62AMt?A709jA2WJZ@UJly|pRH8#cLu9DXD?c{#h z+2l$SB6CU}xG%g^7xnbOWq!s@NKA*)Mg&)y$XXG{lk%ghvS=~d?)2K$mY&x|zGg#&^ObSRIVZyxH+G?e~m0H)e?@kw|nC-l)QrgG+uVB1Z5z4U zL^b#T+Zv=D66sxcTLfca8Ivk%tQcw5BD_tHeIEJIkH)5f#Kow?@Bzj7nOo3BA(~CN zOYBqToJo1x^F%jJq)(W&4;)n*`*f7&sR>-a?*8LR63zT0_;Z?=WjDENw%{z{yrV^K*|qbV1@ zh_#I7voLiV>7s#P4*}+SAGV6Fgle1Pnm1boz4a<>i+nf7=Fft2lS~piim#el~AHw$VR+(hnU5Jp;Qhd(ndzF}D73?M`yKtF{{@SNiZ{R@_e#GCj z_tzo6i;>3mwJX#0sKc11YHO>bhh+=d(>k__+}hE+v7^g<%rZcH1yLg3G}~%kD_-&$_U&+|V^CiT&5UDUceIIQ%|?A62vDM$TM?*|O*eJ%^M`mtGv; zDQjCk9e=uKH8!TT;4EnT9Zui{HJ3BlpGSzPzqHyj0y) zqTd7dov~ul`qRCO-_4CMTJ8kxYS38piHPefyM#Eer@MW~(BgVkjg=IS=4tjEMDl>6 z{Aw+!4nwR_G}^*w8aBF0mdIEpr_b&kx#UZP#PQT=@M!A7{_QiXRsb?dp1JW;FaJq? z0u6T)-CtUU9LyBTDhv|I>GlOwX_MTRDgi?U&(OmaF5ixDvR$E|#}$^ypyZjA<9Oe{ z3ZCc8HPoYS2){(Svux@52iWGWxDM z@Ur)h{}EK0q&)E>rjy+-E;PtGZ;~<5D_K?tI)~j$XF&~^o#^>X2}n>gZH%y<>T1Y! z0}~pJf8BrMDzG=4m~p~k*&xi~B;Y#S%`upo>d;-tnf|70gnr%MwvBCz0SjS7Gv3qC z1`rE_}=c z6=xbK%g2J2YU>TXJUZU1Mg;KC8-F$$=w~S$}Xj}1}XC2CIgKW{EoZ1e87%x`B zgLcE~|DZbdgLL}mJk*N>S_SFbI{i-wBr_*EG3F=61Un45O&I)QBlhuv!LqgvG2(cF z7XXX~nBZP<@ADMhzft9d=)2$$;$J}I=rOkWe9&vRV-GVin}Gc4cWs&Ihzwgn4K`4H zryy!v=Pprkm1Tlzsw&7DS4rdIQ@G5@c~(DAv=06vkK#fG4<)||i1SadXukuYD$EE? zvM2T>^m#kXi5x@+oct$Qq=z}%4hp0A-6X!C$2kH?12Rvy5E)=n_%r91+F)cD+`#=t zk}Tu8L1<)}<>c_~gSQ!6x}@pBwrSOIF)#PuECG(BTQsEc7o-}g_6dQ-uN_JQ}6td*>HOA>@=Bi1ipXd3Nk zlif^T_)IJp4tLhkNV-e0F2@Q0r9&ina*}fG+OQyl62-W z2hi&~rX5rxFaOp%E;>vS!PXCGT+ee$6|1y;yBubR2eh(@Mm(ddL{8i!^tm|M1!DCr zpZB~Zxx@xl>$zARd_Pg}KJUXB2)0*>(o1abfbLHR45V0;w|@6sde)`I-Jf`@ckFOy z(PkoZT}GE`+EyjJZ~>#Ls;!#eWx%E(i-e;|o8r{F1-X4C*1hIylW zMMrdx@wPH!ocZ^7aKVL3*JU<$b%o1EX2kLi*?Y3>m&T&@h!C5mMiEWR-c#$Z{D#_U zeQJEjUJH$=6X!pB>M3^e`Yn)FnaRovQoVw8t-`8j5gS{}&UmuyeK~?ZtbjN>a4(R% zc0jJIH>oVXzn^nIWR5kp)kSlx_hKKfec#-0AYv}+!#j^Z#ld6LxWWOZ9N7P9Z~^|e z(Z<0gNxWi>MFWk~)mTQrPt(HB$=(m6;OK+7+5jnp6haJv6hp|HB9ID_G73_1q6mZn z0%7KjQ~xgoo?cFF&cXkC0sl>@i>m^y)Fuso-fREpn7aCVIw&aUdfK~S6ck)BZZ58V zfFwdvyFW7^RUFMieb3Fw&-I^3woCt?RA00r^(}cxq@1)AQcmpp`=QiEv%`L*wJ_Py`Au4{&^Dhee&4B%k`fq0luyb7g0f-1x0>~VJ)2A+a+&Y7&#}|Q=fv*D#U1l4PjvRE1q(UDAPX`Sqcx3#D&wmWN zsCJIKVxu;5BB-$#Xr}vIg01C1Iw0SGtm`uzXTCJVknq_e5dn5u05SR;83~PB?7i4v z0QJp7AH7}20ZX7ehz(?Vt7aRzCtKB=H*D#2R3MmPRHJc7TUP_ldQ%kVnzsvH*^SF!!Fh)p!)sz(DPFeufU86YqF;KLN~>X4RTl>4eWqh^MTO{3S| znlK~~&lykx-62A5c>=H2Fnq?%nu6tS$scb?)J~MFPd11Suw z3YZkGiLil8t<`$I3ViuB2h`!C-gu_@d)Q#v7FJqf$U+r!QuvHq^MI^;UnG3U_#NTr2TEa7%w3<0}F zhWIW}^yV-HFRFkTg9k3*A%qyfDYH{G{xp)RlXE{!Odh={6g0!wsn2hVh{}3%5h|6p2|dL=jk`a4i^vfflszk9_#Q#N zG!-U4O~C)k_A&E?1Cp%Wd_RxvHp=gd$X81ZH@#J)KgpHOQpanDPr3Q8N3bEt`d{D% zHyTlb-m7m7JL+9djG%m9^L`+TQE3nnVy7wAjs(dTYJv^lgl$~JwD(JY7oajsMlO!8 zy{Xs8p2{`DpMY8cw|ZMck%Bcy$fACSFT|e;EhVM)d8@Y>debs z-oI%Dg=%D;Z|+f?2~j}Hmd^=8-BkczlPPZLi{>7t)d%84$Kb%v9wm4S&?S$cg|`%8 zWTTqlwnHvG%EcuKQo?{|Y6mylBb9>MkiQ3rxIv?b54jnB+l}twH__Fk1~#$HWu!UD zzH8*xBv!b8{Qu68JyFCE-uH9;i#yf-F(7h`WbjiqF4}Kvve&Y{UFlBm2ZuX}yWRWB zMHK{GYrd_8YTUcdvFAsJw{=qmC9J?SQ&&y8}!LbeLY?s7A$<` zU{6bgp7e2OpDBW5;f4*dfkdiC2&&LnGWJwxy2C>#~dxNlqiRy&)bG&u~%vyZCXn=?H~}QR&!J2}Jy~BnTSUWLjyZWMGC`kc2*c zn#g3H{rV_zSHf-aIYj-OvKBq`R*8a#8v`x!ed`H8lemY>VhseN|1AuWb1quLV3K!o z$NU%ApovX}noxs8Z%}GLW?>^2`=M`Rl!)Z4Lq0OJnmX=UJ<;VWN9ar&lXl?GG|Ba~ zFne9LK4M2QSc7Yu{6K@C)RG5gi{_R#-fvvWh$YI*8v-0plAEAKIZ#SQ+`p&g+=v!d zJT#!@h1t+GQAEgqY+nSXz!F#j4K^L`+p^4I-OUgvr^V>3s-z#WPz$Mzz#6UG_?YF` z!9iWcUH7(u#`EH5P6#y{2vr(}j@q(bg&Bf^4^_*B^T(rzqg$bF^9M4bQKrkay!yrv zNzb6@bb~GU8D`+ffX5*pRe~d8#ZV|Z9thmOR(v~3na;YukRoDON@G&H zWynDR?;a%;AcANuOL;gFopoJBiZp2l5+g1G7&Rd|+moy_^ncU%($>`#qF01aYN&rk z-4KJ+V6pjvtkxiWY;p8o5v6Wx`;fCCCX_B?H`;%2EvEck(D-_Vv>gJCj!5%oSbnx=Vf@AGpVgPO{15#sN0uh9 z?5^aUb>t-q4Y-Ezm?VZj1mn>tTWOGsajL+N{!Y^SZ(KjgOC)&ASq!z=Ip0Um-PpD` z9}!q>fM6egQ z=N&B(5lm)Bc>nVy`bK|&SQGE+9uqB{6{mQQZ(1ZKB_X|lFH&;mg?Xh( z+Lty=^EiiKaB-%bGZecP%jRy*tzKG!Dd)@Ou&Fec6*o*FIlwY-t_~^`@z&C}$lfpw zl#iYuLOiZHj?`F>kd6n!L`zFl$(wa*5OlUPIo2`c=Nx*9(r%F>a!c zhBnO5NC5+`0MPmLcy}$;d1^za!J7P)<3l1}+t^psA{mdKPda1EuL_UI8LL<#)Jsxt z%z}5ZK7r70Xm!ka=A6PR8wMzNPP513;%<1KR*y`nO~nK5uNRK@1da{uK#gQ!lrt10 z-UJN{_g^enp^q)Tn3vsO6vb)coDz%P!GA_-3p3W?^Z`*_=zKw3SYeT%g5XFp2E*%z zs0cUtZ%}i2*z4Em`a$0Pbq3$-2DXa0qJO&?&`9~ddu#%3hDO`l?}4X%JFlm1v@F|< z--broQKUmeL6H%pkm#0SK|9=n;D}U)%%Ev(4iAh17Aza?f!WFY(Kd7V&Oo|+hv6R$ z;GF5q40!s(^thFzLFJ!n6y13}(`3LJ^yDGBp-AsH_KB5PP>JYEN?p_tIDs)Ay#!?O zq5vJH&g=FcHJBTe4LYaU`U4bLfr>jMs?1_IMhe)^{`6$i(r0Nr-Z0%s-Q#tQ>KjC- zY2+?ZOqsGRrDJWy9-LM`94WGW@cLj$r@`iM1gv$%g!Q^57xioIL3PR|g6EJVFbvoX zQDypc&&$kOZFkm&w^6B4_J5kP1C3E$*Z+*I4dsX~(Ero##?L$c>C*_kq_0H)7RAR? ze$X6a!o%?2jOFj1<9K0cUp%xO3UMmmR*{k#YJDal9cGjmf^-qV1fd={g`YlOU?-dA ze*%644bqQ{7QV98CF^&1oyVPbzpL2)XV z`s_E`M=3PlLz|}wa@PPqKOKAb1BAP1ARtErQpaY6N@DDv+>CbkN(zSG{W?X6yu6}; zRA|eqsyTe78DM$y)=-=Ci~YNo9?r>`MulWi(<+>X?+c8D|A4EwPIX%{c}H*lD&O4i zP6rV3?PD}SHtSHY2ib}*wG7fvytIo9GK)oj5Ldo?U!WJMJp$7z%kIo)4rVNH2Lm}l z(;S>0s5vxpd#^*@T%_Rf)i(^J*Rc=(aeOEKbe^>Fl)8LxW`@Nir%4C2NZB$vz3v3d2<3thC{>P3Vswf7YL3 zUbD=d9o)0=z@P0_u}r*6Qxp{SY8gP`BL07}pdiJ;BPs$#Nz4kvZPo_%BxYWvzoeXo ztoftwvA%L?y^kOZ)vlK~pt#|sJW&Oi^Is?k=#&dzvq$FaAtej%o+R*`TNgDG059Xr*4hJ2!xru@ji7YQw z3&}#?)u*W2jtFItzi)k0=lF^WFY1T=+kFkzKkW|>r;`u9wn8+niLBXQDeZbu2o!s*UAZ0~Gsdy%`0aH*&_0;0Uhi%FqJQ$@%ljE-lMrYA9Gr9j8_wpN^7m!- zyt+caqrwamSPQf{UNIG#mN9!L;Dzyq-G#IH#z_g%zqxcg*k=GklHMsLPTTgP#1;8o z9gbgL&f+dNa@Azghic=>N31s($=8i7_Wn zqjZRHXilzX8PlpqdH@y$L{{ip>z4*E$J9V8w^i77lv8sF2R7$d9`2$&fzz{_$KG&Z zYCLZ~np1P3jdib>$q&Ox?fx-WMHK3+;xw@d_~Aoga_k3{z!*7*DPSMk3e#d-fU^28?|d?DH(ddV}n<88v5^F6bdEJ z$RgjM@CRc(ZLdDK2vNi)9RWLHf7zsNwR}!D`NLo^mD(v4c#bq1_J_opnJN?h7zHN3 z$KIzGA>Cbfs&t!D_qWpiN5viS;x~i9n>gS&#QO2R<)y74j~=JhNS!&`uLLHLZk_gP zq8y#Xszfd${DDnNpQBv=>uY|=t9q&OfZKAj-{Em|9EBu9zy&@hRC9ti=zA{OGWVDs zLEK^#u-y9BiW)Uy^9M`UzP8O1^DVcUj?eWmW9)#H&-0CHf4Z*qIXNv1xH&fv@V#Zu z0&d^e`JBk6*x5Of;aZJM@d@hhCDxBx3RyNZY22=S9ws2X=zh5S5fV;#vb)Z7v74iK zyWSgq`S@@Lyo2L^agx^zH$Q-j>iWFL;m-BH?RPVg(#Gw* zhN?4$`c~$#u7fiLYPbwg=JzVFzTlX+74PuO~*D-s?@%bpkC^Pc=J=ksnk+Md?Kl|^al&T-S> zm@I2i5_dGJBBA?e55%fh*lRf3bfqp0?Z3FY92yQ^1dK0-OHSM(ApV{vi6`sd$gj_C2K|Qxam#|9!X%Iolb(I6Wu1v9xe95UtP|)=o5(7}6)iNdBbY z@U1EB4dKyA_m}Vw&*zlX>$yU?EA$HMHk9{Ll|nuWbYo>rIIDzJ?t(Pk;^W#Hu*jlh z04kKYGSmgAu^bOr*+7vqUsGf=i-aif_^4v1A6MuqpKs1-cZjvCTVj>EMv|YT9_x6{ zZzZ^P?`QRa&F5p}$U0>C>t!AGC4u(YOY!(3Kebr{)z;m<&ttxFcS`v>Jhc8g`}yD} zBM1(cb>_|UuLuaH-GqOY-x!lehw`KXxF%I()@Mr#bwcQ@8X)nNMUA4XBf?Ai_UOsS z0NWV;He)x5CA^QH@dCCj>Xu^89S@jz-LNk0EBUG7Qhcs8ZIlz=TwNvge?KZJKRf%X z&y(^hEFEPkid{K*OdtmjBN;E;fsbx)-8%8p<>jcC%Xm>pP{WL22LAe@9)1ZNFp^th zf%4jz9Jhw+*4oeuxBrV=MD@p(whiRtQE*TV%XqU$9Hb$X0FqAC~EduY;Ug1*U$1pih;zh zS&3EZVic0FQ@quS*oR0$1>~#V09x!uWKppw=?3rRMSp$}rm_h+ff2GM$t2p$P+3(r zU^T-ZsH)@(8b2C?ss+032f^}L*G#f~E}S%E8!$($)>j*vW)Sv@CMMU{L`h6HB}V-*KzNZx87U9J zc)iVWUtlaF9B+<-jT3jutH~Xm&%%^UPO}1-Q#aEsk$G*MZ<;ncdyLFc z-qAIpG}-brs$vQ|N&B}iC;tvrpb1d>4(H`aJTo@F0+W6{{WlFHr6pF#2~OpC1M+i{ zb}W**b?!fljZf0-hgijF00lb-HoYm^XNsn=pqig};F%Gr^DO4vE7m}YlZV_$td-NQ zfc!aM1L|=bULB+AQA7BTnJ5;1L2qcn)2xlIM`J>=TlQFvxywVuWrEu^* z&!yWa?!mu3a%I8}Ka-2NC>;}0iUI=Jq&xLY>HmG(da*gJ0CJsI0oHGEg_8csnRF?P zH@hAZIu@g=UWCXs8=e#1Kec1!6M0PZJhbbHFrX9IqVHYdL64N((4W&83S_{`mv+d| z$ZqbsJ&meoyU!_xbo}LhzD@ntWHwYc*xHtzO{MOP;R`q^%_;Hgpqqb8q?Z|YtNjWs z9f<*T9eKgL9)i$WKmqh81tGr-V-R%J^Rd=n{Dvb0GZBv|fIBH>}eTz#WP>^|BE8uWr%v^{}G~<-VJ+` z%h6@X!Js(~fIf31wZFibQYVvbKAvjE*NyO5PDPN?aSZ#0Z5ITog504vKmUA&`g58y zpQZ;P|rKY^LSRRXv|d5qU=KwmDeD2PkY`%iV|_Ls(qR!`5I zv!aexe1dsnIS1JtbD>g;S(o9bSp$=xa!HSa^(YEp>na+m`2`<^5nYaig1&8q7nuDAfsdKsp4*$z=T{ljj0kMC$m+LP69o zaLYL7S7o!wqfxyWY~5;SRz9wD@h|t$8?C8A>$v@0UG?Dq%w`#V)Nf!kW>WoUDx4oZ zf`j=kD7GyV<^D!kRm%&QQ|90BbXqrGk>3>q%0nmmPkaS%6YkMZh}{a`Z=hOR+{vB^ z!z)h|fpf*{3$v#S>Vxkcf`NV?C`cDdw;DXM5f}00SQ{f`W2iENCKTBewRhkyldus# ztC-!rbcK<#%?Ygh_ZZc}r!yQfeuX6PN^d@j$-e6+!7QN5PfiQ zrC;X*gLaFQ`P>+O+$en(SbOpQIrsE{r}=CJ!(CG>Xy#hzC6Nb8H*H*w5_5~YpmkNBXz5xOMj`o+p$d+_a@CN>ja{sSr=qor zV6(<}uwmcGOl_S1dwW}O)GH;u3@>&1{KiJloW0xg-E^Zd&mJ4BHSLL_`;Y0syePM{ z|H73p6rirytJXiqPLO0pB3O^FeolrpgmfPGWffHXOWK`;B~nl zU(*I}8X(fwZNl&g-Q26PML)g#=(}*5Rf>>0E@~LqlwNXBF5(=0{O@{#8Al3xAyK8r zMvA$dhf-whf}#YaKJ`?1fdO!Yh@MpkosR0;9$1YWE~e6=e3PSYIv@&ZwGHB1LWc|z zf~6P>-g2a%4kc?-LMRJKI0|2)=8LX@?R^U0<4X#~cgnLtc1gW&RsNwm$#w~!*o7}G z_BQ(0j@=S-_SH&GY*-K`m|+g(y)4v*4oBGUHpz0xZ#l3VxRAZb#s(Tbb1802hiYJ5 z?jI4R)hvh}oTh-K&1$y==tgP3$>{-2uZjQ5i2Ke3JMHZ3*tn&;3Ei_B6=yDhKw?w0 zIV)fJYL#fJ%tzdXw_tYs_&M6qHOYD>teT9z+uyzM;b7q8x>7^C+^$vvuF|z`}HZ$0IwRKL*qBA9zy0k`__ZXKvyo&mXaz z6kvy6d7|{V7_vPzWn@^zulAlC;21;(Bv~`@`xe#J0da2mDcTv@4kgK%=tC}0euae} zwey14dBN^P0m}mqijNDVke{Gze)rQW;OXjmVYZ{OQKLE()arP1awEJ&7%9E-TOMQq zRhxB0=wUO!Zh5v`1W7)G<`3T0JZ;)FIwr1^$a~|*OJQT>ANvF`I&hJacI2V`(aYz~ zGs0p3xPCxK+HtP(1kWgq6&8-+W_OttkCc*MQ2fhf&s&S)PN|{oRpmmS1i=iQ_bVyr z#Dp`f*51GJ2~S-%b+Gf;o(Aht1kKDf1H@&kc}p<(ql>mu5l;AtxT}*hD-%>C*#tjx zWkI;p<>te;6Kn`{KDGh@?Ka-G6&+-#yJCSr?dZHP8WL@4V6wOSJyY;?$MI4YUM)w< zK~uS(m171mr=}w*P8I&h)X)>rbrH%}l+*u$r$w`v3gh!cVZ-w$);w+%6!ND(z6)*om$;8|ECX{Nkw1gIjx>BN(akR0O4DJDNzXA5bL zRSKR$co5tTS-JV<^sdq9{=RB;A)Z;X>635RL0cu52}o;pU#^$-k`!e#e*N~H+zY+F zFLT5rOVBDeRnj;zXmopLVk&$+!UD*P*k0Mn^j(I^wcW$NvEOoBKvAX)TVX{P7tc_RC_D%ZGGu%Pjt36A_)N|0PVHq>ZVf z1GCvHKRBXDr4&s>Rr4=E-^B|W8?EE>X$Cd>7m7+(ST}g=w{CjWIXNz4tpf8imujhH zd$-$rVICM^d+$!I$~DP#qWTzQM(1?!zUiCHb-(C48kUY;nG`8%{kR_=!HO8-eZ(lW zVTo=*mQzQ1*bAZ<53Yqi4brw8Hp8W7)b92oEQlGGZT0QO+QxROeQhzV^6gV&)zU7c z_CgLsSc8vgyU$?fP?7dtB4AP)E@8RN5twLl@Gdx7C$Saw+4S=o>1LJzYr~);nDEW) zgMYS*lkkb!QFH8Z>q3k2>cR%)^kobIG+zY29t~Fd?$oa^xnYK?`Z_94hD%!j-Zvuj z2V_c!(uR{@DaU3~7VClvX>)FV$@oEL1aBfUcz%VM=tS{DNK8bJJkVYkk@c~9!)sZf zYaI2zChdDtvFd~7gQpR3cTDp2GT4Oe!(WxY_mgN;PVw#k<#2)wIZ|$R!iO|Utir5E zw2CeN&B}uON8?SlhlMfq^>#ik*N4m!*6K-$46aMYKa{tFVbsWtjE2+{?YgeKw|r~> z*E{G5#rPV|6_3_9D$pN03gQoL%#fH}cBegB?!J&s^E8cLGV2|6l&BLFTwKdeaSyOv zYozSTGGTdSZzO|ci+o+j>h@8bL$As|1AS6*^MZOY!SW>|zRMkEg=n@#+T2Ko*U+uw z3sT1&7dFi3!&Pm09=w^71G`)mV3tm08}V%gMl9Q1p=J>+fIF5QgbFelm?3CO@bfda zX#HL!CID|dn?#28M zmbJJD`!}#U#Fyl=@${C{7w8)asQDk!YeH6PIJQ_)7w6@ZR357>wrQlDD@_E>5;MqW z7G4XE-wR*u0Pg58(A)A6_CK=kh}|H?rG(#~aiPl;ZA>U#x84^kTQ%6iI2rlN%p)vw z%=Y||_wz)ZI<%@^dH>-|y%6MG-?$uq_~=k6VPT7Hl^P$48VD&)#l%kwelBJhDy5%i zd@34Nei`!m^+cBQukm#nHzlh4(kMOk3lFfNICUNvz`6Yg~H!o*8Zm@vlRt4bt#p;XyZ?;0-O>?7X}}ZZWD&Q!vR(|Eylx4W{_pdluB*5e2@m)ck96?-lu*7^E0L zCQ?7cGhD~jR!MINPhnOTrNEmKQVUm3j7iZBoylzHK}c6o!46k@?G5BaAH$5)K#S?Z zo}clm$%Hw&)?G!&R-Acp-cwAoW|+JVX3=X0pyGl9TDmThj8k@jmxDM}MB=jAgy4!=9ULfK#YiJYrHQj1%+obT#~>RD8|BP2=>F&GJ-)&h2(^{SF>|!N$E4E|abvY_a|o?SM1o#V>|)mk$I9PO z5Q8$2sJM9Fq|&A#RBx0T9l6dvMRgo)N?G5hcm zsTM0V9=F>v!>mASkgHG)7O@<-~Xl@s4ayX3d9 zo*3FR;X1RRAahn4`a7HOrU*+@5eVXgo5PR)q?X8pR*1F&wxO+_d12+JES;dlV zpp&e%zO7v@CFD7_R@R(Tpp2!6Kr+BIaZvUT4kpd{0{foW3(G=95R<*WSGJ&hi75o_ z&gvgjWBLkJRhYY0luZqHy0<#aT_moWX8f7(Y;>PScio871K|`VKO6v7@j~jvUd0}4X!diUC5}Kz3VU49Jvw{QRiVK7zC*g>B5t& zlQkdB3O*urZ&4tm%87I92qlA5h#=fWK`rC;SwjF7B)5Bp^6b}(CN~WG5mdP9mqo^# zSQ(0i8rg%N5|_D4JFs(_F5K%043RC<$Yx{_@telrh~aMYE`wAcL0d)8eZ%RIGB8N- z9>uur3FMI&4VHTYf+uXH5KHfq7QgYu$m5Ctinq*o%LJBI>L4AZhFW*9|fg;W^Aj`?3N>oGg#KF5N znvKPGr^laU?4PPdnh90e{kj&3x~2@jPZ;vr)n_RGA_3lKT8hxLhNB0$8^Z7J$DhQ3 zJ)>1^)9DP52s#2}PX7sv{zDEba=bYG#8VI-yMQBW3_4?XakE3gZ!G%4*=~wFW zpwOqe;Q%Lx5gc*W%osi%dUnD)?*H&MrFN%r>odsvPTCQ6p@9fdmad)%wW3Aq1pbh8 zNj%+Q0T*0g-y#=1A$xk8MoxaKB=yOUPr{uC=G;iq)gBg|-U}3KRnRV>)V=1>!9m7v z2VIEt(783n@n?K0g2}7(_$U5A&$Z@ztcGmfAID50TdP-tbwv%4d_(#Yk^QsjYNpnwqWxxkj87aP49o6@K9)W%OWWz*6S!-K4A0? z?{>_yLvEDo^ht6F@0gATvLvSlT1S0mOT2{S)j+5wCkl9NVU*@3v3bJGasJO)<+Xmu zbzPbVi224iUMiGRE0LoR!*DOiOfse8x}P_d9=NY%fd)K1TsfuMq}Wt*scw1m{H6iI z5Lo_LYmjFH;c_2hS@ks5`sgMJVUL~QvY_oZ2zN@0TGXY%&mOesCykKbq9*@v{5eN5 z5)~i$SQUx2bQ>6-a|JxdXN_4oS$o)_(kXYRkv$5B(Vtp&-n2se4uO2u1A<60AtfYB zYz1-Y`n~4gmP3;r{6@dpOp6%zt6ONpPBkT zv&YWepfDL>D`QPb11Useg&~x9izXlrFaGmW(8m`&e;Xd^>eRNZ#16}2AFJ~FHPYdZ zc|g^@Hl(dA zfD2N?H2GtpP%rx774cFt7P=65SM;f}?>MR$GvF~X*@RCEdWA`l0IZFqZ7C;8KTliQ z1H2AeEI+;|ypbiI>=ntIsAE>=fjv9C8d3Z514<`fSm&Yb@Rz1g#ScGGodouI9sytd z!3W;SIM?0Uu=1JIYaILxV8&;+DWQ7)%kyykJKA;-{;1M#t7Xgb9K+rpxeJFU>zRe* z8egIehFiV$>5d%(`M+~XfP23Cd|;7eKi{~z;Z1s~+Al2fYbP*5L4~7qQOCaW2NST~ z0$8=^OlMQBpa{$V+M~v7>5s+de1n`UEk?-r?AQ|pM=1XHU0NXvc#wMZCqMLiK#)R@ zCo}`*D+jYshrSwr)^^ZWVF_8HN0xVSiD9Mk(IRReHylMT(RjYS<}9Qi!FK*VDYc}1NH$NIevG%;A0 ztYqd!0Gb$Yv;dGGY9D=J=U815wgkQOJ?!HmFFmm76Y;~(2fJ(Ud0Vixeb2X(*C-Zd z3Kk0aOpzrkW1%k&T5laq=q_6KzGnt4oO7tNGueP8W@lAON7FcswcGvP@5bP83m2e$ zg$Y?~V}j_wlahji>-f5YTJFz!yJCP~En}7b?tny+4M2Hy1ze1Lb*36p+qpxpZ~qCt zQp@Y=6yEBDty$PyBF*f3!Uf}3(QgLnZa9&>{c|+L52+vu?>-<JJ1_cP#;570>H=Rmqt2m6Ma0q*F(?n!E0STB!lUJ4aUI*4*!v^GV;8Qq zxOKh2@PrFtkPfI!CPJmaZi*#Y#XwOS`ZkLVYN806zDh%~amr?@vQ)LN$$c23OXaXoX*VGwBHfNN?y% zLe{tRZ9$hG1GonxEKeS;-Hs(?9;?XRzep6dG1{5R{EY?h|H=uX+PjIl?hq~zXEBF{HtvymeRq3=8}TwtL0!Ukd#ql z*f3l_VMBbbZ_F%Il0;rhy;w)w`xO1|?ry3mYaIJfklmB^Z%{Pc#feC#b>nN#YGWvO z%34j%=QnEhSJS5UZ(+@(j7X%6GoaNzWt5N#l7(wGFT^BUw`f{I0(0K5@(rx@5=!;e z+l^C{lqsV%clYSm?$diXdOSKY1oP5`v80%w5Et1k zGUAfCr~WbCXmdeO?oZov_2TPp!hpc`_I8zfqWkY!5c@3nDh70JE9jsOSoh?QEf+dI5mh zX*xCi#e#eA9pX_HuZJ4fzpZiImHetRMt8SNE$)-mT>y(SXt_18A+@Jnaes;F4sYdK zX@jJU)07a5nMEH)h}90X#~Og7xCOiZo@k8S;9QfZ` zu`M+d(HQv)%Oh7?|EvNK%T?)ELx!pY6wh=? zE`y3l%Tu4B@7IO^1(-&}Zj1ImyapXk0wl3i7tK#fbMB=GqNS$Zqn8_={zlZNVS}y~ zYaS|Yi()g7UKW~o(!ndsXoi4>3EE8Tzp3yNm1W<)*#U}!&T8{*caWk=>CWi0D2h#` z)Na(TEV*pU*BGeKZkOgpotLC{{X%JR!q8ySbolfi?JYE*O4k)o}U$o%@^ z2-_n{q*g(j-e{ICdi|Y#&;rS375oUbqJ9Cnvk?h=K@*1kq3cHDXem-t#Z-4a*O_!YLvy19_wF4%;Fp(sR=_t zhjhVL58F=Gx017AH_kriG= zLukWg43J^t6l4VzzaS2uzzL>hYsR_q^{hhnl7nbUZAw$*YHe#hEK*x4)3$_ zvj?c(FA5(JCOXf#pGMuG>GPlU7>d=;`WVqNr{OW-T$k8ba*6uIwqVQ2KYSDkE!xGjmp)&C7dyy*KRv%2Y#=D z!|k|o8%NPU&uP_hhIZ7=@PM+7;2ISTg9GWrl@|sKIFS_AA)ap=1Z6)}_6otDi%)M}0pl&_9+udTG7*~-?u(@Gido(-E=6%DAkzKb_@biwg_T_%G z)d3u{p*8R0XEWp%56!OHc)sE+Fb~1S2dhZTp_$ZHV-dT}Tq9{JrA$y!%$m0&E{AuXuplUi5@5Sqc*;>M{U+|#Z@%$K0j@4cfk?QvFLuZ=A!`n zU6kx20~<8l%b4-WD0<)0**OlJvH`MYw^M0U`16a4Av3pAo9-EuYucP{od7pGvvO53(NWFYIIx7AEeN}oFDS0t zzS3KqZu5WKcp}z$CZ@~ucpdjd(Yp@rJfZG%E#?0ng>^ndENiB|P;~F?lM7ax#jE3n zoV$vL9nIxy#OvvEu;MTR81TyJJA-b6h)oc>4viezcMyu#BG9o8AmqUx9~=u&#I(!r#%) z3hp|_>QC-hq{b(7Ts8XJrCBb@Yp%DBa@WgJ3${t4kB$ydtZ&R1!W(9uC8W=KAcxA& z$(AyYC2Ge1wVymSbT^_;ke&Hw_`1YkRekvfBZqu&y%lCYR2A8yv2q$;I6v5fm3d@$ zhGO}+TDJ^TV=n<-dbv9jhVEdTpX(BCEiQMQ*yM9zpqIbMGb4YbO}=oB!CD}hayrD1 zy8}xvit$>l&m-^sKZH2NORd1rPwtw#-jY5Y$$jaCQP>XN^7;Wx6-Ite}oKQFb0?LRUviW6#oLxdM`J%;h^r8_u-%nDXQ*!=sSxVM=}|w zvhqZsFF`Gvk3Yk~^>FxR`l4f&ZHUK_DO=IEhFY}_!vE+Ku&wa!ej37K<0gO1hfCB% zUmDk)fkptb>H*6+wqbpEB|nCZfm`lQn=#K#_2a*4XK|dmaXj##aX2nGW=&--v}%9A z?R5YlOl3+<#*AQ|wQ;BecXCDo$ie#d13Jx8hTPfMlw2hTG)8YKF*i%{*DvIMg35#6 z!k8!Xbg{lQ?fjQ)!1zt-u3oBl_3>b}!U_45Kphak8;nCfwJ%9 z*;8|sRGM4!bkR$yq5drV=c1o^QIP#gh2Tl-e>VRFg~<7n5Gc% z41WGQE23Y;qaf&2y{cQOh}6G^W^3LQN?D2g2BFp&s?KBFPDJ6!L*?piCFk-g;E55j zSBoX|^5SIyms;M`?VLZPajItIkxkY0wchW7Jkyk9)bM8?- z2bEUS=nO+Fbj4V>S zC{ysc4~)LAVHwTtfyiuN?i*T$e?42I(dQ3e64IQFyk~TTA{!~qb9U?3jVL_4WGQCo z6g;Em+;P@k7-#fYP0!>`%>RyRYC;cZ_@s}IK<6+gb*ehXvN0O^GZqs}4k(=uKNFMH;!P8D8P!Bx#Q zYY^yQ9zo_!J^34-tS4+56s3$F9gy89P1b9Ch;FtNvfDhc-_mstY_|4t9lJ+awon8w zint6Q=dEj=Vw+j0<+t6xVi8Ldi+-RCw8Ttv(AUFwmvu^I)^r)-JNI-aUVQZ5HwiYf zJ>j7{r*V9{z^TD~uJ!gdMB}47RMckM>KfXBKu2s~Gc{iF30m<{FO(q?8yfirl5GqY>bSI0S#Da7BO3tW z6X--kTGwtS_U+uj_uQs~eb<~-NTUTUcf)Uyihwv1FJON#~U3lHT9LVWT58q@M!L`uugq!_|D3z!DJ1%4L zG43x{lB3>HqJLZk8fZ83q}65r9y?P%H7o2slisrRfkTOO%BlcCuCHDzir`M}8M(Yx zy7;&jiM%#Re?Hep0)NplBz%VOD|^@N%ZT4Ly=f1P1tX$R?;P6>57%TtMtsgij?5I6PIXPh?7ncl)aQpX-u zFm#r!SDrF{`3%abcqc-#h8t~#46p0?(ydv0>5|9;wfbC9{gxJKBZb3f z;+!LHj+GL2+Z^9XVPT`$-QJP?iPr0FKhiESD~x>iUoJfrStNU4_ZpMKQ*TdaiELdN3Kk6|o z-iEUJ9j74|S*kyv-EUc|d3LkJm8MD}|GE8aFD7Gfl#5@M$dgB_Saq6|&6Lup1>bVC z{QvF8G(M#X6?%m=x(_UV&*aY$4t~xlIM?{I&bm(z(w|N0=rK&(*gorK2P+3d-P`MR zZVOjUjI=XSOiUcZh6UMX}yVWq^7Ia$|J?I z83jF+Y=863+w8qLOrgWUfvUxW@6o8bw*UWG`uDTfE#AThGE8<|___EZ2XJIt(C+ih^C9*Eg8$#W z|F^F4&yPY&sopTpNoQ;oHP$!O>pon=tN(C9{33VNjy&x*x5`e=dHvv9{)HaJbL+b} zF6fjLyxAVCna`xI7ka{8g6D_-|1bXezpU5st^+O*u)dzw{2w@H=3DpSLF36yYk<=V zbFTL27_Z-R$I@kPu+4#^4!iDcaAV8c`%SlLo5VT;J`J6s(9|-{Pr?&Jy$YwLhSx_; ze7f!6QqBe1Eep5cTv7k%q#}GUoVtp z@7@PYQ|(%Gz-+02&#$T1{jh8G*0pc1$i8_{dU*Epoxt-a)(L{ zMaz2z0|SFRdP`(kYX@0Ff!CNFxE9P2{AIZGBB_*GSxQVFaWZ?gxyG* ztSclgg((k`Zskt6H#ttIQbinOWJpG7ZjzOiXKrG8s+CnnYG!&y34^iGD%PrSpsiw) z{|HI285>=Qwy2yeEo{weW@u(+WM*MxnsFlO^5kS;XM@BvGmA76Lla{&Bh%zG6XO)) iq(q~%Gz(M9#H2)X*pFx+n>Ph`ve?(R+T2Xe-zt2+>25S4r?{(R+kM zl<3h*^i`rH%Ju&7&YgSb-hb}Q{o~A;dFFZMJLk-q&+|P`1r9PMh>rmQ9RRpmT7B*+ z06=f6i&irYn%d5pPUYzJk8NcGDDB97G8z{(n^GByQr>lmSYj-Fm~=52rG@o(Fs*V% zr@i~6%L26Te2P;{3*{=%DQvO452_p=c<7}y@E7Ctcepaz{or4z5RF71>IVSjp9g04 z67^IcLw}EtkE{iOSTz&Q?mT}e6DIvF!1TrhB4k(uHGZW}ApyM7$Xc}bA~@%$R~^sg9xF}ZpKx4zLq$r_MjA$`HxBUH-7$|`(_N`7;E=iT zc_}XMfbsM(mqs0DEG8dV{4BZIktiCor_-!R@a!uhU5E=lz<=gmYsVNIl4+M+k4>L0 z6YY`t6be7cy^y(9M@5qZECHR*tx%YiioU(%&lx@KF z&*zvP3anR&C=?b{lHF_4gI`*%)cIH*P_^H?p65c}rO_g@(Ps=rpxyzjM(yty=TBeT zcEDve2*0ieRgov&cxpM;g`QQ)H;sJAY*^Oz*(V^lY`2|zr}MYg+B?&Iz_`3^!`tF7 zP}hbcdaK`SiU_i`qswIpLKDZFFmh=C6xJ(3*ij@Daic0J{=PF{HhOc`HY%@$w6&hx zR{3dj$dPh{bWZw+reFZH3 zaGh;9p8RBVYhEnS9jjIvjEZL9w2gGXw@|(dB)pc`mr`n^0xt*G1I0-!$~smK2%q%{ zUswy8(6x?ZZVcphoAjeB3+>~^;(=?POJmQU-)Ofd+Xg5g>vc(RBG1#Lpk{Dx^XyY@ z5OqTi22N=LmuAoBVEj=;X9Y=vtr`Mq-^vBu{^lzp=lP2#8t>O=Zd8#`c6PVdPt-Wm z8(#gYASPZ39{_jO<;T`1b!}dp&nkG(C-VcC+QTf`bvTMPWb4_nyM-Ab-@fa8w@Ax7 zg_kfxx7IrM^-*imJz_lLBB-1a^&?cKDr?jK(teL2dD%DSLgNNA%1~$4V*LJ}PC`r= z&1j6CH|I9QCr+|TJ@j$Jo7pr>huc>E;LTlhf0LN2%xkKwJxZMf8>bU$Q)U#6Fw?w_ z<$$c+rQu^w6XY*vjB)0z7Sa_4&hqwnvkB^aqMY_8)xy;6ANtotu;45DYe6L>szHo4 zEip2|o^HUsjD={?$2*qq_sBN;a%SJ+KD|*MyscIqEn9yC@H#krDHXv#IPN!Qnl-&jt7#fy9x!>Er zY^M&YlC@qjhb+_0fvGs-ib^9Or@F|uNqhrhLw^?4JOA1Es7u8)Z6U82ib&;9nEd?O ze}pIXL6#22Xv9^5_E2)qRVx7~vil+RGyir%Fz=(cFD4z!fz=li8-B9~FImeNv4sYV z|Dt2-0r4GYqhZGheo=1{_j|IYfF8K`Ss^+5A-xC)thgyn{9qpBv{lU-IFEz;h4CKu z*=Lih5y>{ICDS9$-xBm8`xC_Y#G7)q6(S45l94N@uR>kdb4N-E<*G5N;mosP%%9E5 zkkz4_1}dr<=~@02cm>nB`E?F3+4(sk5dY~P16LH z4grvN|1`SLdJtKfZcWbfU8}QJ(Vlmf_cGZp(d~B#S3%0M9)M^iRZjD}_Wi3!AQanI z`0*`oRto<(^x7NgpXltD{x_IJKNSmism)2?q{JJTu!XNR#bZ(5l!aKd#MMKn-6)1M z1i$L3`Uqp|_y0V%y)3##{&+!v6GI|4F%tv+`2DQeP}DqCA7TgCo-Mvo5r#9&1_|Ic zhSROX{kbpp)*c^#_M!LBR@{y9Ir%f7aiLfTdh_)8nv4ZO)u)T}%h(g>%mtH5BaC~F zrBhsUT~nO+1Fey@6VoCD6l$d;PRy_1G!(xVk@8~dnrj^0wTE{Nhuo}MJZQPzEs62AMt?A709jA2WJZ@UJly|pRH8#cLu9DXD?c{#h z+2l$SB6CU}xG%g^7xnbOWq!s@NKA*)Mg&)y$XXG{lk%ghvS=~d?)2K$mY&x|zGg#&^ObSRIVZyxH+G?e~m0H)e?@kw|nC-l)QrgG+uVB1Z5z4U zL^b#T+Zv=D66sxcTLfca8Ivk%tQcw5BD_tHeIEJIkH)5f#Kow?@Bzj7nOo3BA(~CN zOYBqToJo1x^F%jJq)(W&4;)n*`*f7&sR>-a?*8LR63zT0_;Z?=WjDENw%{z{yrV^K*|qbV1@ zh_#I7voLiV>7s#P4*}+SAGV6Fgle1Pnm1boz4a<>i+nf7=Fft2lS~piim#el~AHw$VR+(hnU5Jp;Qhd(ndzF}D73?M`yKtF{{@SNiZ{R@_e#GCj z_tzo6i;>3mwJX#0sKc11YHO>bhh+=d(>k__+}hE+v7^g<%rZcH1yLg3G}~%kD_-&$_U&+|V^CiT&5UDUceIIQ%|?A62vDM$TM?*|O*eJ%^M`mtGv; zDQjCk9e=uKH8!TT;4EnT9Zui{HJ3BlpGSzPzqHyj0y) zqTd7dov~ul`qRCO-_4CMTJ8kxYS38piHPefyM#Eer@MW~(BgVkjg=IS=4tjEMDl>6 z{Aw+!4nwR_G}^*w8aBF0mdIEpr_b&kx#UZP#PQT=@M!A7{_QiXRsb?dp1JW;FaJq? z0u6T)-CtUU9LyBTDhv|I>GlOwX_MTRDgi?U&(OmaF5ixDvR$E|#}$^ypyZjA<9Oe{ z3ZCc8HPoYS2){(Svux@52iWGWxDM z@Ur)h{}EK0q&)E>rjy+-E;PtGZ;~<5D_K?tI)~j$XF&~^o#^>X2}n>gZH%y<>T1Y! z0}~pJf8BrMDzG=4m~p~k*&xi~B;Y#S%`upo>d;-tnf|70gnr%MwvBCz0SjS7Gv3qC z1`rE_}=c z6=xbK%g2J2YU>TXJUZU1Mg;KC8-F$$=w~S$}Xj}1}XC2CIgKW{EoZ1e87%x`B zgLcE~|DZbdgLL}mJk*N>S_SFbI{i-wBr_*EG3F=61Un45O&I)QBlhuv!LqgvG2(cF z7XXX~nBZP<@ADMhzft9d=)2$$;$J}I=rOkWe9&vRV-GVin}Gc4cWs&Ihzwgn4K`4H zryy!v=Pprkm1Tlzsw&7DS4rdIQ@G5@c~(DAv=06vkK#fG4<)||i1SadXukuYD$EE? zvM2T>^m#kXi5x@+oct$Qq=z}%4hp0A-6X!C$2kH?12Rvy5E)=n_%r91+F)cD+`#=t zk}Tu8L1<)}<>c_~gSQ!6x}@pBwrSOIF)#PuECG(BTQsEc7o-}g_6dQ-uN_JQ}6td*>HOA>@=Bi1ipXd3Nk zlif^T_)IJp4tLhkNV-e0F2@Q0r9&ina*}fG+OQyl62-W z2hi&~rX5rxFaOp%E;>vS!PXCGT+ee$6|1y;yBubR2eh(@Mm(ddL{8i!^tm|M1!DCr zpZB~Zxx@xl>$zARd_Pg}KJUXB2)0*>(o1abfbLHR45V0;w|@6sde)`I-Jf`@ckFOy z(PkoZT}GE`+EyjJZ~>#Ls;!#eWx%E(i-e;|o8r{F1-X4C*1hIylW zMMrdx@wPH!ocZ^7aKVL3*JU<$b%o1EX2kLi*?Y3>m&T&@h!C5mMiEWR-c#$Z{D#_U zeQJEjUJH$=6X!pB>M3^e`Yn)FnaRovQoVw8t-`8j5gS{}&UmuyeK~?ZtbjN>a4(R% zc0jJIH>oVXzn^nIWR5kp)kSlx_hKKfec#-0AYv}+!#j^Z#ld6LxWWOZ9N7P9Z~^|e z(Z<0gNxWi>MFWk~)mTQrPt(HB$=(m6;OK+7+5jnp6haJv6hp|HB9ID_G73_1q6mZn z0%7KjQ~xgoo?cFF&cXkC0sl>@i>m^y)Fuso-fREpn7aCVIw&aUdfK~S6ck)BZZ58V zfFwdvyFW7^RUFMieb3Fw&-I^3woCt?RA00r^(}cxq@1)AQcmpp`=QiEvV;K74?_wGG^{`^HS04fGb?g4|NM~@ylbm-KnQ_sL)%a$$MwrvCY z0Vs0dzyY97RixO+fJA z!2^hiKoTejGziE52G!lWcduT(x_&|No;W zt=RyK;OdefzhEGZ3|MUI)wn#R7_E(&y-U>MiUmWvMVYvGZG9EIyo4R2MOh_#mo8tj zc;({7%a_h~SHJVKRY#ds{r11-H~0Ih-~PRE=AvJ#3`3XxXmdL<94OF^$txGgC6svXa$REKDKZGtxEG zH`Y1WJK8A7+t%${w{GFZbN3Ej>^yjL z>B^l;MLAyGin)8o)<&{^&z{-0t*xS?qOx}Hs;&9^r;*8aZ>?@ZW5a<34+IuC{BIH4 zaNx*=4Ier@7C6KUci6AYD+(#`$&qOew~46px_e|LXQ$^$O`esRFXzq;UbWnJj-9gd z&J?m|@+7*=m z{j6Hz8c~vxSdwa$T$Bo=7>o>z40R2Rb&X6yjEt=e46KYywSlC8!I!WbNhlg}^HVa@ zDsgLQ5y!)12ozOlmHvC<8@>W~YVa zRc58JN}^WF8J3BHSEXHQBxw{CWqyt5Pe1zcc<=pqJl-2~u{u@h49evA)EEFXD%_mm zK!>{vTpU3G7&JIC5U>n4>d;XKKOaaUVQWQIDI^hi(1`99^t2*R4jKhvL71{(+J<0% z$df>h<5oSExZz4I$d~xskJ%?6UtpjUfxeisV(Jk>0AH-v;q(3||K@avOcuFh7JJLzwD@Dg^=-W*(!z1BTsd%sz!oiV%NH+VFD}9?oc~ z2Kff&dRUqvi^IwQ%=E(78z+n~8R6>%5f@EWD9M7mGs<$&SP3D4rCvB$j^*BPpn^^T zg8~N%XaE%;NiwBE``Z39MH#mtdRJ49>8IT|6&NJx#dab2gY`W-*V;v&G+La>98hKY zIWp@^Om9=VY-BjStgPHQJx>o+HE7jKlN9}>r> zCCJyM#BJTMC29QLGaEBFQ<NBD9`e5G{ zsE?89)e5~vs4CLfDG3~cLxd5$FhY<@@PzDeA%`DA5JG}TD?AqUPePZk&eoRvKd>T{ zvrv;j|L(>WuzCE|93DR`;A(%(CWch>w_%lv%hqVa`CJ~sQ7hK0(Xf@P1%y(eRr1sV ewuaATWvlX81$kL9wReK--H^s4Mz=*}9{dgaZyQ(u diff --git a/front/dist/static/images/favicons/favicon-32x32.png b/front/dist/static/images/favicons/favicon-32x32.png index 957f500661794fded12906de8d183dee59c864a2..6c2e88a7168677d5dbabdebee45c8548f295616a 100644 GIT binary patch delta 1744 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 P-hjEu72{Wi?(zQv2}%3r delta 2675 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 NBH$gYXqMgy{{XbX*V+I8 diff --git a/front/dist/static/images/favicons/favicon.ico b/front/dist/static/images/favicons/favicon.ico index ec628ea22acf6696ddb792150cb740b893acacff..8272d095d28fd066decac955e6881d1a3b912497 100644 GIT binary patch literal 1150 zcmb`GOK4L;6ox0USVYu{5*IG2SfLAX;lfpYAjKq&f{Ka=x)fU#i!MY2Q@V8}uG)Xn7kvt)mkZ2p)rU`A6LLP0?JW85`Bvi!{=;)}{YPD)D z7K@14Y#zW^pWSX(IGs+W*Xy@;UR_<4fv&~H#qZH*baQ@wo~Ea#X<}l6{C>ZP+wCU! z{e;h3gTb)hWHK?M(I|T4^Z8@o8~6nu;$*W~T3%kJcsx$rZ)$3a0)YTI9F83Hw>=&Y z69hrhw?n%E=x=hl93_)U(PL(2hQ`Lm8i-%;dc6;TqFgS^pb_pq%9nN`L(w9mlg5N)S9usmS#^Ce$Hjv-Ja5#JsTK*fB^p#45*4NjG$H8;J zbrM{U+!FK+oZp1poe70PH=q|JeYIMpdc97?VsR%up@t3Q@eArbG&wn`%VaX`V1=KZ zd+^i*blc^;m>i0R9%j%Yv(j)0~Mvu5Y0VVDQL!4s$ zkuO=fTxyNQqWe_pXI(dM^=n?de0RKC`LyTmy;n+Mw9Xo z8biId@926V m4JZJgy8zBL`;u%|S|Y{<4#BFm$xg1#H9oBOePsCV8T$>28)udP literal 1150 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 delta 3830 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 E50%WC@c;k- delta 3874 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 diff --git a/front/dist/static/images/favicons/ms-icon-310x310.png b/front/dist/static/images/favicons/ms-icon-310x310.png index 56ceeb95c90cb0f3546656fe2702db44f3aa3990..a7b7aeaad731ca5d0ad1ac99a95a0ced893b7ad3 100644 GIT binary patch literal 33026 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 literal 10098 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 diff --git a/front/dist/static/images/favicons/ms-icon-70x70.png b/front/dist/static/images/favicons/ms-icon-70x70.png index 3fa12caee21f5d6d3f22a6288f541466ee5e87a9..00a5a65308bfbf045390b495cbb9dbac50ee63ce 100644 GIT binary patch delta 4454 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 XVo<=%pHr35hvI+*$_CkBf{yzScQQ!9 delta 2028 zcmVFCUynX~umVXZyqoPG8>mwhfXr_LV^GkfoI*80|eeShD#*7~ot1)!)S3v##( z7^$ceV?mu53+lvJP$$NMIx!a1iLszgj0JUKET|J>LCpV0m`^cK+zj%^>5Re2^jxRd`qyjfjc><7z!NEZN!jyvwC#@9t?eKtPpdGP{3kM#a z4P#p@4Hn?KaDVTB$zx2q@?s^uK?x2 z)$4Hins$aDhKNx>OAEZa6&B6c1cVuQuNU5W5B7hP-#`V-p94F#!}xY>Ob}8+*I&@N z1uk3(FGosP{Q_*>08Nd#y|f@+gzkioK8GEIMm6bjnw#=>NPcECF{7GOIZz6dYg7m^Kq?d2Dp$q# znDTOzX(>+{<2+-mmu^=X6eQ(==cW28W{ORkzp=JOqz-5q4Q*q!=adUVz__t6 zb2{|ggMXXdkWBOF5lf6hyZYN(VetZJZGlEh0*_L7LkwPd5uSerj-7xvw!`haB@$B! zEi|l5DPj5)m^}*^EN{g^=$zFt0j_t0<77UM>@npeCud6YFo`BtD|-I>lq_0MupujnHWceFY@xOkIDsqo#hB{NOh7j_oXOo zAzP6g;|P$Bc4IfG-MCuBR0<^%qZG`T2AkIFrNYO1;8YjI>kT6eWsy2M+F;dESp5=A zd4J%)vFBTo$2g=GUY-legpn}MY8jC|Mxa?y=*5^1&olW&RX>_U$R{cydyEjUa4sxa z3^S*}xG~TWhjlAq;XL^982oU&I$0a zEswh8Rq^dT4sNR$n6nAj05oQfu){}#zaK8$(6h{`6Jd07^@#B~Fca>fnXi8x zwUbKMV+5Q&2OGD++AZ+&DQaG%f--qbVgN2))h8i>f^;?Dhf>(;dU!&~SRHbo;E{P$Zdiyx!L^%k^d#K9uL}~u?`Pr6C0Me^XdyW^ zx+;NkRTYgG6TE(I@i)4p(8HyJIU!ZUqf;be29q$5gk;EZG{47OSC3YX)S5}Haa0^J zLJ!Bg_riC_;LHU*xyu*{gnuS%{~N#+&}L8A{Vesi7O7>nyzUfj(#$CRPinCxrjp$u=&LfKT?qx8GZ~LCi_@<0tii5bQbEg~LBW zPoI%l!;Z~LxO5eI`?6=v%I~?jNbS$$Lb{R|Jd5wYlORb=w(=dJ^Lt2$)Vli-+MP{f#^1Gd(L;Hy9tR2an0!4f(!QiZ+*Cz)-ym;&5ucY$b|@rw z6x}dUnCIBIEOzT7>hII*kJ%m+TafK}F=eVe*HP?=T7O2)kALz`WG+PMXf;B9Ut=qn z>Y@I6u?2NvET|J>L7f;2>cm*^FTWr?Kh&d@oB#j-C3HntbYx+4WjbSWWnpw>05UK# zFfA}PEigG$Fg7|dG&(XkD=;uRFfdhdib4PY03~!qSaf7zbY(hiZ)9m^c>ppnGB7PL zHZ3qYR4_I=F%C33GB_(RFgh?WBrG!ilWY Date: Wed, 21 Apr 2021 11:20:17 +0200 Subject: [PATCH 004/189] added loadPage Api call --- front/src/Api/Events/LoadPageEvent.ts | 13 +++++++++++++ front/src/Api/IframeListener.ts | 7 +++++++ front/src/Phaser/Game/GameScene.ts | 6 ++++++ front/src/iframe_api.ts | 11 +++++++++++ 4 files changed, 37 insertions(+) create mode 100644 front/src/Api/Events/LoadPageEvent.ts diff --git a/front/src/Api/Events/LoadPageEvent.ts b/front/src/Api/Events/LoadPageEvent.ts new file mode 100644 index 00000000..6f8b9bcf --- /dev/null +++ b/front/src/Api/Events/LoadPageEvent.ts @@ -0,0 +1,13 @@ +import * as tg from "generic-type-guard"; + + + +export const isLoadPageEvent = + new tg.IsInterface().withProperties({ + url: tg.isString, + }).get(); + +/** + * A message sent from the iFrame to the game to add a message in the chat. + */ +export type LoadPageEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index c875ebbb..f20e055c 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,7 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { isLoadPageEvent } from './Events/LoadPageEvent'; /** @@ -31,6 +32,10 @@ class IframeListener { private readonly _goToPageStream: Subject = new Subject(); public readonly goToPageStream = this._goToPageStream.asObservable(); + + private readonly _loadPageStream: Subject = new Subject(); + public readonly loadPageStream = this._loadPageStream.asObservable(); + private readonly _openCoWebSiteStream: Subject = new Subject(); public readonly openCoWebSiteStream = this._openCoWebSiteStream.asObservable(); @@ -103,6 +108,8 @@ class IframeListener { } else if (payload.type === 'removeBubble'){ this._removeBubbleStream.next(); + }else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)){ + this._loadPageStream.next(payload.data.url); } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 990f702c..ca13491c 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -841,6 +841,12 @@ ${escapedMessage} this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ this.userInputManager.restoreControls(); })); + this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url:string)=>{ + this.loadNextGame(url).then(()=>{ + this.scene.systems.settings.isTransition=true + this.onMapExit(url) + }) + })); let scriptedBubbleSprite : Sprite; this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{ scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white'); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..fb25c015 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,7 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import { LoadPageEvent } from './Api/Events/LoadPageEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -18,6 +19,7 @@ interface WorkAdventureApi { openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; openTab(url : string): void; goToPage(url : string): void; + loadPage(url : string): void; openCoWebSite(url : string): void; closeCoWebSite(): void; disablePlayerControl() : void; @@ -122,6 +124,15 @@ window.WA = { },'*'); }, + loadPage(url : string) : void{ + window.parent.postMessage({ + "type" : 'loadPage', + "data" : { + url + } as LoadPageEvent + },'*'); + }, + openCoWebSite(url : string) : void{ window.parent.postMessage({ "type" : 'openCoWebSite', From 006195e8cc78998cd51cf70925551780f5524b67 Mon Sep 17 00:00:00 2001 From: jonny Date: Wed, 21 Apr 2021 11:54:37 +0200 Subject: [PATCH 005/189] rewrote to run in event loop --- front/src/Phaser/Game/GameScene.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index ca13491c..56647cfc 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -74,6 +74,7 @@ import CanvasTexture = Phaser.Textures.CanvasTexture; import GameObject = Phaser.GameObjects.GameObject; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import DOMElement = Phaser.GameObjects.DOMElement; +import EVENT_TYPE =Phaser.Scenes.Events import {Subscription} from "rxjs"; import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; @@ -843,8 +844,9 @@ ${escapedMessage} })); this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url:string)=>{ this.loadNextGame(url).then(()=>{ - this.scene.systems.settings.isTransition=true - this.onMapExit(url) + this.events.once(EVENT_TYPE.POST_UPDATE,()=>{ + this.onMapExit(url); + }) }) })); let scriptedBubbleSprite : Sprite; From 3836d5037c95d2ec78a3a8855ed2c7c0df5ed20b Mon Sep 17 00:00:00 2001 From: jonny Date: Wed, 21 Apr 2021 15:51:01 +0200 Subject: [PATCH 006/189] game state can be read out by the client APIs # Conflicts: # front/src/Api/IframeListener.ts # front/src/Phaser/Game/GameScene.ts # front/src/iframe_api.ts --- front/src/Api/Events/ApiGameStateEvent.ts | 11 +++++++++++ front/src/Api/IframeListener.ts | 16 ++++++++++++++++ front/src/Phaser/Game/GameScene.ts | 7 +++++++ front/src/iframe_api.ts | 22 ++++++++++++++++++++++ front/src/utility.ts | 18 ++++++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 front/src/Api/Events/ApiGameStateEvent.ts create mode 100644 front/src/utility.ts diff --git a/front/src/Api/Events/ApiGameStateEvent.ts b/front/src/Api/Events/ApiGameStateEvent.ts new file mode 100644 index 00000000..2d5ec686 --- /dev/null +++ b/front/src/Api/Events/ApiGameStateEvent.ts @@ -0,0 +1,11 @@ +import * as tg from "generic-type-guard"; + +export const isGameStateEvent = + new tg.IsInterface().withProperties({ + roomId: tg.isString, + data:tg.isObject + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type GameStateEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index c875ebbb..ef7dc6a3 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,8 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { GameStateEvent } from './Events/ApiGameStateEvent'; +import { deepFreezeClone as deepFreezeClone } from '../utility'; /** @@ -52,6 +54,10 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + + private readonly _gameStateStream: Subject = new Subject(); + public readonly gameStateStream = this._gameStateStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -103,6 +109,8 @@ class IframeListener { } else if (payload.type === 'removeBubble'){ this._removeBubbleStream.next(); + }else if(payload.type=="getState"){ + this._gameStateStream.next(); } } @@ -111,6 +119,14 @@ class IframeListener { } + + sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) { + this.postMessage({ + 'type': 'gameState', + 'data': deepFreezeClone(gameStateEvent) + }); + } + /** * Allows the passed iFrame to send/receive messages via the API. */ diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 990f702c..ae9f23b8 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -841,6 +841,13 @@ ${escapedMessage} this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ this.userInputManager.restoreControls(); })); + this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(()=>{ + iframeListener.sendFrozenGameStateEvent({ + roomId:this.RoomId, + data: this.mapFile + }) + })); + let scriptedBubbleSprite : Sprite; this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{ scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white'); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..b1a8de48 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,7 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -24,6 +25,7 @@ interface WorkAdventureApi { restorePlayerControl() : void; displayBubble() : void; removeBubble() : void; + getGameState():Promise } declare global { @@ -74,7 +76,23 @@ class Popup { } } + +const stateResolvers:Array<(event:GameStateEvent)=>void> =[] + window.WA = { + + + + getGameState(){ + return new Promise((resolver,thrower)=>{ + stateResolvers.push(resolver); + window.parent.postMessage({ + type:"getState" + },"*") + }) + }, + + /** * Send a message in the chat. * Only the local user will receive this message. @@ -224,6 +242,10 @@ window.addEventListener('message', message => { if (callback) { callback(popup); } + }else if(payload.type=="gameState" && isGameStateEvent(payloadData)){ + stateResolvers.forEach(resolver=>{ + resolver(payloadData); + }) } } diff --git a/front/src/utility.ts b/front/src/utility.ts new file mode 100644 index 00000000..a95da6f8 --- /dev/null +++ b/front/src/utility.ts @@ -0,0 +1,18 @@ +export function deepFreezeClone (obj:T):Readonly { + return deepFreeze(JSON.parse(JSON.stringify(obj))); +} + +function deepFreeze (obj:T):T{ + Object.freeze(obj); + if (obj === undefined) { + return obj; + } + const propertyNames = Object.getOwnPropertyNames(obj) as Array; + propertyNames.forEach(function (prop) { + if (obj[prop] !== null&& (typeof obj[prop] === "object" || typeof obj[prop] === "function") && !Object.isFrozen(obj[prop])) { + deepFreezeClone(obj[prop]); + } + }); + + return obj; +} \ No newline at end of file From 79e530f0e60ac4e6156ad6afadbb3a8259fb6860 Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 27 Apr 2021 00:04:08 +0200 Subject: [PATCH 007/189] launch jsons + type fixes --- back/.vscode/launch.json | 27 +++++++++++++++++++++++++++ front/src/Phaser/Game/GameScene.ts | 2 +- pusher/.vscode/launch.json | 27 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 back/.vscode/launch.json create mode 100644 pusher/.vscode/launch.json diff --git a/back/.vscode/launch.json b/back/.vscode/launch.json new file mode 100644 index 00000000..77cdeee0 --- /dev/null +++ b/back/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Example", + "type": "node", + "request": "launch", + "runtimeExecutable": "node", + "runtimeArgs": [ + "--nolazy", + "-r", + "ts-node/register/transpile-only" + ], + "args": [ + "server.ts", + "--example", + "hello" + ], + "cwd": "${workspaceRoot}", + "internalConsoleOptions": "openOnSessionStart", + "skipFiles": [ + "/**", + "node_modules/**" + ] + } + ] +} \ No newline at end of file diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 2995fbc0..7c48239b 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -151,7 +151,7 @@ export class GameScene extends ResizableScene implements CenterListener { private GlobalMessageManager!: GlobalMessageManager; public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager; private connectionAnswerPromise: Promise; - private connectionAnswerPromiseResolve!: (value?: RoomJoinedMessageInterface | PromiseLike) => void; + private connectionAnswerPromiseResolve!: (value: RoomJoinedMessageInterface | PromiseLike) => void; // A promise that will resolve when the "create" method is called (signaling loading is ended) private createPromise: Promise; private createPromiseResolve!: (value?: void | PromiseLike) => void; diff --git a/pusher/.vscode/launch.json b/pusher/.vscode/launch.json new file mode 100644 index 00000000..2a3c02c2 --- /dev/null +++ b/pusher/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Pusher", + "type": "node", + "request": "launch", + "runtimeExecutable": "node", + "runtimeArgs": [ + "--nolazy", + "-r", + "ts-node/register/transpile-only" + ], + "args": [ + "server.ts", + "--example", + "hello" + ], + "cwd": "${workspaceRoot}", + "internalConsoleOptions": "openOnSessionStart", + "skipFiles": [ + "/**", + "node_modules/**" + ] + } + ] +} \ No newline at end of file From fafaabb6e7226e033c6a132d6f8ab270fcd11e1b Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 27 Apr 2021 11:59:22 +0200 Subject: [PATCH 008/189] script api can add menu commands # Conflicts: # front/src/Api/IframeListener.ts # front/src/iframe_api.ts --- front/src/Api/Events/MenuItemClickedEvent.ts | 10 ++++++ front/src/Api/Events/MenuItemRegisterEvent.ts | 10 ++++++ front/src/Api/IframeListener.ts | 15 +++++++++ front/src/Phaser/Menu/MenuScene.ts | 33 +++++++++++++++++-- front/src/iframe_api.ts | 21 ++++++++++-- 5 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 front/src/Api/Events/MenuItemClickedEvent.ts create mode 100644 front/src/Api/Events/MenuItemRegisterEvent.ts diff --git a/front/src/Api/Events/MenuItemClickedEvent.ts b/front/src/Api/Events/MenuItemClickedEvent.ts new file mode 100644 index 00000000..dd80c0f2 --- /dev/null +++ b/front/src/Api/Events/MenuItemClickedEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isMenuItemClickedEvent = + new tg.IsInterface().withProperties({ + menuItem: tg.isString + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type MenuItemClickedEvent = tg.GuardedType; diff --git a/front/src/Api/Events/MenuItemRegisterEvent.ts b/front/src/Api/Events/MenuItemRegisterEvent.ts new file mode 100644 index 00000000..98d4c7d3 --- /dev/null +++ b/front/src/Api/Events/MenuItemRegisterEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isMenuItemRegisterEvent = + new tg.IsInterface().withProperties({ + menutItem: tg.isString + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type MenuItemRegisterEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index c875ebbb..dbb45db3 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,8 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; +import { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; /** @@ -52,6 +54,8 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + private readonly _registerMenuCommandStream: Subject = new Subject(); + public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -103,6 +107,8 @@ class IframeListener { } else if (payload.type === 'removeBubble'){ this._removeBubbleStream.next(); + } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { + this._registerMenuCommandStream.next(payload.data.menutItem) } } @@ -187,6 +193,15 @@ class IframeListener { this.scripts.delete(scriptUrl); } + sendMenuClickedEvent(menuItem: string) { + this.postMessage({ + 'type': 'menuItemClicked', + 'data': { + menuItem: menuItem, + } as MenuItemClickedEvent + }); + } + sendUserInputChat(message: string) { this.postMessage({ 'type': 'userInputChat', diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 05cea305..9e11a873 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -9,6 +9,9 @@ import {connectionManager} from "../../Connexion/ConnectionManager"; import {GameConnexionTypes} from "../../Url/UrlManager"; import {WarningContainer, warningContainerHtml, warningContainerKey} from "../Components/WarningContainer"; import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream"; +import { HtmlUtils } from '../../WebRtc/HtmlUtils'; +import { iframeListener } from '../../Api/IframeListener'; +import { Subscription } from 'rxjs'; export const MenuSceneName = 'MenuScene'; const gameMenuKey = 'gameMenu'; @@ -36,11 +39,20 @@ export class MenuScene extends Phaser.Scene { private warningContainer: WarningContainer | null = null; private warningContainerTimeout: NodeJS.Timeout | null = null; + private apiMenus = [] + + + private subscriptions = new Subscription() constructor() { super({key: MenuSceneName}); this.gameQualityValue = localUserStore.getGameQualityValue(); this.videoQualityValue = localUserStore.getVideoQualityValue(); + + this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => { + this.addMenuOption(menuCommand); + + })) } preload () { @@ -266,13 +278,28 @@ export class MenuScene extends Phaser.Scene { }); } - private onMenuClick(event:MouseEvent) { - if((event?.target as HTMLInputElement).classList.contains('not-button')){ + public addMenuOption(menuText: string) { + const wrappingSection = document.createElement("section") + wrappingSection.innerHTML = `` + const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main"); + if (menuItemContainer) { + menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks")) + } + } + + private onMenuClick(event: MouseEvent) { + const htmlMenuItem = (event?.target as HTMLInputElement); + if (htmlMenuItem.classList.contains('not-button')) { return; } event.preventDefault(); - switch ((event?.target as HTMLInputElement).id) { + if (htmlMenuItem.classList.contains("fromApi")) { + iframeListener.sendMenuClickedEvent(htmlMenuItem.id) + return + } + + switch (htmlMenuItem.id) { case 'changeNameButton': this.closeSideMenu(); gameManager.leaveGame(this, LoginSceneName, new LoginScene()); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..1b68b0c1 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,8 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import { isMenuItemClickedEvent } from './Api/Events/MenuItemClickedEvent'; +import { MenuItemRegisterEvent } from './Api/Events/MenuItemRegisterEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -24,6 +26,7 @@ interface WorkAdventureApi { restorePlayerControl() : void; displayBubble() : void; removeBubble() : void; + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void } declare global { @@ -40,7 +43,7 @@ const enterStreams: Map> = new Map> = new Map>(); const popups: Map = new Map(); const popupCallbacks: Map> = new Map>(); - +const menuCallbacks: Map void> = new Map() let popupId = 0; interface ButtonDescriptor { /** @@ -172,6 +175,16 @@ window.WA = { popups.set(popupId, popup) return popup; }, + + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { + menuCallbacks.set(commandDescriptor, callback); + window.parent.postMessage({ + 'type': 'registerMenuCommand', + 'data': { + menutItem: commandDescriptor + } as MenuItemRegisterEvent + }, '*'); + }, /** * Listen to messages sent by the local user, in the chat. */ @@ -224,8 +237,12 @@ window.addEventListener('message', message => { if (callback) { callback(popup); } + } else if (payload.type == "menuItemClicked" && isMenuItemClickedEvent(payload.data)) { + const callback = menuCallbacks.get(payload.data.menuItem); + if (callback) { + callback(payload.data.menuItem) + } } - } // ... From 4069e878721deffa2d0e2b3833f62f05b834aca2 Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 27 Apr 2021 12:40:29 +0200 Subject: [PATCH 009/189] replace menu items if already present --- front/src/Phaser/Menu/MenuScene.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 9e11a873..348554b3 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -280,9 +280,11 @@ export class MenuScene extends Phaser.Scene { public addMenuOption(menuText: string) { const wrappingSection = document.createElement("section") - wrappingSection.innerHTML = `` + const excapedHtml = HtmlUtils.escapeHtml(menuText); + wrappingSection.innerHTML = `` const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main"); if (menuItemContainer) { + menuItemContainer.querySelector(`#${excapedHtml}.fromApi`)?.remove() menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks")) } } From 6295c8275ec6b3b3f71306ac5bb3af2ee4b2ea67 Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 27 Apr 2021 16:40:56 +0200 Subject: [PATCH 010/189] reset menu items on map change --- front/src/Phaser/Game/GameScene.ts | 3 +++ front/src/Phaser/Menu/MenuScene.ts | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 464c3ca4..1a7a2d9f 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -90,6 +90,7 @@ import {LayersIterator} from "../Map/LayersIterator"; import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; +import { MenuScene, MenuSceneName } from '../Menu/MenuScene'; export interface GameSceneInitInterface { initPosition: PointInterface|null, @@ -880,6 +881,8 @@ ${escapedMessage} const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey); urlManager.pushStartLayerNameToUrl(hash); + const menuScene: MenuScene = this.scene.get(MenuSceneName) as MenuScene + menuScene.reset() if (roomId !== this.scene.key) { if (this.scene.get(roomId) === null) { console.error("next room not loaded", exitKey); diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 348554b3..702fb67b 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -38,10 +38,6 @@ export class MenuScene extends Phaser.Scene { private menuButton!: Phaser.GameObjects.DOMElement; private warningContainer: WarningContainer | null = null; private warningContainerTimeout: NodeJS.Timeout | null = null; - - private apiMenus = [] - - private subscriptions = new Subscription() constructor() { super({key: MenuSceneName}); @@ -64,6 +60,13 @@ export class MenuScene extends Phaser.Scene { this.load.html(warningContainerKey, warningContainerHtml); } + reset() { + const addedMenuItems=[...this.menuElement.node.querySelectorAll(".fromApi")]; + for(let index=addedMenuItems.length-1;index>=0;index--){ + addedMenuItems[index].remove() + } + } + create() { this.menuElement = this.add.dom(closedSideMenuX, 30).createFromCache(gameMenuKey); this.menuElement.setOrigin(0); From 8f6c65384a7a17c3df659fed8b63e3cd06327d70 Mon Sep 17 00:00:00 2001 From: jonny Date: Thu, 29 Apr 2021 10:43:51 +0200 Subject: [PATCH 011/189] added example script for map exit --- maps/tests/goToPageScript.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/maps/tests/goToPageScript.js b/maps/tests/goToPageScript.js index 2b2cf33b..0404bdb4 100644 --- a/maps/tests/goToPageScript.js +++ b/maps/tests/goToPageScript.js @@ -1,14 +1,16 @@ +/// var zoneName = "popUpGoToPageZone"; var urlPricing = "https://workadventu.re/pricing"; var urlGettingStarted = "https://workadventu.re/getting-started"; -var isCoWebSiteOpened = false; +var urlRelativeMap = "script_api.json"; +var isCoWebSiteOpened = false; WA.onChatMessage((message => { - WA.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot'); + WA.sendChatMessage('Poly Parrot says: "' + message + '"', 'Poly Parrot'); })); WA.onEnterZone(zoneName, () => { - WA.openPopup("popUp","Open Links",[ + WA.openPopup("popUp", "Open Links", [ { label: "Open Tab", className: "popUpElement", @@ -18,27 +20,34 @@ WA.onEnterZone(zoneName, () => { }) }, { - label: "Go To Page", className : "popUpElement", - callback:(popup => { + label: "Go To Page", className: "popUpElement", + callback: (popup => { WA.goToPage(urlPricing); popup.close(); }) - } - , + }, { - label: "openCoWebSite", className : "popUpElement", - callback:(popup => { + label: "openCoWebSite", className: "popUpElement", + callback: (popup => { WA.openCoWebSite(urlPricing); isCoWebSiteOpened = true; popup.close(); }) + }, { + label: "load grouped map", + className: "popUpElement", + callback: (popup => { + WA.loadPage(urlRelativeMap); + popup.close(); + }) + }]); }) WA.onLeaveZone(zoneName, () => { - if (isCoWebSiteOpened) { + if(isCoWebSiteOpened) { WA.closeCoWebSite(); isCoWebSiteOpened = false; } From 99926a89b260f4ba9f570f71faac23f6f47fa211 Mon Sep 17 00:00:00 2001 From: jonny Date: Thu, 29 Apr 2021 10:55:01 +0200 Subject: [PATCH 012/189] added goToPage.json with the loadPAge Api call to the index.html --- maps/tests/index.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/maps/tests/index.html b/maps/tests/index.html index f53bbae9..bb25b19c 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -41,6 +41,14 @@ Testing scripting API with a script + + + + Success Failure Pending + + + Testing scripting API with a script + From 99bd9d88d9db60c0fa750720b7306ee52f90e3bb Mon Sep 17 00:00:00 2001 From: jonny Date: Thu, 29 Apr 2021 10:56:56 +0200 Subject: [PATCH 013/189] renamed api method "exitSceneTo" --- front/src/iframe_api.ts | 4 ++-- maps/tests/goToPageScript.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index fb25c015..56cffb1c 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -19,7 +19,7 @@ interface WorkAdventureApi { openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; openTab(url : string): void; goToPage(url : string): void; - loadPage(url : string): void; + exitSceneTo(url : string): void; openCoWebSite(url : string): void; closeCoWebSite(): void; disablePlayerControl() : void; @@ -124,7 +124,7 @@ window.WA = { },'*'); }, - loadPage(url : string) : void{ + exitSceneTo(url : string) : void{ window.parent.postMessage({ "type" : 'loadPage', "data" : { diff --git a/maps/tests/goToPageScript.js b/maps/tests/goToPageScript.js index 0404bdb4..af5b7f9f 100644 --- a/maps/tests/goToPageScript.js +++ b/maps/tests/goToPageScript.js @@ -39,7 +39,7 @@ WA.onEnterZone(zoneName, () => { label: "load grouped map", className: "popUpElement", callback: (popup => { - WA.loadPage(urlRelativeMap); + WA.exitSceneTo(urlRelativeMap); popup.close(); }) From cd77af318d779a10deb136b980d5dc1304340f30 Mon Sep 17 00:00:00 2001 From: jonny Date: Sat, 1 May 2021 19:44:14 +0200 Subject: [PATCH 014/189] added more properties # Conflicts: # front/src/Phaser/Game/GameScene.ts --- front/src/Api/Events/ApiGameStateEvent.ts | 21 ++++++++++++++- front/src/Phaser/Game/GameScene.ts | 32 ++++++++++++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/front/src/Api/Events/ApiGameStateEvent.ts b/front/src/Api/Events/ApiGameStateEvent.ts index 2d5ec686..4f4e98ff 100644 --- a/front/src/Api/Events/ApiGameStateEvent.ts +++ b/front/src/Api/Events/ApiGameStateEvent.ts @@ -1,9 +1,28 @@ import * as tg from "generic-type-guard"; +export const isPositionState = new tg.IsInterface().withProperties({ + x: tg.isNumber, + y: tg.isNumber +}).get() +export const isPlayerState = new tg.IsInterface() + .withStringIndexSignature( + new tg.IsInterface().withProperties({ + position: isPositionState, + pusherId: tg.isUnion(tg.isNumber, tg.isUndefined) + }).get() + ).get() + +export type PlayerStateObject = tg.GuardedType; + export const isGameStateEvent = new tg.IsInterface().withProperties({ roomId: tg.isString, - data:tg.isObject + data: tg.isObject, + mapUrl: tg.isString, + nickName: tg.isString, + uuid: tg.isUnion(tg.isString, tg.isUndefined), + players: isPlayerState, + startLayerName: tg.isUnion(tg.isString, tg.isNull) }).get(); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index ae9f23b8..3841ab07 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -80,6 +80,7 @@ import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoading import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; +import { PlayerStateObject } from '../../Api/Events/ApiGameStateEvent'; export interface GameSceneInitInterface { initPosition: PointInterface|null, @@ -841,10 +842,35 @@ ${escapedMessage} this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ this.userInputManager.restoreControls(); })); - this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => { + const playerObject: PlayerStateObject = { + [this.playerName]: { + position: { + x: this.CurrentPlayer.x, + y: this.CurrentPlayer.y + }, + pusherId: this.connection?.getUserId() + } + } + for (const mapPlayer of this.MapPlayers.children.entries) { + const remotePlayer: RemotePlayer = mapPlayer as RemotePlayer; + playerObject[remotePlayer.PlayerValue] = { + position: { + x: remotePlayer.x, + y: remotePlayer.y + }, + pusherId: remotePlayer.userId + + } + } iframeListener.sendFrozenGameStateEvent({ - roomId:this.RoomId, - data: this.mapFile + mapUrl: this.MapUrlFile, + nickName: this.playerName, + startLayerName: this.startLayerName, + uuid: localUserStore.getLocalUser()?.uuid, + roomId: this.RoomId, + data: this.mapFile, + players: playerObject }) })); From ffe03d40f5691c4114269916d68bbff78ba98c7b Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 00:27:21 +0200 Subject: [PATCH 015/189] option to update tile # Conflicts: # front/src/Api/Events/ApiUpdateTileEvent.ts # front/src/Api/IframeListener.ts # front/src/Phaser/Game/GameScene.ts --- front/src/Api/Events/ApiUpdateTileEvent.ts | 16 + front/src/Api/IframeListener.ts | 7 + front/src/Phaser/Game/GameScene.ts | 346 ++++++++++++--------- front/src/Phaser/Map/ITiledMap.ts | 21 +- 4 files changed, 227 insertions(+), 163 deletions(-) create mode 100644 front/src/Api/Events/ApiUpdateTileEvent.ts diff --git a/front/src/Api/Events/ApiUpdateTileEvent.ts b/front/src/Api/Events/ApiUpdateTileEvent.ts new file mode 100644 index 00000000..8a53fbe5 --- /dev/null +++ b/front/src/Api/Events/ApiUpdateTileEvent.ts @@ -0,0 +1,16 @@ + +import * as tg from "generic-type-guard"; +export const updateTile = "updateTile" + + +export const isUpdateTileEvent = + new tg.IsInterface().withProperties({ + x: tg.isNumber, + y: tg.isNumber, + tile: tg.isUnion(tg.isNumber, tg.isString), + layer: tg.isUnion(tg.isNumber, tg.isString) + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type UpdateTileEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index f20e055c..715eddc0 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -57,6 +57,9 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + private readonly _updateTileEvent: Subject = new Subject(); + public readonly updateTileEvent = this._updateTileEvent.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -110,6 +113,10 @@ class IframeListener { this._removeBubbleStream.next(); }else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)){ this._loadPageStream.next(payload.data.url); + } else if (payload.type == "getState") { + this._gameStateStream.next(); + } else if (payload.type == "updateTile" && isUpdateTileEvent(payload.data)) { + this._updateTileEvent.next(payload.data) } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7c48239b..138ca5ae 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1,4 +1,4 @@ -import {gameManager, HasMovedEvent} from "./GameManager"; +import { gameManager, HasMovedEvent } from "./GameManager"; import { GroupCreatedUpdatedMessageInterface, MessageUserJoined, @@ -9,7 +9,7 @@ import { PositionInterface, RoomJoinedMessageInterface } from "../../Connexion/ConnexionModels"; -import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player"; +import { CurrentGamerInterface, hasMovedEventName, Player } from "../Player/Player"; import { DEBUG_MODE, JITSI_PRIVATE_MODE, @@ -27,15 +27,15 @@ import { ITiledMapTileLayer, ITiledTileSet } from "../Map/ITiledMap"; -import {AddPlayerInterface} from "./AddPlayerInterface"; -import {PlayerAnimationDirections} from "../Player/Animation"; -import {PlayerMovement} from "./PlayerMovement"; -import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator"; -import {RemotePlayer} from "../Entity/RemotePlayer"; -import {Queue} from 'queue-typescript'; -import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer"; -import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene"; -import {lazyLoadPlayerCharacterTextures, loadCustomTexture} from "../Entity/PlayerTexturesLoadingManager"; +import { AddPlayerInterface } from "./AddPlayerInterface"; +import { PlayerAnimationDirections } from "../Player/Animation"; +import { PlayerMovement } from "./PlayerMovement"; +import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator"; +import { RemotePlayer } from "../Entity/RemotePlayer"; +import { Queue } from 'queue-typescript'; +import { SimplePeer, UserSimplePeerInterface } from "../../WebRtc/SimplePeer"; +import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene"; +import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager"; import { CenterListener, JITSI_MESSAGE_PROPERTIES, @@ -48,52 +48,56 @@ import { AUDIO_VOLUME_PROPERTY, AUDIO_LOOP_PROPERTY } from "../../WebRtc/LayoutManager"; -import {GameMap} from "./GameMap"; -import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager"; -import {mediaManager} from "../../WebRtc/MediaManager"; -import {ItemFactoryInterface} from "../Items/ItemFactoryInterface"; -import {ActionableItem} from "../Items/ActionableItem"; -import {UserInputManager} from "../UserInput/UserInputManager"; -import {UserMovedMessage} from "../../Messages/generated/messages_pb"; -import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils"; -import {connectionManager} from "../../Connexion/ConnectionManager"; -import {RoomConnection} from "../../Connexion/RoomConnection"; -import {GlobalMessageManager} from "../../Administration/GlobalMessageManager"; -import {userMessageManager} from "../../Administration/UserMessageManager"; -import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMessageManager"; -import {ResizableScene} from "../Login/ResizableScene"; -import {Room} from "../../Connexion/Room"; -import {jitsiFactory} from "../../WebRtc/JitsiFactory"; -import {urlManager} from "../../Url/UrlManager"; -import {audioManager} from "../../WebRtc/AudioManager"; -import {PresentationModeIcon} from "../Components/PresentationModeIcon"; -import {ChatModeIcon} from "../Components/ChatModeIcon"; -import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon"; -import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene"; -import {TextureError} from "../../Exception/TextureError"; -import {addLoader} from "../Components/Loader"; -import {ErrorSceneName} from "../Reconnecting/ErrorScene"; -import {localUserStore} from "../../Connexion/LocalUserStore"; -import {iframeListener} from "../../Api/IframeListener"; -import {HtmlUtils} from "../../WebRtc/HtmlUtils"; +import { GameMap } from "./GameMap"; +import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; +import { mediaManager } from "../../WebRtc/MediaManager"; +import { ItemFactoryInterface } from "../Items/ItemFactoryInterface"; +import { ActionableItem } from "../Items/ActionableItem"; +import { UserInputManager } from "../UserInput/UserInputManager"; +import { UserMovedMessage } from "../../Messages/generated/messages_pb"; +import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils"; +import { connectionManager } from "../../Connexion/ConnectionManager"; +import { RoomConnection } from "../../Connexion/RoomConnection"; +import { GlobalMessageManager } from "../../Administration/GlobalMessageManager"; +import { userMessageManager } from "../../Administration/UserMessageManager"; +import { ConsoleGlobalMessageManager } from "../../Administration/ConsoleGlobalMessageManager"; +import { ResizableScene } from "../Login/ResizableScene"; +import { Room } from "../../Connexion/Room"; +import { jitsiFactory } from "../../WebRtc/JitsiFactory"; +import { urlManager } from "../../Url/UrlManager"; +import { audioManager } from "../../WebRtc/AudioManager"; +import { PresentationModeIcon } from "../Components/PresentationModeIcon"; +import { ChatModeIcon } from "../Components/ChatModeIcon"; +import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon"; +import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene"; +import { TextureError } from "../../Exception/TextureError"; +import { addLoader } from "../Components/Loader"; +import { ErrorSceneName } from "../Reconnecting/ErrorScene"; +import { localUserStore } from "../../Connexion/LocalUserStore"; +import { iframeListener } from "../../Api/IframeListener"; +import { HtmlUtils } from "../../WebRtc/HtmlUtils"; import Texture = Phaser.Textures.Texture; import Sprite = Phaser.GameObjects.Sprite; import CanvasTexture = Phaser.Textures.CanvasTexture; import GameObject = Phaser.GameObjects.GameObject; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import DOMElement = Phaser.GameObjects.DOMElement; -import EVENT_TYPE =Phaser.Scenes.Events -import {Subscription} from "rxjs"; -import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream"; +import EVENT_TYPE = Phaser.Scenes.Events +import { Subscription } from "rxjs"; +import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; import {TextUtils} from "../Components/TextUtils"; import {LayersIterator} from "../Map/LayersIterator"; import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; +import { TextUtils } from "../Components/TextUtils"; +import { touchScreenManager } from "../../Touch/TouchScreenManager"; +import { PinchManager } from "../UserInput/PinchManager"; +import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick"; export interface GameSceneInitInterface { - initPosition: PointInterface|null, + initPosition: PointInterface | null, reconnecting: boolean } @@ -130,10 +134,10 @@ interface DeleteGroupEventInterface { const defaultStartLayerName = 'start'; export class GameScene extends ResizableScene implements CenterListener { - Terrains : Array; + Terrains: Array; CurrentPlayer!: CurrentGamerInterface; MapPlayers!: Phaser.Physics.Arcade.Group; - MapPlayersByKey : Map = new Map(); + MapPlayersByKey: Map = new Map(); Map!: Phaser.Tilemaps.Tilemap; Layers!: Array; Objects!: Array; @@ -143,10 +147,10 @@ export class GameScene extends ResizableScene implements CenterListener { startY!: number; circleTexture!: CanvasTexture; circleRedTexture!: CanvasTexture; - pendingEvents: Queue = new Queue(); - private initPosition: PositionInterface|null = null; + pendingEvents: Queue = new Queue(); + private initPosition: PositionInterface | null = null; private playersPositionInterpolator = new PlayersPositionInterpolator(); - public connection: RoomConnection|undefined; + public connection: RoomConnection | undefined; private simplePeer!: SimplePeer; private GlobalMessageManager!: GlobalMessageManager; public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager; @@ -155,7 +159,7 @@ export class GameScene extends ResizableScene implements CenterListener { // A promise that will resolve when the "create" method is called (signaling loading is ended) private createPromise: Promise; private createPromiseResolve!: (value?: void | PromiseLike) => void; - private iframeSubscriptionList! : Array; + private iframeSubscriptionList!: Array; MapUrlFile: string; RoomId: string; instance: string; @@ -174,19 +178,19 @@ export class GameScene extends ResizableScene implements CenterListener { private gameMap!: GameMap; private actionableItems: Map = new Map(); // The item that can be selected by pressing the space key. - private outlinedItem: ActionableItem|null = null; + private outlinedItem: ActionableItem | null = null; public userInputManager!: UserInputManager; - private isReconnecting: boolean|undefined = undefined; + private isReconnecting: boolean | undefined = undefined; private startLayerName!: string | null; private openChatIcon!: OpenChatIcon; private playerName!: string; private characterLayers!: string[]; - private companion!: string|null; - private messageSubscription: Subscription|null = null; - private popUpElements : Map = new Map(); - private originalMapUrl: string|undefined; + private companion!: string | null; + private messageSubscription: Subscription | null = null; + private popUpElements: Map = new Map(); + private originalMapUrl: string | undefined; - constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) { + constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) { super({ key: customKey ?? room.id }); @@ -222,13 +226,13 @@ export class GameScene extends ResizableScene implements CenterListener { this.load.image(joystickBaseKey, joystickBaseImg); this.load.image(joystickThumbKey, joystickThumbImg); } - this.load.on(FILE_LOAD_ERROR, (file: {src: string}) => { + this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => { // If we happen to be in HTTP and we are trying to load a URL in HTTPS only... (this happens only in dev environments) if (window.location.protocol === 'http:' && file.src === this.MapUrlFile && file.src.startsWith('http:') && this.originalMapUrl === undefined) { this.originalMapUrl = this.MapUrlFile; this.MapUrlFile = this.MapUrlFile.replace('http://', 'https://'); this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile); - this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => { + this.load.on('filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); }); return; @@ -242,7 +246,7 @@ export class GameScene extends ResizableScene implements CenterListener { this.originalMapUrl = this.MapUrlFile; this.MapUrlFile = this.MapUrlFile.replace('https://', 'http://'); this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile); - this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => { + this.load.on('filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); }); return; @@ -254,7 +258,7 @@ export class GameScene extends ResizableScene implements CenterListener { message: this.originalMapUrl ?? file.src }); }); - this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => { + this.load.on('filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); }); //TODO strategy to add access token @@ -266,7 +270,7 @@ export class GameScene extends ResizableScene implements CenterListener { this.onMapLoad(data); } - this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', {frameWidth: 32, frameHeight: 32}); + this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', { frameWidth: 32, frameHeight: 32 }); this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); } @@ -292,7 +296,7 @@ export class GameScene extends ResizableScene implements CenterListener { for (const layer of this.mapFile.layers) { if (layer.type === 'objectgroup') { for (const object of layer.objects) { - let objectsOfType: ITiledMapObject[]|undefined; + let objectsOfType: ITiledMapObject[] | undefined; if (!objects.has(object.type)) { objectsOfType = new Array(); } else { @@ -320,7 +324,7 @@ export class GameScene extends ResizableScene implements CenterListener { } default: continue; - //throw new Error('Unsupported object type: "'+ itemType +'"'); + //throw new Error('Unsupported object type: "'+ itemType +'"'); } itemFactory.preload(this.load); @@ -355,7 +359,7 @@ export class GameScene extends ResizableScene implements CenterListener { } //hook initialisation - init(initData : GameSceneInitInterface) { + init(initData: GameSceneInitInterface) { if (initData.initPosition !== undefined) { this.initPosition = initData.initPosition; //todo: still used? } @@ -433,7 +437,7 @@ export class GameScene extends ResizableScene implements CenterListener { this.Objects = new Array(); //initialise list of other player - this.MapPlayers = this.physics.add.group({immovable: true}); + this.MapPlayers = this.physics.add.group({ immovable: true }); //create input to move @@ -522,7 +526,7 @@ export class GameScene extends ResizableScene implements CenterListener { bottom: camera.scrollY + camera.height, }, this.companion - ).then((onConnect: OnConnectInterface) => { + ).then((onConnect: OnConnectInterface) => { this.connection = onConnect.connection; this.connection.onUserJoins((message: MessageUserJoined) => { @@ -673,23 +677,23 @@ export class GameScene extends ResizableScene implements CenterListener { const contextRed = this.circleRedTexture.context; contextRed.beginPath(); contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false); - //context.lineWidth = 5; + //context.lineWidth = 5; contextRed.strokeStyle = '#ff0000'; contextRed.stroke(); this.circleRedTexture.refresh(); } - private safeParseJSONstring(jsonString: string|undefined, propertyName: string) { + private safeParseJSONstring(jsonString: string | undefined, propertyName: string) { try { return jsonString ? JSON.parse(jsonString) : {}; - } catch(e) { + } catch (e) { console.warn('Invalid JSON found in property "' + propertyName + '" of the map:' + jsonString, e); return {} } } - private triggerOnMapLayerPropertyChange(){ + private triggerOnMapLayerPropertyChange() { this.gameMap.onPropertyChange('exitSceneUrl', (newValue, oldValue) => { if (newValue) this.onMapExit(newValue as string); }); @@ -700,22 +704,22 @@ export class GameScene extends ResizableScene implements CenterListener { if (newValue === undefined) { layoutManager.removeActionButton('openWebsite', this.userInputManager); coWebsiteManager.closeCoWebsite(); - }else{ + } else { const openWebsiteFunction = () => { coWebsiteManager.loadCoWebsite(newValue as string, this.MapUrlFile, allProps.get('openWebsiteAllowApi') as boolean | undefined, allProps.get('openWebsitePolicy') as string | undefined); layoutManager.removeActionButton('openWebsite', this.userInputManager); }; const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES); - if(openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) { + if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) { let message = allProps.get(WEBSITE_MESSAGE_PROPERTIES); - if(message === undefined){ + if (message === undefined) { message = 'Press SPACE or touch here to open web site'; } layoutManager.addActionButton('openWebsite', message.toString(), () => { openWebsiteFunction(); }, this.userInputManager); - }else{ + } else { openWebsiteFunction(); } } @@ -724,12 +728,12 @@ export class GameScene extends ResizableScene implements CenterListener { if (newValue === undefined) { layoutManager.removeActionButton('jitsiRoom', this.userInputManager); this.stopJitsi(); - }else{ + } else { const openJitsiRoomFunction = () => { const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance); - const jitsiUrl = allProps.get("jitsiUrl") as string|undefined; + const jitsiUrl = allProps.get("jitsiUrl") as string | undefined; if (JITSI_PRIVATE_MODE && !jitsiUrl) { - const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined; + const adminTag = allProps.get("jitsiRoomAdminTag") as string | undefined; this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag); } else { @@ -739,7 +743,7 @@ export class GameScene extends ResizableScene implements CenterListener { } const jitsiTriggerValue = allProps.get(TRIGGER_JITSI_PROPERTIES); - if(jitsiTriggerValue && jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) { + if (jitsiTriggerValue && jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) { let message = allProps.get(JITSI_MESSAGE_PROPERTIES); if (message === undefined) { message = 'Press SPACE or touch here to enter Jitsi Meet room'; @@ -747,7 +751,7 @@ export class GameScene extends ResizableScene implements CenterListener { layoutManager.addActionButton('jitsiRoom', message.toString(), () => { openJitsiRoomFunction(); }, this.userInputManager); - }else{ + } else { openJitsiRoomFunction(); } } @@ -760,8 +764,8 @@ export class GameScene extends ResizableScene implements CenterListener { } }); this.gameMap.onPropertyChange('playAudio', (newValue, oldValue, allProps) => { - const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number|undefined; - const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean|undefined; + const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number | undefined; + const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean | undefined; newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl(), volume, loop); }); // TODO: This legacy property should be removed at some point @@ -780,13 +784,13 @@ export class GameScene extends ResizableScene implements CenterListener { } private listenToIframeEvents(): void { - this.iframeSubscriptionList = []; - this.iframeSubscriptionList.push(iframeListener.openPopupStream.subscribe((openPopupEvent) => { + this.iframeSubscriptionList = []; + this.iframeSubscriptionList.push(iframeListener.openPopupStream.subscribe((openPopupEvent) => { - let objectLayerSquare : ITiledMapObject; + let objectLayerSquare: ITiledMapObject; const targetObjectData = this.getObjectLayerData(openPopupEvent.targetObject); - if (targetObjectData !== undefined){ - objectLayerSquare = targetObjectData; + if (targetObjectData !== undefined) { + objectLayerSquare = targetObjectData; } else { console.error("Error while opening a popup. Cannot find an object on the map with name '" + openPopupEvent.targetObject + "'. The first parameter of WA.openPopup() must be the name of a rectangle object in your map."); return; @@ -799,14 +803,14 @@ ${escapedMessage} html += buttonContainer; let id = 0; for (const button of openPopupEvent.buttons) { - html += ``; + html += ``; id++; } html += ''; - const domElement = this.add.dom(objectLayerSquare.x , + const domElement = this.add.dom(objectLayerSquare.x, objectLayerSquare.y).createFromHTML(html); - const container : HTMLDivElement = domElement.getChildByID("container") as HTMLDivElement; + const container: HTMLDivElement = domElement.getChildByID("container") as HTMLDivElement; container.style.width = objectLayerSquare.width + "px"; domElement.scale = 0; domElement.setClassName('popUpElement'); @@ -826,67 +830,99 @@ ${escapedMessage} id++; } this.tweens.add({ - targets : domElement , - scale : 1, - ease : "EaseOut", - duration : 400, + targets: domElement, + scale: 1, + ease: "EaseOut", + duration: 400, }); this.popUpElements.set(openPopupEvent.popupId, domElement); })); - this.iframeSubscriptionList.push(iframeListener.closePopupStream.subscribe((closePopupEvent) => { + this.iframeSubscriptionList.push(iframeListener.closePopupStream.subscribe((closePopupEvent) => { const popUpElement = this.popUpElements.get(closePopupEvent.popupId); if (popUpElement === undefined) { - console.error('Could not close popup with ID ', closePopupEvent.popupId,'. Maybe it has already been closed?'); + console.error('Could not close popup with ID ', closePopupEvent.popupId, '. Maybe it has already been closed?'); } this.tweens.add({ - targets : popUpElement , - scale : 0, - ease : "EaseOut", - duration : 400, - onComplete : () => { + targets: popUpElement, + scale: 0, + ease: "EaseOut", + duration: 400, + onComplete: () => { popUpElement?.destroy(); this.popUpElements.delete(closePopupEvent.popupId); }, }); })); - this.iframeSubscriptionList.push(iframeListener.disablePlayerControlStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.disablePlayerControlStream.subscribe(() => { this.userInputManager.disableControls(); })); - this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(() => { this.userInputManager.restoreControls(); })); - this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url:string)=>{ - this.loadNextGame(url).then(()=>{ - this.events.once(EVENT_TYPE.POST_UPDATE,()=>{ + this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url: string) => { + this.loadNextGame(url).then(() => { + this.events.once(EVENT_TYPE.POST_UPDATE, () => { this.onMapExit(url); }) }) })); - let scriptedBubbleSprite : Sprite; - this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{ - scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white'); + + this.iframeSubscriptionList.push(iframeListener.updateTileEvent.subscribe(event => { + const layer = this.Layers.find(layer => layer.layer.name == event.layer) + if (layer) { + const tile = layer.getTileAt(event.x, event.y) + if (typeof event.tile == "string") { + const tileIndex = this.getIndexForTileType(event.tile); + if (tileIndex) { + tile.index = tileIndex + } else { + return + } + } else { + tile.index = event.tile + } + this.scene.scene.sys.game.events.emit("contextrestored") + } + })) + + let scriptedBubbleSprite: Sprite; + this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(() => { + scriptedBubbleSprite = new Sprite(this, this.CurrentPlayer.x + 25, this.CurrentPlayer.y, 'circleSprite-white'); scriptedBubbleSprite.setDisplayOrigin(48, 48); this.add.existing(scriptedBubbleSprite); })); - this.iframeSubscriptionList.push(iframeListener.removeBubbleStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.removeBubbleStream.subscribe(() => { scriptedBubbleSprite.destroy(); })); } + private getIndexForTileType(tileType: string): number | undefined { + for (const tileset of this.mapFile.tilesets) { + if (tileset.tiles) { + for (const tilesetTile of tileset.tiles) { + if (tilesetTile.type == tileType) { + return tileset.firstgid + tilesetTile.id + } + } + } + } + return undefined + } + private getMapDirUrl(): string { return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); } private onMapExit(exitKey: string) { - const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); - if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey); + const { roomId, hash } = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); + if (!roomId) throw new Error('Could not find the room from its exit key: ' + exitKey); urlManager.pushStartLayerNameToUrl(hash); if (roomId !== this.scene.key) { if (this.scene.get(roomId) === null) { @@ -922,7 +958,7 @@ ${escapedMessage} this.simplePeer?.unregister(); this.messageSubscription?.unsubscribe(); - for(const iframeEvents of this.iframeSubscriptionList){ + for (const iframeEvents of this.iframeSubscriptionList) { iframeEvents.unsubscribe(); } } @@ -942,7 +978,7 @@ ${escapedMessage} private switchLayoutMode(): void { //if discussion is activated, this layout cannot be activated - if(mediaManager.activatedDiscussion){ + if (mediaManager.activatedDiscussion) { return; } const mode = layoutManager.getLayoutMode(); @@ -983,24 +1019,24 @@ ${escapedMessage} private initPositionFromLayerName(layerName: string) { for (const layer of this.gameMap.layersIterator) { - if ((layerName === layer.name || layer.name.endsWith('/'+layerName)) && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) { + if ((layerName === layer.name || layer.name.endsWith('/' + layerName)) && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) { const startPosition = this.startUser(layer); - this.startX = startPosition.x + this.mapFile.tilewidth/2; - this.startY = startPosition.y + this.mapFile.tileheight/2; + this.startX = startPosition.x + this.mapFile.tilewidth / 2; + this.startY = startPosition.y + this.mapFile.tileheight / 2; } } } - private getExitUrl(layer: ITiledMapLayer): string|undefined { - return this.getProperty(layer, "exitUrl") as string|undefined; + private getExitUrl(layer: ITiledMapLayer): string | undefined { + return this.getProperty(layer, "exitUrl") as string | undefined; } /** * @deprecated the map property exitSceneUrl is deprecated */ - private getExitSceneUrl(layer: ITiledMapLayer): string|undefined { - return this.getProperty(layer, "exitSceneUrl") as string|undefined; + private getExitSceneUrl(layer: ITiledMapLayer): string | undefined { + return this.getProperty(layer, "exitSceneUrl") as string | undefined; } private isStartLayer(layer: ITiledMapLayer): boolean { @@ -1011,8 +1047,8 @@ ${escapedMessage} return (this.getProperties(map, "script") as string[]).map((script) => (new URL(script, this.MapUrlFile)).toString()); } - private getProperty(layer: ITiledMapLayer|ITiledMap, name: string): string|boolean|number|undefined { - const properties: ITiledMapLayerProperty[]|undefined = layer.properties; + private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined { + const properties: ITiledMapLayerProperty[] | undefined = layer.properties; if (!properties) { return undefined; } @@ -1023,8 +1059,8 @@ ${escapedMessage} return obj.value; } - private getProperties(layer: ITiledMapLayer|ITiledMap, name: string): (string|number|boolean|undefined)[] { - const properties: ITiledMapLayerProperty[]|undefined = layer.properties; + private getProperties(layer: ITiledMapLayer | ITiledMap, name: string): (string | number | boolean | undefined)[] { + const properties: ITiledMapLayerProperty[] | undefined = layer.properties; if (!properties) { return []; } @@ -1032,30 +1068,30 @@ ${escapedMessage} } //todo: push that into the gameManager - private async loadNextGame(exitSceneIdentifier: string){ - const {roomId, hash} = Room.getIdFromIdentifier(exitSceneIdentifier, this.MapUrlFile, this.instance); + private async loadNextGame(exitSceneIdentifier: string) { + const { roomId, hash } = Room.getIdFromIdentifier(exitSceneIdentifier, this.MapUrlFile, this.instance); const room = new Room(roomId); await gameManager.loadMap(room, this.scene); } private startUser(layer: ITiledMapTileLayer): PositionInterface { const tiles = layer.data; - if (typeof(tiles) === 'string') { + if (typeof (tiles) === 'string') { throw new Error('The content of a JSON map must be filled as a JSON array, not as a string'); } - const possibleStartPositions : PositionInterface[] = []; - tiles.forEach((objectKey : number, key: number) => { - if(objectKey === 0){ + const possibleStartPositions: PositionInterface[] = []; + tiles.forEach((objectKey: number, key: number) => { + if (objectKey === 0) { return; } const y = Math.floor(key / layer.width); const x = key % layer.width; - possibleStartPositions.push({x: x * this.mapFile.tilewidth, y: y * this.mapFile.tilewidth}); + possibleStartPositions.push({ x: x * this.mapFile.tilewidth, y: y * this.mapFile.tilewidth }); }); // Get a value at random amongst allowed values if (possibleStartPositions.length === 0) { - console.warn('The start layer "'+layer.name+'" for this map is empty.'); + console.warn('The start layer "' + layer.name + '" for this map is empty.'); return { x: 0, y: 0 @@ -1067,12 +1103,12 @@ ${escapedMessage} //todo: in a dedicated class/function? initCamera() { - this.cameras.main.setBounds(0,0, this.Map.widthInPixels, this.Map.heightInPixels); + this.cameras.main.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels); this.updateCameraOffset(); this.cameras.main.setZoom(ZOOM_LEVEL); } - addLayer(Layer : Phaser.Tilemaps.StaticTilemapLayer){ + addLayer(Layer: Phaser.Tilemaps.StaticTilemapLayer) { this.Layers.push(Layer); } @@ -1082,7 +1118,7 @@ ${escapedMessage} this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => { //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) }); - Layer.setCollisionByProperty({collides: true}); + Layer.setCollisionByProperty({ collides: true }); if (DEBUG_MODE) { //debug code to see the collision hitbox of the object in the top layer Layer.renderDebug(this.add.graphics(), { @@ -1094,7 +1130,7 @@ ${escapedMessage} }); } - createCurrentPlayer(){ + createCurrentPlayer() { //TODO create animation moving between exit and start const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, this.characterLayers); try { @@ -1110,8 +1146,8 @@ ${escapedMessage} this.companion, this.companion !== null ? lazyLoadCompanionResource(this.load, this.companion) : undefined ); - }catch (err){ - if(err instanceof TextureError) { + } catch (err) { + if (err instanceof TextureError) { gameManager.leaveGame(this, SelectCharacterSceneName, new SelectCharacterScene()); } throw err; @@ -1172,7 +1208,7 @@ ${escapedMessage} } let shortestDistance: number = Infinity; - let selectedItem: ActionableItem|null = null; + let selectedItem: ActionableItem | null = null; for (const item of this.actionableItems.values()) { const distance = item.actionableDistance(x, y); if (distance !== null && distance < shortestDistance) { @@ -1206,7 +1242,7 @@ ${escapedMessage} * @param time * @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate. */ - update(time: number, delta: number) : void { + update(time: number, delta: number): void { mediaManager.setLastUpdateScene(); this.currentTick = time; this.CurrentPlayer.moveUser(delta); @@ -1263,8 +1299,8 @@ ${escapedMessage} const currentPlayerId = this.connection?.getUserId(); this.removeAllRemotePlayers(); // load map - usersPosition.forEach((userPosition : MessageUserPositionInterface) => { - if(userPosition.userId === currentPlayerId){ + usersPosition.forEach((userPosition: MessageUserPositionInterface) => { + if (userPosition.userId === currentPlayerId) { return; } this.addPlayer(userPosition); @@ -1274,16 +1310,16 @@ ${escapedMessage} /** * Called by the connexion when a new player arrives on a map */ - public addPlayer(addPlayerData : AddPlayerInterface) : void { + public addPlayer(addPlayerData: AddPlayerInterface): void { this.pendingEvents.enqueue({ type: "AddPlayerEvent", event: addPlayerData }); } - private doAddPlayer(addPlayerData : AddPlayerInterface): void { + private doAddPlayer(addPlayerData: AddPlayerInterface): void { //check if exist player, if exist, move position - if(this.MapPlayersByKey.has(addPlayerData.userId)){ + if (this.MapPlayersByKey.has(addPlayerData.userId)) { this.updatePlayerPosition({ userId: addPlayerData.userId, position: addPlayerData.position @@ -1344,10 +1380,10 @@ ${escapedMessage} } private doUpdatePlayerPosition(message: MessageUserMovedInterface): void { - const player : RemotePlayer | undefined = this.MapPlayersByKey.get(message.userId); + const player: RemotePlayer | undefined = this.MapPlayersByKey.get(message.userId); if (player === undefined) { //throw new Error('Cannot find player with ID "' + message.userId +'"'); - console.error('Cannot update position of player with ID "' + message.userId +'": player not found'); + console.error('Cannot update position of player with ID "' + message.userId + '": player not found'); return; } @@ -1391,7 +1427,7 @@ ${escapedMessage} doDeleteGroup(groupId: number): void { const group = this.groups.get(groupId); - if(!group){ + if (!group) { return; } group.destroy(); @@ -1419,7 +1455,7 @@ ${escapedMessage} bottom: camera.scrollY + camera.height, }); } - private getObjectLayerData(objectName : string) : ITiledMapObject| undefined{ + private getObjectLayerData(objectName: string): ITiledMapObject | undefined { for (const layer of this.mapFile.layers) { if (layer.type === 'objectgroup' && layer.name === 'floorLayer') { for (const object of layer.objects) { @@ -1454,7 +1490,7 @@ ${escapedMessage} xCenter /= ZOOM_LEVEL * RESOLUTION; yCenter /= ZOOM_LEVEL * RESOLUTION; - this.cameras.main.startFollow(this.CurrentPlayer, true, 1, 1, xCenter - this.game.renderer.width / 2, yCenter - this.game.renderer.height / 2); + this.cameras.main.startFollow(this.CurrentPlayer, true, 1, 1, xCenter - this.game.renderer.width / 2, yCenter - this.game.renderer.height / 2); } public onCenterChange(): void { @@ -1463,16 +1499,16 @@ ${escapedMessage} public startJitsi(roomName: string, jwt?: string): void { const allProps = this.gameMap.getCurrentProperties(); - const jitsiConfig = this.safeParseJSONstring(allProps.get("jitsiConfig") as string|undefined, 'jitsiConfig'); - const jitsiInterfaceConfig = this.safeParseJSONstring(allProps.get("jitsiInterfaceConfig") as string|undefined, 'jitsiInterfaceConfig'); - const jitsiUrl = allProps.get("jitsiUrl") as string|undefined; + const jitsiConfig = this.safeParseJSONstring(allProps.get("jitsiConfig") as string | undefined, 'jitsiConfig'); + const jitsiInterfaceConfig = this.safeParseJSONstring(allProps.get("jitsiInterfaceConfig") as string | undefined, 'jitsiInterfaceConfig'); + const jitsiUrl = allProps.get("jitsiUrl") as string | undefined; jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl); this.connection?.setSilent(true); mediaManager.hideGameOverlay(); //permit to stop jitsi when user close iframe - mediaManager.addTriggerCloseJitsiFrameButton('close-jisi',() => { + mediaManager.addTriggerCloseJitsiFrameButton('close-jisi', () => { this.stopJitsi(); }); } @@ -1486,7 +1522,7 @@ ${escapedMessage} } //todo: put this into an 'orchestrator' scene (EntryScene?) - private bannedUser(){ + private bannedUser() { this.cleanupClosingScene(); this.userInputManager.disableControls(); this.scene.start(ErrorSceneName, { diff --git a/front/src/Phaser/Map/ITiledMap.ts b/front/src/Phaser/Map/ITiledMap.ts index c4828911..27fe9f45 100644 --- a/front/src/Phaser/Map/ITiledMap.ts +++ b/front/src/Phaser/Map/ITiledMap.ts @@ -34,7 +34,7 @@ export interface ITiledMap { export interface ITiledMapLayerProperty { name: string; type: string; - value: string|boolean|number|undefined; + value: string | boolean | number | undefined; } /*export interface ITiledMapLayerBooleanProperty { @@ -63,7 +63,7 @@ export interface ITiledMapGroupLayer { export interface ITiledMapTileLayer { id?: number, - data: number[]|string; + data: number[] | string; height: number; name: string; opacity: number; @@ -114,7 +114,7 @@ export interface ITiledMapObject { gid: number; height: number; name: string; - properties: {[key: string]: string}; + properties: { [key: string]: string }; rotation: number; type: string; visible: boolean; @@ -130,12 +130,12 @@ export interface ITiledMapObject { /** * Polygon points */ - polygon: {x: number, y: number}[]; + polygon: { x: number, y: number }[]; /** * Polyline points */ - polyline: {x: number, y: number}[]; + polyline: { x: number, y: number }[]; text?: ITiledText } @@ -149,7 +149,7 @@ export interface ITiledText { underline?: boolean, italic?: boolean, strikeout?: boolean, - halign?: "center"|"right"|"justify"|"left" + halign?: "center" | "right" | "justify" | "left" } export interface ITiledTileSet { @@ -160,14 +160,14 @@ export interface ITiledTileSet { imagewidth: number; margin: number; name: string; - properties: {[key: string]: string}; + properties: { [key: string]: string }; spacing: number; tilecount: number; tileheight: number; tilewidth: number; transparentcolor: string; terrains: ITiledMapTerrain[]; - tiles: {[key: string]: { terrain: number[] }}; + tiles: Array; /** * Refers to external tileset file (should be JSON) @@ -175,6 +175,11 @@ export interface ITiledTileSet { source: string; } +export interface ITile { + id: number, + type?: string +} + export interface ITiledMapTerrain { name: string; tile: number; From bed45a831031f99c2af5d5fb7f11a4c773814dca Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 00:31:54 +0200 Subject: [PATCH 016/189] cherry pick conflicts --- front/src/Api/IframeListener.ts | 59 +++++++++++++++--------------- front/src/Phaser/Game/GameScene.ts | 5 --- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 715eddc0..f97e80ae 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -1,18 +1,19 @@ -import {Subject} from "rxjs"; -import {ChatEvent, isChatEvent} from "./Events/ChatEvent"; -import {IframeEvent, isIframeEventWrapper} from "./Events/IframeEvent"; -import {UserInputChatEvent} from "./Events/UserInputChatEvent"; +import { Subject } from "rxjs"; +import { ChatEvent, isChatEvent } from "./Events/ChatEvent"; +import { IframeEvent, isIframeEventWrapper } from "./Events/IframeEvent"; +import { UserInputChatEvent } from "./Events/UserInputChatEvent"; import * as crypto from "crypto"; -import {HtmlUtils} from "../WebRtc/HtmlUtils"; -import {EnterLeaveEvent} from "./Events/EnterLeaveEvent"; -import {isOpenPopupEvent, OpenPopupEvent} from "./Events/OpenPopupEvent"; -import {isOpenTabEvent, OpenTabEvent} from "./Events/OpenTabEvent"; -import {ButtonClickedEvent} from "./Events/ButtonClickedEvent"; -import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; -import {scriptUtils} from "./ScriptUtils"; -import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; -import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { HtmlUtils } from "../WebRtc/HtmlUtils"; +import { EnterLeaveEvent } from "./Events/EnterLeaveEvent"; +import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent"; +import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent"; +import { ButtonClickedEvent } from "./Events/ButtonClickedEvent"; +import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent"; +import { scriptUtils } from "./ScriptUtils"; +import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent"; +import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; import { isLoadPageEvent } from './Events/LoadPageEvent'; +import { isUpdateTileEvent, UpdateTileEvent } from './Events/ApiUpdateTileEvent'; /** @@ -32,7 +33,7 @@ class IframeListener { private readonly _goToPageStream: Subject = new Subject(); public readonly goToPageStream = this._goToPageStream.asObservable(); - + private readonly _loadPageStream: Subject = new Subject(); public readonly loadPageStream = this._loadPageStream.asObservable(); @@ -88,33 +89,31 @@ class IframeListener { } else if (payload.type === 'closePopup' && isClosePopupEvent(payload.data)) { this._closePopupStream.next(payload.data); } - else if(payload.type === 'openTab' && isOpenTabEvent(payload.data)) { + else if (payload.type === 'openTab' && isOpenTabEvent(payload.data)) { scriptUtils.openTab(payload.data.url); } - else if(payload.type === 'goToPage' && isGoToPageEvent(payload.data)) { + else if (payload.type === 'goToPage' && isGoToPageEvent(payload.data)) { scriptUtils.goToPage(payload.data.url); } - else if(payload.type === 'openCoWebSite' && isOpenCoWebsite(payload.data)) { + else if (payload.type === 'openCoWebSite' && isOpenCoWebsite(payload.data)) { scriptUtils.openCoWebsite(payload.data.url); } - else if(payload.type === 'closeCoWebSite') { + else if (payload.type === 'closeCoWebSite') { scriptUtils.closeCoWebSite(); } - else if (payload.type === 'disablePlayerControl'){ + else if (payload.type === 'disablePlayerControl') { this._disablePlayerControlStream.next(); } - else if (payload.type === 'restorePlayerControl'){ + else if (payload.type === 'restorePlayerControl') { this._enablePlayerControlStream.next(); } - else if (payload.type === 'displayBubble'){ + else if (payload.type === 'displayBubble') { this._displayBubbleStream.next(); } - else if (payload.type === 'removeBubble'){ + else if (payload.type === 'removeBubble') { this._removeBubbleStream.next(); - }else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)){ + } else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) { this._loadPageStream.next(payload.data.url); - } else if (payload.type == "getState") { - this._gameStateStream.next(); } else if (payload.type == "updateTile" && isUpdateTileEvent(payload.data)) { this._updateTileEvent.next(payload.data) } @@ -144,7 +143,7 @@ class IframeListener { const iframe = document.createElement('iframe'); iframe.id = this.getIFrameId(scriptUrl); iframe.style.display = 'none'; - iframe.src = '/iframe.html?script='+encodeURIComponent(scriptUrl); + iframe.src = '/iframe.html?script=' + encodeURIComponent(scriptUrl); // We are putting a sandbox on this script because it will run in the same domain as the main website. iframe.sandbox.add('allow-scripts'); @@ -168,8 +167,8 @@ class IframeListener { '\n' + '\n' + '\n' + - '\n' + - '\n' + + '\n' + + '\n' + '\n' + '\n'; @@ -186,14 +185,14 @@ class IframeListener { } private getIFrameId(scriptUrl: string): string { - return 'script'+crypto.createHash('md5').update(scriptUrl).digest("hex"); + return 'script' + crypto.createHash('md5').update(scriptUrl).digest("hex"); } unregisterScript(scriptUrl: string): void { const iFrameId = this.getIFrameId(scriptUrl); const iframe = HtmlUtils.getElementByIdOrFail(iFrameId); if (!iframe) { - throw new Error('Unknown iframe for script "'+scriptUrl+'"'); + throw new Error('Unknown iframe for script "' + scriptUrl + '"'); } this.unregisterIframe(iframe); iframe.remove(); diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 138ca5ae..9ed86716 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -86,11 +86,6 @@ import EVENT_TYPE = Phaser.Scenes.Events import { Subscription } from "rxjs"; import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; -import {TextUtils} from "../Components/TextUtils"; -import {LayersIterator} from "../Map/LayersIterator"; -import {touchScreenManager} from "../../Touch/TouchScreenManager"; -import {PinchManager} from "../UserInput/PinchManager"; -import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; import { TextUtils } from "../Components/TextUtils"; import { touchScreenManager } from "../../Touch/TouchScreenManager"; import { PinchManager } from "../UserInput/PinchManager"; From 8db72d2dfd4e707fa07e982d4afb549bc286303c Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 01:21:37 +0200 Subject: [PATCH 017/189] refactored to Array of tile --- front/src/Api/Events/ApiUpdateTileEvent.ts | 5 +++-- front/src/Phaser/Game/GameScene.ts | 26 ++++++++++++---------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/front/src/Api/Events/ApiUpdateTileEvent.ts b/front/src/Api/Events/ApiUpdateTileEvent.ts index 8a53fbe5..094596a4 100644 --- a/front/src/Api/Events/ApiUpdateTileEvent.ts +++ b/front/src/Api/Events/ApiUpdateTileEvent.ts @@ -3,13 +3,14 @@ import * as tg from "generic-type-guard"; export const updateTile = "updateTile" -export const isUpdateTileEvent = +export const isUpdateTileEvent = tg.isArray( new tg.IsInterface().withProperties({ x: tg.isNumber, y: tg.isNumber, tile: tg.isUnion(tg.isNumber, tg.isString), layer: tg.isUnion(tg.isNumber, tg.isString) - }).get(); + }).get() +); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9ed86716..5687c7e5 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -868,18 +868,20 @@ ${escapedMessage} })); this.iframeSubscriptionList.push(iframeListener.updateTileEvent.subscribe(event => { - const layer = this.Layers.find(layer => layer.layer.name == event.layer) - if (layer) { - const tile = layer.getTileAt(event.x, event.y) - if (typeof event.tile == "string") { - const tileIndex = this.getIndexForTileType(event.tile); - if (tileIndex) { - tile.index = tileIndex + for (const eventTile of event) { + const layer = this.Layers.find(layer => layer.layer.name == eventTile.layer) + if (layer) { + const tile = layer.getTileAt(eventTile.x, eventTile.y) + if (typeof eventTile.tile == "string") { + const tileIndex = this.getIndexForTileType(eventTile.tile); + if (tileIndex) { + tile.index = tileIndex + } else { + return + } } else { - return + tile.index = eventTile.tile } - } else { - tile.index = event.tile } this.scene.scene.sys.game.events.emit("contextrestored") } @@ -898,7 +900,7 @@ ${escapedMessage} } - private getIndexForTileType(tileType: string): number | undefined { + private getIndexForTileType(tileType: string): number | null { for (const tileset of this.mapFile.tilesets) { if (tileset.tiles) { for (const tilesetTile of tileset.tiles) { @@ -908,7 +910,7 @@ ${escapedMessage} } } } - return undefined + return null } private getMapDirUrl(): string { From 46996f70497666bf79f5f3dde624252634eb3ae9 Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 01:27:17 +0200 Subject: [PATCH 018/189] moved event trigger out of index array --- front/src/Phaser/Game/GameScene.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 5687c7e5..674087e0 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -883,8 +883,8 @@ ${escapedMessage} tile.index = eventTile.tile } } - this.scene.scene.sys.game.events.emit("contextrestored") } + this.scene.scene.sys.game.events.emit("contextrestored") })) let scriptedBubbleSprite: Sprite; From a6ba8d41b9a9c7d73cec0452b313c34bfd9e38b4 Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 10 May 2021 11:19:18 +0200 Subject: [PATCH 019/189] implement show/hide layer with scripting --- front/src/Api/Events/LayerEvent.ts | 10 ++++++++++ front/src/Api/IframeListener.ts | 15 ++++++++++++++- front/src/iframe_api.ts | 21 ++++++++++++++++++++ maps/tests/iframe.html | 31 +++++++++++++++++++++++++++++- maps/tests/iframe_api.json | 25 +++++++++++++++++++++--- 5 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 front/src/Api/Events/LayerEvent.ts diff --git a/front/src/Api/Events/LayerEvent.ts b/front/src/Api/Events/LayerEvent.ts new file mode 100644 index 00000000..f854248b --- /dev/null +++ b/front/src/Api/Events/LayerEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isLayerEvent = + new tg.IsInterface().withProperties({ + name: tg.isString, + }).get(); +/** + * A message sent from the iFrame to the game to show/hide a layer. + */ +export type LayerEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 7e51a281..0820785a 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,7 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import {isLayerEvent, LayerEvent} from "./Events/LayerEvent"; /** @@ -52,6 +53,12 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + private readonly _showLayerStream: Subject = new Subject(); + public readonly showLayerStream = this._showLayerStream.asObservable(); + + private readonly _hideLayerStream: Subject = new Subject(); + public readonly hideLayerStream = this._hideLayerStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -73,7 +80,13 @@ class IframeListener { const payload = message.data; if (isIframeEventWrapper(payload)) { - if (payload.type === 'chat' && isChatEvent(payload.data)) { + if (payload.type ==='showLayer' && isLayerEvent(payload.data)) { + console.log('showLayer 2'); + this._showLayerStream.next(payload.data); + } else if (payload.type === 'hideLayer' && isLayerEvent(payload.data)) { + console.log('hideLayer 2'); + this._hideLayerStream.next(payload.data); + } else if (payload.type === 'chat' && isChatEvent(payload.data)) { this._chatStream.next(payload.data); } else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) { this._openPopupStream.next(payload.data); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..0b9fac46 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,7 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import {LayerEvent} from "./Api/Events/LayerEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -24,6 +25,8 @@ interface WorkAdventureApi { restorePlayerControl() : void; displayBubble() : void; removeBubble() : void; + showLayer(layer: string) : void; + hideLayer(layer: string) : void; } declare global { @@ -88,6 +91,24 @@ window.WA = { } as ChatEvent }, '*'); }, + showLayer(layer: string) : void { + console.log('showLayer'); + window.parent.postMessage({ + 'type' : 'showLayer', + 'data' : { + 'name' : layer + } as LayerEvent + }, '*'); + }, + hideLayer(layer: string) : void { + console.log('hideLayer'); + window.parent.postMessage({ + 'type' : 'hideLayer', + 'data' : { + 'name' : layer + } as LayerEvent + }, '*'); + }, disablePlayerControl() : void { window.parent.postMessage({'type' : 'disablePlayerControl'},'*'); }, diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index 23bfb479..4c7cd044 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -3,7 +3,7 @@ @@ -21,5 +21,34 @@ document.getElementById('chatSent').append(chatDiv); })); +

+ +
+ + diff --git a/maps/tests/iframe_api.json b/maps/tests/iframe_api.json index fa138500..db840b3f 100644 --- a/maps/tests/iframe_api.json +++ b/maps/tests/iframe_api.json @@ -1,4 +1,11 @@ { "compressionlevel":-1, + "editorsettings": + { + "export": + { + "target":"." + } + }, "height":10, "infinite":false, "layers":[ @@ -49,6 +56,18 @@ "x":0, "y":0 }, + { + "data":[0, 0, 93, 0, 104, 0, 0, 0, 0, 0, 0, 0, 104, 0, 115, 0, 0, 0, 93, 0, 0, 0, 115, 0, 0, 0, 93, 0, 104, 0, 0, 0, 0, 0, 0, 0, 104, 0, 115, 93, 0, 0, 0, 0, 0, 0, 115, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":6, + "name":"Metadata", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, { "draworder":"topdown", "id":3, @@ -78,11 +97,11 @@ "x":0, "y":0 }], - "nextlayerid":6, + "nextlayerid":7, "nextobjectid":3, "orientation":"orthogonal", "renderorder":"right-down", - "tiledversion":"2021.03.23", + "tiledversion":"1.4.3", "tileheight":32, "tilesets":[ { @@ -100,6 +119,6 @@ }], "tilewidth":32, "type":"map", - "version":1.5, + "version":1.4, "width":10 } \ No newline at end of file From 841bf29764305e1fbdccf15eebb85aab5a9237fe Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 10 May 2021 11:20:07 +0200 Subject: [PATCH 020/189] auto update show/hide layer --- front/src/Phaser/Game/DirtyScene.ts | 1 + front/src/Phaser/Game/GameScene.ts | 34 ++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/front/src/Phaser/Game/DirtyScene.ts b/front/src/Phaser/Game/DirtyScene.ts index 03ec9a95..e88e11f6 100644 --- a/front/src/Phaser/Game/DirtyScene.ts +++ b/front/src/Phaser/Game/DirtyScene.ts @@ -35,6 +35,7 @@ export abstract class DirtyScene extends ResizableScene { this.events.on(Events.RENDER, () => { this.objectListChanged = false; + this.dirty = false; }); } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 65129787..6939721e 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -91,6 +91,7 @@ import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; import {waScaleManager} from "../Services/WaScaleManager"; +import {LayerEvent} from "../../Api/Events/LayerEvent"; export interface GameSceneInitInterface { initPosition: PointInterface|null, @@ -839,7 +840,7 @@ ${escapedMessage} this.popUpElements.set(openPopupEvent.popupId, domElement); })); - this.iframeSubscriptionList.push(iframeListener.closePopupStream.subscribe((closePopupEvent) => { + this.iframeSubscriptionList.push(iframeListener.closePopupStream.subscribe((closePopupEvent) => { const popUpElement = this.popUpElements.get(closePopupEvent.popupId); if (popUpElement === undefined) { console.error('Could not close popup with ID ', closePopupEvent.popupId,'. Maybe it has already been closed?'); @@ -857,26 +858,48 @@ ${escapedMessage} }); })); - this.iframeSubscriptionList.push(iframeListener.disablePlayerControlStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.disablePlayerControlStream.subscribe(()=>{ this.userInputManager.disableControls(); })); - this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ this.userInputManager.restoreControls(); })); let scriptedBubbleSprite : Sprite; - this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(()=>{ scriptedBubbleSprite = new Sprite(this,this.CurrentPlayer.x + 25,this.CurrentPlayer.y,'circleSprite-white'); scriptedBubbleSprite.setDisplayOrigin(48, 48); this.add.existing(scriptedBubbleSprite); })); - this.iframeSubscriptionList.push(iframeListener.removeBubbleStream.subscribe(()=>{ + this.iframeSubscriptionList.push(iframeListener.removeBubbleStream.subscribe(()=>{ scriptedBubbleSprite.destroy(); })); + this.iframeSubscriptionList.push(iframeListener.showLayerStream.subscribe((layerEvent)=>{ + console.log('showLayer 3'); + this.setLayerVisibility(layerEvent.name, true); + })); + + this.iframeSubscriptionList.push(iframeListener.hideLayerStream.subscribe((layerEvent)=>{ + console.log('hideLayer 3'); + this.setLayerVisibility(layerEvent.name, false); + })); + } + private setLayerVisibility(layerName: string, visible: boolean): void { + console.log('visibility'); + const layer = this.Layers.find((layer) => layer.layer.name === layerName); + if (layer === undefined) { + console.warn('Could not find layer "' + layerName + '" when calling WA.hideLayer / WA.showLayer'); + return; + } + layer.setVisible(visible); + this.dirty = true; + } + + private getMapDirUrl(): string { return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); } @@ -1207,7 +1230,6 @@ ${escapedMessage} * @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate. */ update(time: number, delta: number) : void { - this.dirty = false; mediaManager.updateScene(); this.currentTick = time; if (this.CurrentPlayer.isMoving()) { From 8edd29abaab1c1d671e8cc9cca3bb465e2aec43d Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 10 May 2021 14:43:00 +0200 Subject: [PATCH 021/189] suppression console.log --- maps/tests/iframe.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index 135096f8..116bbfd9 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -2,9 +2,6 @@ - @@ -22,17 +19,15 @@ }));
- +
From 973b3405ef3ff54809e110f6a6c09fc2e54ed9fe Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 10 May 2021 15:10:11 +0200 Subject: [PATCH 022/189] documentation of show/hide layer --- docs/maps/api-reference.md | 29 +++++++++++++++++++++++++++++ maps/tests/iframe.html | 10 +++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 9891a88a..3a893474 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -235,3 +235,32 @@ mySound.play(config); // ... mySound.stop(); ``` + +### Show / Hide a layer + +``` +WA.showLayer(layerName : string): void +WA.hideLayer(layerName : string) : void +``` +These 2 methods can be used to show and hide a layer. + +Example : + +```javascript +
+ + +
+ +``` + + diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index 116bbfd9..c5c30972 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -19,15 +19,15 @@ }));
- +
From cf811c547b615ac9bbca9be19aa84e2aafe5a5f0 Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 10 May 2021 17:29:50 +0200 Subject: [PATCH 023/189] documentation of show/hide layer simplification --- docs/maps/api-reference.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 3a893474..d7d7f385 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -247,20 +247,9 @@ These 2 methods can be used to show and hide a layer. Example : ```javascript -
- - -
- +WA.showLayer('bottom'); +//... +WA.hideLayer('bottom'); ``` From 8e136cebe8a787433a33b13153f1e8f0d9a9f625 Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 21:27:17 +0200 Subject: [PATCH 024/189] added callback on playermove - gets quite delayed after walking for a few seconds --- front/src/Api/Events/HasMovedEvent.ts | 19 ++++++ front/src/Api/Events/IframeEvent.ts | 4 +- front/src/Api/IframeListener.ts | 34 +++++++---- front/src/Phaser/Game/GameManager.ts | 7 +-- front/src/Phaser/Game/GameScene.ts | 8 ++- front/src/Phaser/Game/PlayerMovement.ts | 7 ++- .../Game/PlayersPositionInterpolator.ts | 8 +-- front/src/iframe_api.ts | 61 ++++++++++++++----- 8 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 front/src/Api/Events/HasMovedEvent.ts diff --git a/front/src/Api/Events/HasMovedEvent.ts b/front/src/Api/Events/HasMovedEvent.ts new file mode 100644 index 00000000..fef8e731 --- /dev/null +++ b/front/src/Api/Events/HasMovedEvent.ts @@ -0,0 +1,19 @@ +import * as tg from "generic-type-guard"; + + + +export const isHasMovedEvent = + new tg.IsInterface().withProperties({ + direction: tg.isString, + moving: tg.isBoolean, + x: tg.isNumber, + y: tg.isNumber + }).get(); + +/** + * A message sent from the iFrame to the game to add a message in the chat. + */ +export type HasMovedEvent = tg.GuardedType; + + +export type HasMovedEventCallback = (event: HasMovedEvent) => void diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index c1ad6955..f28ea85e 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,11 +1,11 @@ - import { GameStateEvent } from './ApiGameStateEvent'; import { ButtonClickedEvent } from './ButtonClickedEvent'; import { ChatEvent } from './ChatEvent'; import { ClosePopupEvent } from './ClosePopupEvent'; import { EnterLeaveEvent } from './EnterLeaveEvent'; import { GoToPageEvent } from './GoToPageEvent'; +import { HasMovedEvent } from './HasMovedEvent'; import { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent'; import { OpenPopupEvent } from './OpenPopupEvent'; import { OpenTabEvent } from './OpenTabEvent'; @@ -30,6 +30,7 @@ export type IframeEventMap = { restorePlayerControl: null displayBubble: null removeBubble: null + enableMoveEvents: undefined } export interface IframeEvent { type: T; @@ -46,6 +47,7 @@ export interface IframeResponseEventMap { leaveEvent: EnterLeaveEvent buttonClickedEvent: ButtonClickedEvent gameState: GameStateEvent + hasMovedEvent: HasMovedEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index fcf4e854..f10d0fc1 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -14,6 +14,7 @@ import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMa import { UserInputChatEvent } from "./Events/UserInputChatEvent"; import { GameStateEvent } from './Events/ApiGameStateEvent'; import { deepFreezeClone as deepFreezeClone } from '../utility'; +import { HasMovedEvent } from './Events/HasMovedEvent'; /** @@ -21,6 +22,7 @@ import { deepFreezeClone as deepFreezeClone } from '../utility'; * Also allows to send messages to those iframes. */ class IframeListener { + private readonly _chatStream: Subject = new Subject(); public readonly chatStream = this._chatStream.asObservable(); @@ -54,12 +56,13 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); - + private readonly _gameStateStream: Subject = new Subject(); public readonly gameStateStream = this._gameStateStream.asObservable(); private readonly iframes = new Set(); private readonly scripts = new Map(); + private sendMoveEvents: boolean = false; init() { window.addEventListener("message", (message: TypedMessageEvent>) => { @@ -101,20 +104,18 @@ class IframeListener { } else if (payload.type === 'closeCoWebSite') { scriptUtils.closeCoWebSite(); - } - else if (payload.type === 'disablePlayerControl') { + } else if (payload.type === 'disablePlayerControl') { this._disablePlayerControlStream.next(); - } - else if (payload.type === 'restorePlayerControl') { + } else if (payload.type === 'restorePlayerControl') { this._enablePlayerControlStream.next(); - } - else if (payload.type === 'displayBubble') { + } else if (payload.type === 'displayBubble') { this._displayBubbleStream.next(); - } - else if (payload.type === 'removeBubble') { + } else if (payload.type === 'removeBubble') { this._removeBubbleStream.next(); - }else if(payload.type=="getState"){ + } else if (payload.type == "getState") { this._gameStateStream.next(); + } else if (payload.type == "enableMoveEvents") { + this.sendMoveEvents = true } } @@ -123,11 +124,11 @@ class IframeListener { } - + sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) { this.postMessage({ 'type': 'gameState', - 'data': deepFreezeClone(gameStateEvent) + 'data': deepFreezeClone(gameStateEvent) }); } @@ -234,6 +235,15 @@ class IframeListener { }); } + hasMovedEvent(event: HasMovedEvent) { + if (this.sendMoveEvents) { + this.postMessage({ + 'type': 'hasMovedEvent', + 'data': event + }); + } + } + sendButtonClickedEvent(popupId: number, buttonId: number): void { this.postMessage({ 'type': 'buttonClickedEvent', diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 6047d430..157e8e80 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -8,12 +8,7 @@ import {SelectCharacterSceneName} from "../Login/SelectCharacterScene"; import {EnableCameraSceneName} from "../Login/EnableCameraScene"; import {localUserStore} from "../../Connexion/LocalUserStore"; -export interface HasMovedEvent { - direction: string; - moving: boolean; - x: number; - y: number; -} + /** * This class should be responsible for any scene starting/stopping diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7d0d51d3..63efa3e6 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1,4 +1,4 @@ -import {gameManager, HasMovedEvent} from "./GameManager"; +import { gameManager } from "./GameManager"; import { GroupCreatedUpdatedMessageInterface, MessageUserJoined, @@ -91,7 +91,8 @@ import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; import { PlayerStateObject } from '../../Api/Events/ApiGameStateEvent'; -import {waScaleManager} from "../Services/WaScaleManager"; +import { waScaleManager } from "../Services/WaScaleManager"; +import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; export interface GameSceneInitInterface { initPosition: PointInterface|null, @@ -631,6 +632,9 @@ export class GameScene extends DirtyScene implements CenterListener { //listen event to share position of user this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this)) + this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => { + iframeListener.hasMovedEvent(event) + }) this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this)) this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => { this.gameMap.setPosition(event.x, event.y); diff --git a/front/src/Phaser/Game/PlayerMovement.ts b/front/src/Phaser/Game/PlayerMovement.ts index eb1a5d1b..18c3ee0c 100644 --- a/front/src/Phaser/Game/PlayerMovement.ts +++ b/front/src/Phaser/Game/PlayerMovement.ts @@ -1,6 +1,7 @@ -import {HasMovedEvent} from "./GameManager"; -import {MAX_EXTRAPOLATION_TIME} from "../../Enum/EnvironmentVariable"; -import {PositionInterface} from "../../Connexion/ConnexionModels"; + +import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable"; +import { PositionInterface } from "../../Connexion/ConnexionModels"; +import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; export class PlayerMovement { public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasMovedEvent, private endTick: number) { diff --git a/front/src/Phaser/Game/PlayersPositionInterpolator.ts b/front/src/Phaser/Game/PlayersPositionInterpolator.ts index 3ac87397..321396e2 100644 --- a/front/src/Phaser/Game/PlayersPositionInterpolator.ts +++ b/front/src/Phaser/Game/PlayersPositionInterpolator.ts @@ -2,13 +2,13 @@ * This class is in charge of computing the position of all players. * Player movement is delayed by 200ms so position depends on ticks. */ -import {PlayerMovement} from "./PlayerMovement"; -import {HasMovedEvent} from "./GameManager"; +import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; +import { PlayerMovement } from "./PlayerMovement"; export class PlayersPositionInterpolator { playerMovements: Map = new Map(); - updatePlayerPosition(userId: number, playerMovement: PlayerMovement) : void { + updatePlayerPosition(userId: number, playerMovement: PlayerMovement): void { this.playerMovements.set(userId, playerMovement); } @@ -16,7 +16,7 @@ export class PlayersPositionInterpolator { this.playerMovements.delete(userId); } - getUpdatedPositions(tick: number) : Map { + getUpdatedPositions(tick: number): Map { const positions = new Map(); this.playerMovements.forEach((playerMovement: PlayerMovement, userId: number) => { if (playerMovement.isOutdated(tick)) { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index cb55f1aa..9a3e63b0 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,5 +1,5 @@ import { ChatEvent } from "./Api/Events/ChatEvent"; -import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; +import { IframeEvent, IframeEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; import { Subject } from "rxjs"; import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent"; @@ -10,6 +10,7 @@ import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent'; +import { HasMovedEvent, HasMovedEventCallback, isHasMovedEvent } from './Api/Events/HasMovedEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -17,15 +18,17 @@ interface WorkAdventureApi { onEnterZone(name: string, callback: () => void): void; onLeaveZone(name: string, callback: () => void): void; openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; - openTab(url : string): void; - goToPage(url : string): void; - openCoWebSite(url : string): void; + openTab(url: string): void; + goToPage(url: string): void; + openCoWebSite(url: string): void; closeCoWebSite(): void; disablePlayerControl(): void; restorePlayerControl(): void; displayBubble(): void; removeBubble(): void; - getGameState():Promise + getGameState(): Promise + + onMoveEvent(callback: (moveEvent: HasMovedEvent) => void): void } declare global { @@ -75,20 +78,44 @@ class Popup { }, '*'); } } +function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + +const stateResolvers: Array<(event: GameStateEvent) => void> = [] + +const callbacks: { [type: string]: HasMovedEventCallback | ((arg?: HasMovedEvent | never) => void) } = {} -const stateResolvers:Array<(event:GameStateEvent)=>void> =[] +function postToParent(content: IframeEvent) { + window.parent.postMessage(content, "*") +} +let moveEventUuid: string | undefined; window.WA = { + onMoveEvent(callback: HasMovedEventCallback): void { + moveEventUuid = uuidv4(); + callbacks[moveEventUuid] = callback; + postToParent({ + type: "enableMoveEvents", + data: undefined + }) + window.parent.postMessage({ + type: "enable" + }, "*") + }, - getGameState(){ - return new Promise((resolver,thrower)=>{ + getGameState() { + return new Promise((resolver, thrower) => { stateResolvers.push(resolver); - window.parent.postMessage({ - type:"getState" - },"*") + window.parent.postMessage({ + type: "getState" + }, "*") }) }, @@ -140,10 +167,10 @@ window.WA = { }, '*'); }, - openCoWebSite(url : string) : void{ + openCoWebSite(url: string): void { window.parent.postMessage({ - "type" : 'openCoWebSite', - "data" : { + "type": 'openCoWebSite', + "data": { url } as OpenCoWebSiteEvent }, '*'); @@ -242,10 +269,12 @@ window.addEventListener('message', message => { if (callback) { callback(popup); } - }else if(payload.type=="gameState" && isGameStateEvent(payloadData)){ - stateResolvers.forEach(resolver=>{ + } else if (payload.type == "gameState" && isGameStateEvent(payloadData)) { + stateResolvers.forEach(resolver => { resolver(payloadData); }) + } else if (payload.type == "hasMovedEvent" && isHasMovedEvent(payloadData) && moveEventUuid) { + callbacks[moveEventUuid](payloadData) } } From 2c4c98b0e56c3d064d2a93aa6464b1b8d508b4de Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 10 May 2021 21:44:15 +0200 Subject: [PATCH 025/189] limited event trigger to max 10 per second --- front/src/Api/IframeListener.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index f10d0fc1..975dde67 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -15,6 +15,8 @@ import { UserInputChatEvent } from "./Events/UserInputChatEvent"; import { GameStateEvent } from './Events/ApiGameStateEvent'; import { deepFreezeClone as deepFreezeClone } from '../utility'; import { HasMovedEvent } from './Events/HasMovedEvent'; +import { Math } from 'phaser'; + /** @@ -63,6 +65,7 @@ class IframeListener { private readonly iframes = new Set(); private readonly scripts = new Map(); private sendMoveEvents: boolean = false; + private lastMoveTimestamp: number = 0 init() { window.addEventListener("message", (message: TypedMessageEvent>) => { @@ -237,10 +240,14 @@ class IframeListener { hasMovedEvent(event: HasMovedEvent) { if (this.sendMoveEvents) { - this.postMessage({ - 'type': 'hasMovedEvent', - 'data': event - }); + if (this.lastMoveTimestamp < Date.now() - 100) { + this.lastMoveTimestamp = Date.now() + this.postMessage({ + 'type': 'hasMovedEvent', + 'data': event + }); + } + } } From 43aad4ab143242086124e4519612145666589eb4 Mon Sep 17 00:00:00 2001 From: GRL Date: Wed, 12 May 2021 14:30:12 +0200 Subject: [PATCH 026/189] phaserLayers managed by Gamemap Implementation of LayersFlattener Implementation of Setting properties of a layer form script Update show/hide layer form script Update unit test of LayersIteratorTest --- front/src/Api/Events/IframeEvent.ts | 2 + front/src/Api/Events/setPropertyEvent.ts | 12 + front/src/Api/IframeListener.ts | 8 +- front/src/Phaser/Game/GameMap.ts | 39 +++- front/src/Phaser/Game/GameScene.ts | 78 ++++--- front/src/Phaser/Map/ITiledMap.ts | 3 + front/src/Phaser/Map/LayersFlattener.ts | 22 ++ front/src/Phaser/Map/LayersIterator.ts | 44 ---- front/src/iframe_api.ts | 14 +- front/tests/Phaser/Map/LayersIteratorTest.ts | 223 ++++++++++--------- maps/tests/iframe.html | 9 +- 11 files changed, 258 insertions(+), 196 deletions(-) create mode 100644 front/src/Api/Events/setPropertyEvent.ts create mode 100644 front/src/Phaser/Map/LayersFlattener.ts delete mode 100644 front/src/Phaser/Map/LayersIterator.ts diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 2e7ccd86..d0994fa5 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -10,6 +10,7 @@ import { OpenPopupEvent } from './OpenPopupEvent'; import { OpenTabEvent } from './OpenTabEvent'; import { UserInputChatEvent } from './UserInputChatEvent'; import { LayerEvent } from './LayerEvent'; +import { SetPropertyEvent } from "./setPropertyEvent"; export interface TypedMessageEvent extends MessageEvent { @@ -32,6 +33,7 @@ export type IframeEventMap = { removeBubble: null showLayer: LayerEvent hideLayer: LayerEvent + setProperty: SetPropertyEvent } export interface IframeEvent { type: T; diff --git a/front/src/Api/Events/setPropertyEvent.ts b/front/src/Api/Events/setPropertyEvent.ts new file mode 100644 index 00000000..39785bc6 --- /dev/null +++ b/front/src/Api/Events/setPropertyEvent.ts @@ -0,0 +1,12 @@ +import * as tg from "generic-type-guard"; + +export const isSetPropertyEvent = + new tg.IsInterface().withProperties({ + layerName: tg.isString, + propertyName: tg.isString, + propertyValue: tg.isUnion(tg.isString, tg.isUnion(tg.isNumber, tg.isUnion(tg.isBoolean, tg.isUndefined))) + }).get(); +/** + * A message sent from the iFrame to the game to change the value of the property of the layer + */ +export type SetPropertyEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 5529d36e..d8e3a8c8 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,7 +12,8 @@ import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent"; import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMap, isIframeEventWrapper, TypedMessageEvent } from "./Events/IframeEvent"; import { UserInputChatEvent } from "./Events/UserInputChatEvent"; -import {isLayerEvent, LayerEvent} from "./Events/LayerEvent"; +import { isLayerEvent, LayerEvent } from "./Events/LayerEvent"; +import { isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent"; /** @@ -59,6 +60,9 @@ class IframeListener { private readonly _hideLayerStream: Subject = new Subject(); public readonly hideLayerStream = this._hideLayerStream.asObservable(); + private readonly _setPropertyStream: Subject = new Subject(); + public readonly setPropertyStream = this._setPropertyStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -84,6 +88,8 @@ class IframeListener { this._showLayerStream.next(payload.data); } else if (payload.type === 'hideLayer' && isLayerEvent(payload.data)) { this._hideLayerStream.next(payload.data); + } else if (payload.type === 'setProperty' && isSetPropertyEvent(payload.data)) { + this._setPropertyStream.next(payload.data); } else if (payload.type === 'chat' && isChatEvent(payload.data)) { this._chatStream.next(payload.data); } else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) { diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 5fe91b62..b8b68e15 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -1,5 +1,5 @@ -import {ITiledMap, ITiledMapLayer} from "../Map/ITiledMap"; -import {LayersIterator} from "../Map/LayersIterator"; +import {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap"; +import { flattenGroupLayersMap } from "../Map/LayersFlattener"; export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map) => void; @@ -11,10 +11,19 @@ export class GameMap { private key: number|undefined; private lastProperties = new Map(); private callbacks = new Map>(); - public readonly layersIterator: LayersIterator; + public readonly flatLayers: ITiledMapLayer[]; - public constructor(private map: ITiledMap) { - this.layersIterator = new LayersIterator(map); + public constructor(private map: ITiledMap, phaserMap: Phaser.Tilemaps.Tilemap, terrains: Array) { + this.flatLayers = flattenGroupLayersMap(map); + let depth = -2; + for (const layer of this.flatLayers) { + if(layer.type === 'tilelayer'){ + layer.phaserLayer = phaserMap.createLayer(layer.name, terrains, 0, 0).setDepth(depth); + } + if (layer.type === 'objectgroup' && layer.name === 'floorLayer') { + depth = 10000; + } + } } /** @@ -58,7 +67,7 @@ export class GameMap { private getProperties(key: number): Map { const properties = new Map(); - for (const layer of this.layersIterator) { + for (const layer of this.flatLayers) { if (layer.type !== 'tilelayer') { continue; } @@ -100,4 +109,22 @@ export class GameMap { } callbacksArray.push(callback); } + + public findLayer(layerName: string): ITiledMapLayer | undefined { + let i = 0; + let found = false; + while (!found && i = new Map(); Map!: Phaser.Tilemaps.Tilemap; - Layers!: Array; Objects!: Array; mapFile!: ITiledMap; groups: Map; @@ -392,7 +392,6 @@ export class GameScene extends DirtyScene implements CenterListener { //initalise map this.Map = this.add.tilemap(this.MapUrlFile); - this.gameMap = new GameMap(this.mapFile); const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => { this.Terrains.push(this.Map.addTilesetImage(tileset.name, `${mapDirUrl}/${tileset.image}`, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing/*, tileset.firstgid*/)); @@ -402,11 +401,9 @@ export class GameScene extends DirtyScene implements CenterListener { this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels); //add layer on map - this.Layers = new Array(); - let depth = -2; - for (const layer of this.gameMap.layersIterator) { + this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains); + for (const layer of this.gameMap.flatLayers) { if (layer.type === 'tilelayer') { - this.addLayer(this.Map.createLayer(layer.name, this.Terrains, 0, 0).setDepth(depth)); const exitSceneUrl = this.getExitSceneUrl(layer); if (exitSceneUrl !== undefined) { @@ -417,9 +414,6 @@ export class GameScene extends DirtyScene implements CenterListener { this.loadNextGame(exitUrl); } } - if (layer.type === 'objectgroup' && layer.name === 'floorLayer') { - depth = 10000; - } if (layer.type === 'objectgroup') { for (const object of layer.objects) { if (object.text) { @@ -428,9 +422,6 @@ export class GameScene extends DirtyScene implements CenterListener { } } } - if (depth === -2) { - throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at. This layer cannot be contained in a group.'); - } this.initStartXAndStartY(); @@ -884,15 +875,38 @@ ${escapedMessage} this.setLayerVisibility(layerEvent.name, false); })); + this.iframeSubscriptionList.push(iframeListener.setPropertyStream.subscribe((setProperty) => { + this.setPropertyLayer(setProperty.layerName, setProperty.propertyName, setProperty.propertyValue); + })); + + } + + private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { + const layer = this.gameMap.findLayer(layerName); + if (layer === undefined) { + console.warn('Could not find layer "' + layerName + '" when calling setProperty'); + return; + } + const property = (layer.properties as ITiledMapLayerProperty[])?.find((property) => property.name === propertyName); + if (property === undefined) { + layer.properties = []; + layer.properties.push({name : propertyName, type : typeof propertyValue, value : propertyValue}); + return; + } + property.value = propertyValue; } private setLayerVisibility(layerName: string, visible: boolean): void { - const layer = this.Layers.find((layer) => layer.layer.name === layerName); + const layer = this.gameMap.findLayer(layerName); if (layer === undefined) { console.warn('Could not find layer "' + layerName + '" when calling WA.hideLayer / WA.showLayer'); return; } - layer.setVisible(visible); + if(layer.type != "tilelayer"){ + console.warn('The layer "' + layerName + '" is not a tilelayer. It can not be show/hide'); + return; + } + layer.phaserLayer?.setVisible(visible); this.dirty = true; } @@ -1001,7 +1015,7 @@ ${escapedMessage} } private initPositionFromLayerName(layerName: string) { - for (const layer of this.gameMap.layersIterator) { + for (const layer of this.gameMap.flatLayers) { if ((layerName === layer.name || layer.name.endsWith('/'+layerName)) && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) { const startPosition = this.startUser(layer); this.startX = startPosition.x + this.mapFile.tilewidth/2; @@ -1091,27 +1105,29 @@ ${escapedMessage} this.updateCameraOffset(); } - addLayer(Layer : Phaser.Tilemaps.TilemapLayer){ - this.Layers.push(Layer); - } - createCollisionWithPlayer() { this.physics.disableUpdate(); //add collision layer - this.Layers.forEach((Layer: Phaser.Tilemaps.TilemapLayer) => { - this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => { - //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) - }); - Layer.setCollisionByProperty({collides: true}); - if (DEBUG_MODE) { - //debug code to see the collision hitbox of the object in the top layer - Layer.renderDebug(this.add.graphics(), { - tileColor: null, //non-colliding tiles - collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200), // Colliding tiles, - faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Colliding face edges + for (const Layer of this.gameMap.flatLayers) { + if (Layer.type == "tilelayer") { + if (Layer.phaserLayer === undefined) { + throw new Error('phaserLayer of layer "' + Layer.name + '" is undefined'); + } + this.physics.add.collider(this.CurrentPlayer, Layer.phaserLayer, (object1: GameObject, object2: GameObject) => { + //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) }); + Layer.phaserLayer.setCollisionByProperty({collides: true}); + if (DEBUG_MODE) { + //debug code to see the collision hitbox of the object in the top layer + Layer.phaserLayer.renderDebug(this.add.graphics(), { + tileColor: null, //non-colliding tiles + collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200), // Colliding tiles, + faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Colliding face edges + }); + } + //}); } - }); + } } createCurrentPlayer(){ diff --git a/front/src/Phaser/Map/ITiledMap.ts b/front/src/Phaser/Map/ITiledMap.ts index c4828911..d381e9d4 100644 --- a/front/src/Phaser/Map/ITiledMap.ts +++ b/front/src/Phaser/Map/ITiledMap.ts @@ -4,6 +4,8 @@ * Represents the interface for the Tiled exported data structure (JSON). Used * when loading resources via Resource loader. */ +import TilemapLayer = Phaser.Tilemaps.TilemapLayer; + export interface ITiledMap { width: number; height: number; @@ -81,6 +83,7 @@ export interface ITiledMapTileLayer { * Draw order (topdown (default), index) */ draworder?: string; + phaserLayer?: TilemapLayer; } export interface ITiledMapObjectLayer { diff --git a/front/src/Phaser/Map/LayersFlattener.ts b/front/src/Phaser/Map/LayersFlattener.ts new file mode 100644 index 00000000..a3b12522 --- /dev/null +++ b/front/src/Phaser/Map/LayersFlattener.ts @@ -0,0 +1,22 @@ +import {ITiledMap, ITiledMapLayer} from "./ITiledMap"; + +/** + * Flatten the grouped layers + */ +export function flattenGroupLayersMap(map: ITiledMap) { + let flatLayers: ITiledMapLayer[] = []; + flattenGroupLayers(map.layers, '', flatLayers); + return flatLayers; +} + +function flattenGroupLayers(layers : ITiledMapLayer[], prefix : string, flatLayers: ITiledMapLayer[]) { + for (const layer of layers) { + if (layer.type === 'group') { + flattenGroupLayers(layer.layers, prefix + layer.name + '/', flatLayers); + } else { + const layerWithNewName = { ...layer }; + layerWithNewName.name = prefix+layerWithNewName.name; + flatLayers.push(layerWithNewName); + } + } +} \ No newline at end of file diff --git a/front/src/Phaser/Map/LayersIterator.ts b/front/src/Phaser/Map/LayersIterator.ts deleted file mode 100644 index 501a5f7b..00000000 --- a/front/src/Phaser/Map/LayersIterator.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {ITiledMap, ITiledMapLayer} from "./ITiledMap"; - -/** - * Iterates over the layers of a map, flattening the grouped layers - */ -export class LayersIterator implements IterableIterator { - - private layers: ITiledMapLayer[] = []; - private pointer: number = 0; - - constructor(private map: ITiledMap) { - this.initLayersList(map.layers, ''); - } - - private initLayersList(layers : ITiledMapLayer[], prefix : string) { - for (const layer of layers) { - if (layer.type === 'group') { - this.initLayersList(layer.layers, prefix + layer.name + '/'); - } else { - const layerWithNewName = { ...layer }; - layerWithNewName.name = prefix+layerWithNewName.name; - this.layers.push(layerWithNewName); - } - } - } - - public next(): IteratorResult { - if (this.pointer < this.layers.length) { - return { - done: false, - value: this.layers[this.pointer++] - } - } else { - return { - done: true, - value: null - } - } - } - - [Symbol.iterator](): IterableIterator { - return new LayersIterator(this.map); - } -} diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 9f059cd0..a96ad193 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,7 +9,8 @@ import { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import {LayerEvent} from "./Api/Events/LayerEvent"; +import { LayerEvent } from "./Api/Events/LayerEvent"; +import { SetPropertyEvent } from "./Api/Events/setPropertyEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -27,6 +28,7 @@ interface WorkAdventureApi { removeBubble() : void; showLayer(layer: string) : void; hideLayer(layer: string) : void; + setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void; } declare global { @@ -107,6 +109,16 @@ window.WA = { } as LayerEvent }, '*'); }, + setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { + window.parent.postMessage({ + 'type' : 'setProperty', + 'data' : { + 'layerName' : layerName, + 'propertyName' : propertyName, + 'propertyValue' : propertyValue + } as SetPropertyEvent + }, '*'); + }, disablePlayerControls(): void { window.parent.postMessage({ 'type': 'disablePlayerControls' }, '*'); }, diff --git a/front/tests/Phaser/Map/LayersIteratorTest.ts b/front/tests/Phaser/Map/LayersIteratorTest.ts index 3b9d0d9b..de95ecef 100644 --- a/front/tests/Phaser/Map/LayersIteratorTest.ts +++ b/front/tests/Phaser/Map/LayersIteratorTest.ts @@ -1,145 +1,148 @@ import "jasmine"; import {Room} from "../../../src/Connexion/Room"; -import {LayersIterator} from "../../../src/Phaser/Map/LayersIterator"; +import {flattenGroupLayersMap} from "../../../src/Phaser/Map/LayersFlattener"; +import {ITiledMapLayer} from "../../../src/Phaser/Map/ITiledMap"; -describe("Layers iterator", () => { +describe("Layers flattener", () => { it("should iterate maps with no group", () => { - const layersIterator = new LayersIterator({ - "compressionlevel":-1, - "height":2, - "infinite":false, - "layers":[ + let flatLayers:ITiledMapLayer[] = []; + flatLayers = flattenGroupLayersMap({ + "compressionlevel": -1, + "height": 2, + "infinite": false, + "layers": [ { - "data":[0, 0, 0, 0], - "height":2, - "id":1, - "name":"Tile Layer 1", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":2, - "x":0, - "y":0 + "data": [0, 0, 0, 0], + "height": 2, + "id": 1, + "name": "Tile Layer 1", + "opacity": 1, + "type": "tilelayer", + "visible": true, + "width": 2, + "x": 0, + "y": 0 }, { - "data":[0, 0, 0, 0], - "height":2, - "id":1, - "name":"Tile Layer 2", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":2, - "x":0, - "y":0 + "data": [0, 0, 0, 0], + "height": 2, + "id": 1, + "name": "Tile Layer 2", + "opacity": 1, + "type": "tilelayer", + "visible": true, + "width": 2, + "x": 0, + "y": 0 }], - "nextlayerid":2, - "nextobjectid":1, - "orientation":"orthogonal", - "renderorder":"right-down", - "tiledversion":"2021.03.23", - "tileheight":32, - "tilesets":[], - "tilewidth":32, - "type":"map", - "version":1.5, - "width":2 + "nextlayerid": 2, + "nextobjectid": 1, + "orientation": "orthogonal", + "renderorder": "right-down", + "tiledversion": "2021.03.23", + "tileheight": 32, + "tilesets": [], + "tilewidth": 32, + "type": "map", + "version": 1.5, + "width": 2 }) const layers = []; - for (const layer of layersIterator) { + for (const layer of flatLayers) { layers.push(layer.name); } expect(layers).toEqual(['Tile Layer 1', 'Tile Layer 2']); }); it("should iterate maps with recursive groups", () => { - const layersIterator = new LayersIterator({ - "compressionlevel":-1, - "height":2, - "infinite":false, - "layers":[ + let flatLayers:ITiledMapLayer[] = []; + flatLayers = flattenGroupLayersMap({ + "compressionlevel": -1, + "height": 2, + "infinite": false, + "layers": [ { - "id":6, - "layers":[ + "id": 6, + "layers": [ { - "id":5, - "layers":[ + "id": 5, + "layers": [ { - "data":[0, 0, 0, 0], - "height":2, - "id":10, - "name":"Tile3", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":2, - "x":0, - "y":0 + "data": [0, 0, 0, 0], + "height": 2, + "id": 10, + "name": "Tile3", + "opacity": 1, + "type": "tilelayer", + "visible": true, + "width": 2, + "x": 0, + "y": 0 }, { - "data":[0, 0, 0, 0], - "height":2, - "id":9, - "name":"Tile2", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":2, - "x":0, - "y":0 + "data": [0, 0, 0, 0], + "height": 2, + "id": 9, + "name": "Tile2", + "opacity": 1, + "type": "tilelayer", + "visible": true, + "width": 2, + "x": 0, + "y": 0 }], - "name":"Group 3", - "opacity":1, - "type":"group", - "visible":true, - "x":0, - "y":0 + "name": "Group 3", + "opacity": 1, + "type": "group", + "visible": true, + "x": 0, + "y": 0 }, { - "id":7, - "layers":[ + "id": 7, + "layers": [ { - "data":[0, 0, 0, 0], - "height":2, - "id":8, - "name":"Tile1", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":2, - "x":0, - "y":0 + "data": [0, 0, 0, 0], + "height": 2, + "id": 8, + "name": "Tile1", + "opacity": 1, + "type": "tilelayer", + "visible": true, + "width": 2, + "x": 0, + "y": 0 }], - "name":"Group 2", - "opacity":1, - "type":"group", - "visible":true, - "x":0, - "y":0 + "name": "Group 2", + "opacity": 1, + "type": "group", + "visible": true, + "x": 0, + "y": 0 }], - "name":"Group 1", - "opacity":1, - "type":"group", - "visible":true, - "x":0, - "y":0 + "name": "Group 1", + "opacity": 1, + "type": "group", + "visible": true, + "x": 0, + "y": 0 }], - "nextlayerid":11, - "nextobjectid":1, - "orientation":"orthogonal", - "renderorder":"right-down", - "tiledversion":"2021.03.23", - "tileheight":32, - "tilesets":[], - "tilewidth":32, - "type":"map", - "version":1.5, - "width":2 + "nextlayerid": 11, + "nextobjectid": 1, + "orientation": "orthogonal", + "renderorder": "right-down", + "tiledversion": "2021.03.23", + "tileheight": 32, + "tilesets": [], + "tilewidth": 32, + "type": "map", + "version": 1.5, + "width": 2 }) const layers = []; - for (const layer of layersIterator) { + for (const layer of flatLayers) { layers.push(layer.name); } expect(layers).toEqual(['Group 1/Group 3/Tile3', 'Group 1/Group 3/Tile2', 'Group 1/Group 2/Tile1']); diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index c5c30972..f9f43f20 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -19,17 +19,20 @@ }));
- +
+ From 39539214df3ae7993bc13af738898ae95fafe2fe Mon Sep 17 00:00:00 2001 From: GRL Date: Mon, 17 May 2021 10:13:48 +0200 Subject: [PATCH 027/189] documentation of SetProperty --- docs/maps/api-reference.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index d7d7f385..6e98dfb5 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -252,4 +252,15 @@ WA.showLayer('bottom'); WA.hideLayer('bottom'); ``` +### Set/Create properties in a layer + +``` +WA.setProperty(layerName : string, propertyName : string, propertyValue : string | number | boolean | undefined) : void; +``` + +Set the value of the "propertyName" property of the layer "layerName" at "propertyValue". If the property doesn't exist, create the property "propertyName" and set the value of the property at "propertyValue". + +```javascript +WA.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/'); +``` From 9b68faac0e491b58a8a0b30734d740f0b916b34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 18 May 2021 09:53:54 +0200 Subject: [PATCH 028/189] Fixing JSDoc --- front/src/Api/Events/MenuItemClickedEvent.ts | 2 +- front/src/Api/Events/MenuItemRegisterEvent.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/Api/Events/MenuItemClickedEvent.ts b/front/src/Api/Events/MenuItemClickedEvent.ts index dd80c0f2..0735eda4 100644 --- a/front/src/Api/Events/MenuItemClickedEvent.ts +++ b/front/src/Api/Events/MenuItemClickedEvent.ts @@ -5,6 +5,6 @@ export const isMenuItemClickedEvent = menuItem: tg.isString }).get(); /** - * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + * A message sent from the game to the iFrame when a menu item is clicked. */ export type MenuItemClickedEvent = tg.GuardedType; diff --git a/front/src/Api/Events/MenuItemRegisterEvent.ts b/front/src/Api/Events/MenuItemRegisterEvent.ts index 98d4c7d3..a25e5cc3 100644 --- a/front/src/Api/Events/MenuItemRegisterEvent.ts +++ b/front/src/Api/Events/MenuItemRegisterEvent.ts @@ -5,6 +5,6 @@ export const isMenuItemRegisterEvent = menutItem: tg.isString }).get(); /** - * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + * A message sent from the iFrame to the game to add a new menu item. */ export type MenuItemRegisterEvent = tg.GuardedType; From 3edfd5b285c5d2f51eab85c0c1fc865a04ffcc8e Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 18 May 2021 11:33:16 +0200 Subject: [PATCH 029/189] GameState is now save in cache HasPlayerMoved is send when the player is actually moving on the map every 200ms. --- ...ApiGameStateEvent.ts => GameStateEvent.ts} | 9 +- .../Api/Events/HasDataLayerChangedEvent.ts | 16 ++ front/src/Api/Events/HasMovedEvent.ts | 19 -- front/src/Api/Events/HasPlayerMovedEvent.ts | 19 ++ front/src/Api/Events/IframeEvent.ts | 11 +- front/src/Api/IframeListener.ts | 42 ++-- front/src/Phaser/Game/GameScene.ts | 28 +-- front/src/Phaser/Game/PlayerMovement.ts | 6 +- .../Game/PlayersPositionInterpolator.ts | 6 +- front/src/iframe_api.ts | 109 ++++++--- maps/tests/Metadata/map.json | 230 ++++++++++++++++++ maps/tests/Metadata/script.js | 9 + maps/tests/Metadata/tileset_dungeon.png | Bin 0 -> 9696 bytes 13 files changed, 404 insertions(+), 100 deletions(-) rename front/src/Api/Events/{ApiGameStateEvent.ts => GameStateEvent.ts} (72%) create mode 100644 front/src/Api/Events/HasDataLayerChangedEvent.ts delete mode 100644 front/src/Api/Events/HasMovedEvent.ts create mode 100644 front/src/Api/Events/HasPlayerMovedEvent.ts create mode 100644 maps/tests/Metadata/map.json create mode 100644 maps/tests/Metadata/script.js create mode 100644 maps/tests/Metadata/tileset_dungeon.png diff --git a/front/src/Api/Events/ApiGameStateEvent.ts b/front/src/Api/Events/GameStateEvent.ts similarity index 72% rename from front/src/Api/Events/ApiGameStateEvent.ts rename to front/src/Api/Events/GameStateEvent.ts index 4f4e98ff..418d1ca0 100644 --- a/front/src/Api/Events/ApiGameStateEvent.ts +++ b/front/src/Api/Events/GameStateEvent.ts @@ -1,6 +1,6 @@ import * as tg from "generic-type-guard"; -export const isPositionState = new tg.IsInterface().withProperties({ +/*export const isPositionState = new tg.IsInterface().withProperties({ x: tg.isNumber, y: tg.isNumber }).get() @@ -12,19 +12,16 @@ export const isPlayerState = new tg.IsInterface() }).get() ).get() -export type PlayerStateObject = tg.GuardedType; +export type PlayerStateObject = tg.GuardedType;*/ export const isGameStateEvent = new tg.IsInterface().withProperties({ roomId: tg.isString, - data: tg.isObject, mapUrl: tg.isString, - nickName: tg.isString, uuid: tg.isUnion(tg.isString, tg.isUndefined), - players: isPlayerState, startLayerName: tg.isUnion(tg.isString, tg.isNull) }).get(); /** - * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + * A message sent from the game to the iFrame when the gameState is got by the script */ export type GameStateEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/Events/HasDataLayerChangedEvent.ts b/front/src/Api/Events/HasDataLayerChangedEvent.ts new file mode 100644 index 00000000..7714f978 --- /dev/null +++ b/front/src/Api/Events/HasDataLayerChangedEvent.ts @@ -0,0 +1,16 @@ +import * as tg from "generic-type-guard"; + + + +export const isHasDataLayerChangedEvent = + new tg.IsInterface().withProperties({ + data: tg.isObject + }).get(); + +/** + * A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers + */ +export type HasDataLayerChangedEvent = tg.GuardedType; + + +export type HasDataLayerChangedEventCallback = (event: HasDataLayerChangedEvent) => void \ No newline at end of file diff --git a/front/src/Api/Events/HasMovedEvent.ts b/front/src/Api/Events/HasMovedEvent.ts deleted file mode 100644 index fef8e731..00000000 --- a/front/src/Api/Events/HasMovedEvent.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as tg from "generic-type-guard"; - - - -export const isHasMovedEvent = - new tg.IsInterface().withProperties({ - direction: tg.isString, - moving: tg.isBoolean, - x: tg.isNumber, - y: tg.isNumber - }).get(); - -/** - * A message sent from the iFrame to the game to add a message in the chat. - */ -export type HasMovedEvent = tg.GuardedType; - - -export type HasMovedEventCallback = (event: HasMovedEvent) => void diff --git a/front/src/Api/Events/HasPlayerMovedEvent.ts b/front/src/Api/Events/HasPlayerMovedEvent.ts new file mode 100644 index 00000000..28603284 --- /dev/null +++ b/front/src/Api/Events/HasPlayerMovedEvent.ts @@ -0,0 +1,19 @@ +import * as tg from "generic-type-guard"; + + + +export const isHasPlayerMovedEvent = + new tg.IsInterface().withProperties({ + direction: tg.isString, + moving: tg.isBoolean, + x: tg.isNumber, + y: tg.isNumber + }).get(); + +/** + * A message sent from the game to the iFrame when the player move after the iFrame send a message to the game that it want to listen to the position of the player + */ +export type HasPlayerMovedEvent = tg.GuardedType; + + +export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 307b09fc..ae0eab34 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,15 +1,16 @@ -import { GameStateEvent } from './ApiGameStateEvent'; +import { GameStateEvent } from './GameStateEvent'; import { ButtonClickedEvent } from './ButtonClickedEvent'; import { ChatEvent } from './ChatEvent'; import { ClosePopupEvent } from './ClosePopupEvent'; import { EnterLeaveEvent } from './EnterLeaveEvent'; import { GoToPageEvent } from './GoToPageEvent'; -import { HasMovedEvent } from './HasMovedEvent'; +import { HasPlayerMovedEvent } from './HasPlayerMovedEvent'; import { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent'; import { OpenPopupEvent } from './OpenPopupEvent'; import { OpenTabEvent } from './OpenTabEvent'; import { UserInputChatEvent } from './UserInputChatEvent'; +import { HasDataLayerChangedEvent } from "./HasDataLayerChangedEvent"; export interface TypedMessageEvent extends MessageEvent { @@ -30,7 +31,8 @@ export type IframeEventMap = { restorePlayerControls: null displayBubble: null removeBubble: null - enableMoveEvents: undefined + onPlayerMove: undefined + onDataLayerChange: undefined } export interface IframeEvent { type: T; @@ -47,7 +49,8 @@ export interface IframeResponseEventMap { leaveEvent: EnterLeaveEvent buttonClickedEvent: ButtonClickedEvent gameState: GameStateEvent - hasMovedEvent: HasMovedEvent + hasPlayerMoved: HasPlayerMovedEvent + hasDataLayerChanged: HasDataLayerChangedEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 82dd23cf..d6c02516 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,10 +12,11 @@ import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent"; import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMap, isIframeEventWrapper, TypedMessageEvent } from "./Events/IframeEvent"; import { UserInputChatEvent } from "./Events/UserInputChatEvent"; -import { GameStateEvent } from './Events/ApiGameStateEvent'; +import { GameStateEvent } from './Events/GameStateEvent'; import { deepFreezeClone as deepFreezeClone } from '../utility'; -import { HasMovedEvent } from './Events/HasMovedEvent'; +import { HasPlayerMovedEvent } from './Events/HasPlayerMovedEvent'; import { Math } from 'phaser'; +import { HasDataLayerChangedEvent } from "./Events/HasDataLayerChangedEvent"; @@ -58,14 +59,14 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); - private readonly _gameStateStream: Subject = new Subject(); public readonly gameStateStream = this._gameStateStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); - private sendMoveEvents: boolean = false; - private lastMoveTimestamp: number = 0 + private sendPlayerMove: boolean = false; + private sendDataLayerChange: boolean = false; init() { window.addEventListener("message", (message: TypedMessageEvent>) => { @@ -119,8 +120,10 @@ class IframeListener { this._removeBubbleStream.next(); } else if (payload.type == "getState") { this._gameStateStream.next(); - } else if (payload.type == "enableMoveEvents") { - this.sendMoveEvents = true + } else if (payload.type == "onPlayerMove") { + this.sendPlayerMove = true + } else if (payload.type == "onDataLayerChange") { + this.sendDataLayerChange = true } } @@ -133,7 +136,7 @@ class IframeListener { sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) { this.postMessage({ 'type': 'gameState', - 'data': deepFreezeClone(gameStateEvent) + 'data': gameStateEvent //deepFreezeClone(gameStateEvent) }); } @@ -240,16 +243,21 @@ class IframeListener { }); } - hasMovedEvent(event: HasMovedEvent) { - if (this.sendMoveEvents) { - if (this.lastMoveTimestamp < Date.now() - 100) { - this.lastMoveTimestamp = Date.now() - this.postMessage({ - 'type': 'hasMovedEvent', - 'data': event - }); - } + hasPlayerMoved(event: HasPlayerMovedEvent) { + if (this.sendPlayerMove) { + this.postMessage({ + 'type': 'hasPlayerMoved', + 'data': event + }); + } + } + hasDataLayerChanged(event: HasDataLayerChangedEvent) { + if (this.sendDataLayerChange) { + this.postMessage({ + 'type' : 'hasDataLayerChanged', + 'data' : event + }); } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 39fa79db..83256cec 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -90,9 +90,9 @@ import { TextUtils } from "../Components/TextUtils"; import { touchScreenManager } from "../../Touch/TouchScreenManager"; import { PinchManager } from "../UserInput/PinchManager"; import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick"; -import { PlayerStateObject } from '../../Api/Events/ApiGameStateEvent'; +//import { PlayerStateObject } from '../../Api/Events/GameStateEvent'; import { waScaleManager } from "../Services/WaScaleManager"; -import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; +import { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent'; export interface GameSceneInitInterface { initPosition: PointInterface | null, @@ -164,7 +164,7 @@ export class GameScene extends DirtyScene implements CenterListener { currentTick!: number; lastSentTick!: number; // The last tick at which a position was sent. - lastMoveEventSent: HasMovedEvent = { + lastMoveEventSent: HasPlayerMovedEvent = { direction: '', moving: false, x: -1000, @@ -632,11 +632,11 @@ export class GameScene extends DirtyScene implements CenterListener { //listen event to share position of user this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this)) - this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => { - iframeListener.hasMovedEvent(event) + this.CurrentPlayer.on(hasMovedEventName, (event: HasPlayerMovedEvent) => { + //iframeListener.hasMovedEvent(event) }) this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this)) - this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => { + this.CurrentPlayer.on(hasMovedEventName, (event: HasPlayerMovedEvent) => { this.gameMap.setPosition(event.x, event.y); }) @@ -870,7 +870,7 @@ ${escapedMessage} this.userInputManager.restoreControls(); })); this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => { - const playerObject: PlayerStateObject = { + /*const playerObject: PlayerStateObject = { [this.playerName]: { position: { x: this.CurrentPlayer.x, @@ -889,15 +889,12 @@ ${escapedMessage} pusherId: remotePlayer.userId } - } + }*/ iframeListener.sendFrozenGameStateEvent({ mapUrl: this.MapUrlFile, - nickName: this.playerName, startLayerName: this.startLayerName, uuid: localUserStore.getLocalUser()?.uuid, roomId: this.RoomId, - data: this.mapFile, - players: playerObject }) })); @@ -1158,7 +1155,7 @@ ${escapedMessage} this.createCollisionWithPlayer(); } - pushPlayerPosition(event: HasMovedEvent) { + pushPlayerPosition(event: HasPlayerMovedEvent) { if (this.lastMoveEventSent === event) { return; } @@ -1188,7 +1185,7 @@ ${escapedMessage} * Finds the correct item to outline and outline it (if there is an item to be outlined) * @param event */ - private outlineItem(event: HasMovedEvent): void { + private outlineItem(event: HasPlayerMovedEvent): void { let x = event.x; let y = event.y; switch (event.direction) { @@ -1227,7 +1224,7 @@ ${escapedMessage} this.outlinedItem?.selectable(); } - private doPushPlayerPosition(event: HasMovedEvent): void { + private doPushPlayerPosition(event: HasPlayerMovedEvent): void { this.lastMoveEventSent = event; this.lastSentTick = this.currentTick; const camera = this.cameras.main; @@ -1237,6 +1234,7 @@ ${escapedMessage} right: camera.scrollX + camera.width, bottom: camera.scrollY + camera.height, }); + iframeListener.hasPlayerMoved(event); } /** @@ -1286,7 +1284,7 @@ ${escapedMessage} } // Let's move all users const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time); - updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => { + updatedPlayersPositions.forEach((moveEvent: HasPlayerMovedEvent, userId: number) => { this.dirty = true; const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId); if (player === undefined) { diff --git a/front/src/Phaser/Game/PlayerMovement.ts b/front/src/Phaser/Game/PlayerMovement.ts index 18c3ee0c..5680d7de 100644 --- a/front/src/Phaser/Game/PlayerMovement.ts +++ b/front/src/Phaser/Game/PlayerMovement.ts @@ -1,10 +1,10 @@ import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable"; import { PositionInterface } from "../../Connexion/ConnexionModels"; -import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; +import { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent'; export class PlayerMovement { - public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasMovedEvent, private endTick: number) { + public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasPlayerMovedEvent, private endTick: number) { } public isOutdated(tick: number): boolean { @@ -18,7 +18,7 @@ export class PlayerMovement { return tick > this.endTick + MAX_EXTRAPOLATION_TIME; } - public getPosition(tick: number): HasMovedEvent { + public getPosition(tick: number): HasPlayerMovedEvent { // Special case: end position reached and end position is not moving if (tick >= this.endTick && this.endPosition.moving === false) { //console.log('Movement finished ', this.endPosition) diff --git a/front/src/Phaser/Game/PlayersPositionInterpolator.ts b/front/src/Phaser/Game/PlayersPositionInterpolator.ts index 321396e2..53578884 100644 --- a/front/src/Phaser/Game/PlayersPositionInterpolator.ts +++ b/front/src/Phaser/Game/PlayersPositionInterpolator.ts @@ -2,7 +2,7 @@ * This class is in charge of computing the position of all players. * Player movement is delayed by 200ms so position depends on ticks. */ -import { HasMovedEvent } from '../../Api/Events/HasMovedEvent'; +import { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent'; import { PlayerMovement } from "./PlayerMovement"; export class PlayersPositionInterpolator { @@ -16,8 +16,8 @@ export class PlayersPositionInterpolator { this.playerMovements.delete(userId); } - getUpdatedPositions(tick: number): Map { - const positions = new Map(); + getUpdatedPositions(tick: number): Map { + const positions = new Map(); this.playerMovements.forEach((playerMovement: PlayerMovement, userId: number) => { if (playerMovement.isOutdated(tick)) { //console.log("outdated") diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 17c489ca..c2e91ea5 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,8 +9,9 @@ import { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent'; -import { HasMovedEvent, HasMovedEventCallback, isHasMovedEvent } from './Api/Events/HasMovedEvent'; +import { GameStateEvent, isGameStateEvent } from './Api/Events/GameStateEvent'; +import { HasPlayerMovedEvent, HasPlayerMovedEventCallback, isHasPlayerMovedEvent } from './Api/Events/HasPlayerMovedEvent'; +import { HasDataLayerChangedEvent, HasDataLayerChangedEventCallback, isHasDataLayerChangedEvent} from "./Api/Events/HasDataLayerChangedEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -26,9 +27,14 @@ interface WorkAdventureApi { restorePlayerControls(): void; displayBubble(): void; removeBubble(): void; - getGameState(): Promise + getMapUrl(): Promise; + getUuid(): Promise; + getRoomId(): Promise; + getStartLayerName(): Promise; - onMoveEvent(callback: (moveEvent: HasMovedEvent) => void): void + + onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void + onDataLayerChange(callback: (dataLayerChangedEvent: HasDataLayerChangedEvent) => void): void } declare global { @@ -84,41 +90,75 @@ function uuidv4() { return v.toString(16); }); } - -const stateResolvers: Array<(event: GameStateEvent) => void> = [] - -const callbacks: { [type: string]: HasMovedEventCallback | ((arg?: HasMovedEvent | never) => void) } = {} - - -function postToParent(content: IframeEvent) { - window.parent.postMessage(content, "*") -} -let moveEventUuid: string | undefined; - -window.WA = { - - onMoveEvent(callback: HasMovedEventCallback): void { - moveEventUuid = uuidv4(); - callbacks[moveEventUuid] = callback; - postToParent({ - type: "enableMoveEvents", - data: undefined - }) - - window.parent.postMessage({ - type: "enable" - }, "*") - }, - - getGameState() { +function getGameState(): Promise { + if (immutableData) { + return Promise.resolve(immutableData); + } + else { return new Promise((resolver, thrower) => { stateResolvers.push(resolver); window.parent.postMessage({ type: "getState" }, "*") }) + } +} + +const stateResolvers: Array<(event: GameStateEvent) => void> = [] +let immutableData: GameStateEvent; + +const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} +const callbackDataLayerChanged: { [type: string]: HasDataLayerChangedEventCallback | ((arg?: HasDataLayerChangedEvent | never) => void) } = {} + + +function postToParent(content: IframeEvent) { + window.parent.postMessage(content, "*") +} +let playerUuid: string | undefined; + +window.WA = { + + onPlayerMove(callback: HasPlayerMovedEventCallback): void { + playerUuid = uuidv4(); + callbackPlayerMoved[playerUuid] = callback; + postToParent({ + type: "onPlayerMove", + data: undefined + }) }, + onDataLayerChange(callback: HasDataLayerChangedEventCallback): void { + callbackDataLayerChanged['test'] = callback; + postToParent({ + type : "onDataLayerChange", + data: undefined + }) + }, + + + getMapUrl() { + return getGameState().then((res) => { + return res.mapUrl; + }) + }, + + getUuid() { + return getGameState().then((res) => { + return res.uuid; + }) + }, + + getRoomId() { + return getGameState().then((res) => { + return res.roomId; + }) + }, + + getStartLayerName() { + return getGameState().then((res) => { + return res.startLayerName; + }) + }, /** * Send a message in the chat. @@ -273,8 +313,11 @@ window.addEventListener('message', message => { stateResolvers.forEach(resolver => { resolver(payloadData); }) - } else if (payload.type == "hasMovedEvent" && isHasMovedEvent(payloadData) && moveEventUuid) { - callbacks[moveEventUuid](payloadData) + immutableData = payloadData; + } else if (payload.type == "hasPlayerMoved" && isHasPlayerMovedEvent(payloadData) && playerUuid) { + callbackPlayerMoved[playerUuid](payloadData) + } else if (payload.type == "hasDataLayerChanged" && isHasDataLayerChangedEvent(payloadData)) { + callbackDataLayerChanged['test'](payloadData) } } diff --git a/maps/tests/Metadata/map.json b/maps/tests/Metadata/map.json new file mode 100644 index 00000000..8967ed02 --- /dev/null +++ b/maps/tests/Metadata/map.json @@ -0,0 +1,230 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 33, 34, 34, 34, 34, 34, 34, 35, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 49, 50, 50, 50, 50, 50, 50, 51, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }, + { + "data":[1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19], + "height":10, + "id":3, + "name":"wall", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }], + "nextlayerid":6, + "nextobjectid":1, + "orientation":"orthogonal", + "properties":[ + { + "name":"script", + "type":"string", + "value":"script.js" + }], + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/script.js b/maps/tests/Metadata/script.js new file mode 100644 index 00000000..f3ac255a --- /dev/null +++ b/maps/tests/Metadata/script.js @@ -0,0 +1,9 @@ + + +WA.getMapUrl().then((map) => {console.log('mapUrl : ', map)}); +WA.getUuid().then((uuid) => {console.log('Uuid : ',uuid)}); +WA.getRoomId().then((roomId) => console.log('roomID : ',roomId)); + +WA.listenPositionPlayer(console.log); + + diff --git a/maps/tests/Metadata/tileset_dungeon.png b/maps/tests/Metadata/tileset_dungeon.png new file mode 100644 index 0000000000000000000000000000000000000000..fcac082c33704b31451bc8a58af5982c06586aa6 GIT binary patch literal 9696 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 Date: Tue, 18 May 2021 15:41:16 +0200 Subject: [PATCH 030/189] implementation of DataLayerEvent update GetGameState to add nickname to the returned data update GameMap to separate phaserLayer and mapLayer --- front/src/Api/Events/DataLayerEvent.ts | 7 ++--- front/src/Api/Events/GameStateEvent.ts | 1 + front/src/Api/Events/IframeEvent.ts | 5 ++-- front/src/Api/IframeListener.ts | 34 +++++++++++------------ front/src/Phaser/Game/GameMap.ts | 26 +++++++++++++++++- front/src/Phaser/Game/GameScene.ts | 36 ++++++++++++------------- front/src/Phaser/Game/PlayerMovement.ts | 1 - front/src/Phaser/Map/LayersFlattener.ts | 5 ++-- front/src/iframe_api.ts | 36 ++++++++++++++++--------- maps/tests/Metadata/script.js | 10 +++---- 10 files changed, 94 insertions(+), 67 deletions(-) diff --git a/front/src/Api/Events/DataLayerEvent.ts b/front/src/Api/Events/DataLayerEvent.ts index 8d2ffa23..096d6ef5 100644 --- a/front/src/Api/Events/DataLayerEvent.ts +++ b/front/src/Api/Events/DataLayerEvent.ts @@ -2,7 +2,7 @@ import * as tg from "generic-type-guard"; -export const isHasDataLayerChangedEvent = +export const isDataLayerEvent = new tg.IsInterface().withProperties({ data: tg.isObject }).get(); @@ -10,7 +10,4 @@ export const isHasDataLayerChangedEvent = /** * A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers */ -export type DataLayerEvent = tg.GuardedType; - - -export type HasDataLayerChangedEventCallback = (event: DataLayerEvent) => void \ No newline at end of file +export type DataLayerEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/Events/GameStateEvent.ts b/front/src/Api/Events/GameStateEvent.ts index 418d1ca0..72e40898 100644 --- a/front/src/Api/Events/GameStateEvent.ts +++ b/front/src/Api/Events/GameStateEvent.ts @@ -18,6 +18,7 @@ export const isGameStateEvent = new tg.IsInterface().withProperties({ roomId: tg.isString, mapUrl: tg.isString, + nickname: tg.isUnion(tg.isString, tg.isNull), uuid: tg.isUnion(tg.isString, tg.isUndefined), startLayerName: tg.isUnion(tg.isString, tg.isNull) }).get(); diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 3ba5529f..e267fe90 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -10,7 +10,7 @@ import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent'; import type { OpenPopupEvent } from './OpenPopupEvent'; import type { OpenTabEvent } from './OpenTabEvent'; import type { UserInputChatEvent } from './UserInputChatEvent'; -import type { HasDataLayerChangedEvent } from "./HasDataLayerChangedEvent"; +import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; @@ -37,6 +37,7 @@ export type IframeEventMap = { showLayer: LayerEvent hideLayer: LayerEvent setProperty: SetPropertyEvent + getDataLayer: undefined } export interface IframeEvent { type: T; @@ -54,7 +55,7 @@ export interface IframeResponseEventMap { buttonClickedEvent: ButtonClickedEvent gameState: GameStateEvent hasPlayerMoved: HasPlayerMovedEvent - hasDataLayerChanged: HasDataLayerChangedEvent + dataLayer: DataLayerEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 48441d34..600ff0a6 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -13,11 +13,10 @@ import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMa import type { UserInputChatEvent } from "./Events/UserInputChatEvent"; import { isLayerEvent, LayerEvent } from "./Events/LayerEvent"; import { isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent"; -import { GameStateEvent } from './Events/GameStateEvent'; -import { deepFreezeClone as deepFreezeClone } from '../utility'; -import { HasPlayerMovedEvent } from './Events/HasPlayerMovedEvent'; +import type { GameStateEvent } from './Events/GameStateEvent'; +import type { HasPlayerMovedEvent } from './Events/HasPlayerMovedEvent'; import { Math } from 'phaser'; -import { HasDataLayerChangedEvent } from "./Events/HasDataLayerChangedEvent"; +import type { DataLayerEvent } from "./Events/DataLayerEvent"; @@ -72,11 +71,12 @@ class IframeListener { private readonly _gameStateStream: Subject = new Subject(); public readonly gameStateStream = this._gameStateStream.asObservable(); + private readonly _dataLayerChangeStream: Subject = new Subject(); + public readonly dataLayerChangeStream = this._dataLayerChangeStream.asObservable(); private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; - private sendDataLayerChange: boolean = false; init() { window.addEventListener("message", (message: TypedMessageEvent>) => { @@ -138,21 +138,26 @@ class IframeListener { this._gameStateStream.next(); } else if (payload.type == "onPlayerMove") { this.sendPlayerMove = true - } else if (payload.type == "onDataLayerChange") { - this.sendDataLayerChange = true + } else if (payload.type == "getDataLayer") { + this._dataLayerChangeStream.next(); } } - - }, false); } + sendDataLayerEvent(dataLayerEvent: DataLayerEvent) { + this.postMessage({ + 'type' : 'dataLayer', + 'data' : dataLayerEvent + }) + } + sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) { this.postMessage({ 'type': 'gameState', - 'data': gameStateEvent //deepFreezeClone(gameStateEvent) + 'data': gameStateEvent }); } @@ -268,15 +273,6 @@ class IframeListener { } } - hasDataLayerChanged(event: HasDataLayerChangedEvent) { - if (this.sendDataLayerChange) { - this.postMessage({ - 'type' : 'hasDataLayerChanged', - 'data' : event - }); - } - } - sendButtonClickedEvent(popupId: number, buttonId: number): void { this.postMessage({ 'type': 'buttonClickedEvent', diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 0c5d804a..f95bfa0f 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -1,5 +1,7 @@ import type {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap"; import { flattenGroupLayersMap } from "../Map/LayersFlattener"; +import {iframeListener} from "../../Api/IframeListener"; +import TilemapLayer = Phaser.Tilemaps.TilemapLayer; export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map) => void; @@ -12,13 +14,14 @@ export class GameMap { private lastProperties = new Map(); private callbacks = new Map>(); public readonly flatLayers: ITiledMapLayer[]; + public readonly phaserLayers: TilemapLayer[] = []; public constructor(private map: ITiledMap, phaserMap: Phaser.Tilemaps.Tilemap, terrains: Array) { this.flatLayers = flattenGroupLayersMap(map); let depth = -2; for (const layer of this.flatLayers) { if(layer.type === 'tilelayer'){ - layer.phaserLayer = phaserMap.createLayer(layer.name, terrains, 0, 0).setDepth(depth); + this.phaserLayers.push(phaserMap.createLayer(layer.name, terrains, 0, 0).setDepth(depth)); } if (layer.type === 'objectgroup' && layer.name === 'floorLayer') { depth = 10000; @@ -89,6 +92,10 @@ export class GameMap { return properties; } + public getMap(): ITiledMap{ + return this.map; + } + private trigger(propName: string, oldValue: string | number | boolean | undefined, newValue: string | number | boolean | undefined, allProps: Map) { const callbacksArray = this.callbacks.get(propName); if (callbacksArray !== undefined) { @@ -127,4 +134,21 @@ export class GameMap { return undefined; } + public findPhaserLayer(layerName: string): TilemapLayer | undefined { + let i = 0; + let found = false; + while (!found && i { + iframeListener.sendDataLayerEvent({data: this.gameMap.getMap()}); + })) + } private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { @@ -909,21 +912,21 @@ ${escapedMessage} layer.properties = []; layer.properties.push({name : propertyName, type : typeof propertyValue, value : propertyValue}); return; - } - property.value = propertyValue; + } + property.value = propertyValue; } private setLayerVisibility(layerName: string, visible: boolean): void { - const layer = this.gameMap.findLayer(layerName); - if (layer === undefined) { + const phaserlayer = this.gameMap.findPhaserLayer(layerName); + if (phaserlayer === undefined) { console.warn('Could not find layer "' + layerName + '" when calling WA.hideLayer / WA.showLayer'); return; } - if(layer.type != "tilelayer"){ + if(phaserlayer.type != "tilelayer"){ console.warn('The layer "' + layerName + '" is not a tilelayer. It can not be show/hide'); return; } - layer.phaserLayer?.setVisible(visible); + phaserlayer.setVisible(visible); this.dirty = true; } @@ -1131,18 +1134,15 @@ ${escapedMessage} this.physics.disableUpdate(); this.physicsEnabled = false; //add collision layer - for (const Layer of this.gameMap.flatLayers) { - if (Layer.type == "tilelayer") { - if (Layer.phaserLayer === undefined) { - throw new Error('phaserLayer of layer "' + Layer.name + '" is undefined'); - } - this.physics.add.collider(this.CurrentPlayer, Layer.phaserLayer, (object1: GameObject, object2: GameObject) => { + for (const phaserLayer of this.gameMap.phaserLayers) { + if (phaserLayer.type == "tilelayer") { + this.physics.add.collider(this.CurrentPlayer, phaserLayer, (object1: GameObject, object2: GameObject) => { //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) }); - Layer.phaserLayer.setCollisionByProperty({collides: true}); + phaserLayer.setCollisionByProperty({collides: true}); if (DEBUG_MODE) { //debug code to see the collision hitbox of the object in the top layer - Layer.phaserLayer.renderDebug(this.add.graphics(), { + phaserLayer.renderDebug(this.add.graphics(), { tileColor: null, //non-colliding tiles collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200), // Colliding tiles, faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Colliding face edges diff --git a/front/src/Phaser/Game/PlayerMovement.ts b/front/src/Phaser/Game/PlayerMovement.ts index b70124b3..2369b86b 100644 --- a/front/src/Phaser/Game/PlayerMovement.ts +++ b/front/src/Phaser/Game/PlayerMovement.ts @@ -1,4 +1,3 @@ -import type {HasMovedEvent} from "./GameManager"; import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable"; import type { PositionInterface } from "../../Connexion/ConnexionModels"; import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent'; diff --git a/front/src/Phaser/Map/LayersFlattener.ts b/front/src/Phaser/Map/LayersFlattener.ts index 3ea8a449..c5092779 100644 --- a/front/src/Phaser/Map/LayersFlattener.ts +++ b/front/src/Phaser/Map/LayersFlattener.ts @@ -14,9 +14,8 @@ function flattenGroupLayers(layers : ITiledMapLayer[], prefix : string, flatLaye if (layer.type === 'group') { flattenGroupLayers(layer.layers, prefix + layer.name + '/', flatLayers); } else { - const layerWithNewName = { ...layer }; - layerWithNewName.name = prefix+layerWithNewName.name; - flatLayers.push(layerWithNewName); + layer.name = prefix+layer.name + flatLayers.push(layer); } } } \ No newline at end of file diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 6734388f..a2fbb70b 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -13,7 +13,7 @@ import type { LayerEvent } from "./Api/Events/LayerEvent"; import type { SetPropertyEvent } from "./Api/Events/setPropertyEvent"; import { GameStateEvent, isGameStateEvent } from './Api/Events/GameStateEvent'; import { HasPlayerMovedEvent, HasPlayerMovedEventCallback, isHasPlayerMovedEvent } from './Api/Events/HasPlayerMovedEvent'; -import { HasDataLayerChangedEvent, HasDataLayerChangedEventCallback, isHasDataLayerChangedEvent} from "./Api/Events/HasDataLayerChangedEvent"; +import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -40,10 +40,11 @@ interface WorkAdventureApi { getUuid(): Promise; getRoomId(): Promise; getStartLayerName(): Promise; + getNickName(): Promise; onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void - onDataLayerChange(callback: (dataLayerChangedEvent: HasDataLayerChangedEvent) => void): void + getDataLayer(): Promise } declare global { @@ -105,7 +106,7 @@ function getGameState(): Promise { } else { return new Promise((resolver, thrower) => { - stateResolvers.push(resolver); + gameStateResolver.push(resolver); window.parent.postMessage({ type: "getState" }, "*") @@ -113,11 +114,11 @@ function getGameState(): Promise { } } -const stateResolvers: Array<(event: GameStateEvent) => void> = [] +const gameStateResolver: Array<(event: GameStateEvent) => void> = [] +const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] let immutableData: GameStateEvent; const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} -const callbackDataLayerChanged: { [type: string]: HasDataLayerChangedEventCallback | ((arg?: HasDataLayerChangedEvent | never) => void) } = {} function postToParent(content: IframeEvent) { @@ -136,14 +137,21 @@ window.WA = { }) }, - onDataLayerChange(callback: HasDataLayerChangedEventCallback): void { - callbackDataLayerChanged['test'] = callback; - postToParent({ - type : "onDataLayerChange", - data: undefined + getDataLayer(): Promise { + return new Promise((resolver, thrower) => { + dataLayerResolver.push(resolver); + postToParent({ + type: "getDataLayer", + data: undefined + }) }) }, + getNickName() { + return getGameState().then((res) => { + return res.nickname; + }) + }, getMapUrl() { return getGameState().then((res) => { @@ -345,14 +353,16 @@ window.addEventListener('message', message => { callback(popup); } } else if (payload.type == "gameState" && isGameStateEvent(payloadData)) { - stateResolvers.forEach(resolver => { + gameStateResolver.forEach(resolver => { resolver(payloadData); }) immutableData = payloadData; } else if (payload.type == "hasPlayerMoved" && isHasPlayerMovedEvent(payloadData) && playerUuid) { callbackPlayerMoved[playerUuid](payloadData) - } else if (payload.type == "hasDataLayerChanged" && isHasDataLayerChangedEvent(payloadData)) { - callbackDataLayerChanged['test'](payloadData) + } else if (payload.type == "dataLayer" && isDataLayerEvent(payloadData)) { + dataLayerResolver.forEach(resolver => { + resolver(payloadData); + }) } } diff --git a/maps/tests/Metadata/script.js b/maps/tests/Metadata/script.js index f3ac255a..c857d783 100644 --- a/maps/tests/Metadata/script.js +++ b/maps/tests/Metadata/script.js @@ -1,9 +1,9 @@ -WA.getMapUrl().then((map) => {console.log('mapUrl : ', map)}); +/*WA.getMapUrl().then((map) => {console.log('mapUrl : ', map)}); WA.getUuid().then((uuid) => {console.log('Uuid : ',uuid)}); -WA.getRoomId().then((roomId) => console.log('roomID : ',roomId)); - -WA.listenPositionPlayer(console.log); - +WA.getRoomId().then((roomId) => console.log('roomID : ',roomId));*/ +//WA.onPlayerMove(console.log); +WA.setProperty('metadata', 'openWebsite', 'https://fr.wikipedia.org/'); +WA.getDataLayer().then((data) => {console.log('data 1 : ', data)}); \ No newline at end of file From b509471140c10126e5c6864f98ed7e22e4543b10 Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 18 May 2021 17:05:16 +0200 Subject: [PATCH 031/189] documentation documentation of onPlayerMove documentation of getMap documentation of getGameState --- docs/maps/api-reference.md | 94 ++++++++++++++++++++++++++++++++++++++ front/src/iframe_api.ts | 34 ++++++++------ 2 files changed, 115 insertions(+), 13 deletions(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 6e98dfb5..8eb00397 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -260,7 +260,101 @@ WA.setProperty(layerName : string, propertyName : string, propertyValue : string Set the value of the "propertyName" property of the layer "layerName" at "propertyValue". If the property doesn't exist, create the property "propertyName" and set the value of the property at "propertyValue". +Example : + ```javascript WA.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/'); ``` +### Listen player movement + +``` +onPlayerMove(callback: HasPlayerMovedEventCallback): void; +``` +Listens to the movement of the current user and calls the callback. Send a event when current user stop moving, change direction and every 200ms when moving in the same direction. + +The event has the following attributes : +* **moving (boolean):** **true** when the current player is moving, **false** otherwise. +* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving. +* **x (number):** coordinate X of the current player. +* **y (number):** coordinate Y of the current player. + +**callback:** the function that will be called when the current player is moving. It contains the event. + +Exemple : +```javascript +WA.onPlayerMove(console.log); +``` + +### Getting the map + +``` +getMap(): Promise +``` + +Return a promise of an ITiledMap that contains the JSON file of the map plus the property set by a script. + +Example : +```javascript +WA.getMap().then((data) => console.log(data.layers)); +``` + +### Getting the url of the JSON file map + +``` +getMapUrl(): Promise +``` + +Return a promise of the url of the JSON file map. + +Example : +```javascript +WA.getMapUrl().then((mapUrl) => {console.log(mapUrl)}); +``` + +### Getting the roomID +``` +getRoomId(): Promise +``` +Return a promise of the ID of the current room. + +Example : +```javascript +WA.getRoomId().then((roomId) => console.log(roomId)); +``` + +### Getting the UUID of the current user +``` +getUuid(): Promise +``` +Return a promise of the ID of the current user. + +Example : +```javascript +WA.getUuid().then((uuid) => {console.log(uuid)}); +``` + +### Getting the nickname of the current user +``` +getNickName(): Promise +``` +Return a promise of the nickname of the current user. + +Example : +```javascript +WA.getNickName().then((nickname) => {console.log(nickname)}); +``` + +### Getting the name of the layer where the current user started (if other than start) +``` +getStartLayerName(): Promise +``` +Return a promise of the name of the layer where the current user started if the name is different than "start". + +Example : +```javascript +WA.getStartLayerName().then((starLayerName) => {console.log(starLayerName)}); +``` + + + diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index a2fbb70b..4fdb0a03 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -14,6 +14,7 @@ import type { SetPropertyEvent } from "./Api/Events/setPropertyEvent"; import { GameStateEvent, isGameStateEvent } from './Api/Events/GameStateEvent'; import { HasPlayerMovedEvent, HasPlayerMovedEventCallback, isHasPlayerMovedEvent } from './Api/Events/HasPlayerMovedEvent'; import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; +import type {ITiledMap} from "./Phaser/Map/ITiledMap"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -44,7 +45,7 @@ interface WorkAdventureApi { onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void - getDataLayer(): Promise + getMap(): Promise } declare global { @@ -114,6 +115,16 @@ function getGameState(): Promise { } } +function getDataLayer(): Promise { + return new Promise((resolver, thrower) => { + dataLayerResolver.push(resolver); + postToParent({ + type: "getDataLayer", + data: undefined + }) + }) +} + const gameStateResolver: Array<(event: GameStateEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] let immutableData: GameStateEvent; @@ -137,41 +148,38 @@ window.WA = { }) }, - getDataLayer(): Promise { - return new Promise((resolver, thrower) => { - dataLayerResolver.push(resolver); - postToParent({ - type: "getDataLayer", - data: undefined - }) + + getMap(): Promise { + return getDataLayer().then((res) => { + return res.data as ITiledMap; }) }, - getNickName() { + getNickName(): Promise { return getGameState().then((res) => { return res.nickname; }) }, - getMapUrl() { + getMapUrl(): Promise { return getGameState().then((res) => { return res.mapUrl; }) }, - getUuid() { + getUuid(): Promise { return getGameState().then((res) => { return res.uuid; }) }, - getRoomId() { + getRoomId(): Promise { return getGameState().then((res) => { return res.roomId; }) }, - getStartLayerName() { + getStartLayerName(): Promise { return getGameState().then((res) => { return res.startLayerName; }) From 96545c618a3a6fb71db728017ce868d80e28cf01 Mon Sep 17 00:00:00 2001 From: GRL Date: Thu, 20 May 2021 08:58:05 +0200 Subject: [PATCH 032/189] Adding maps for test metadata Documentation of metadata functions/methods --- docs/maps/api-reference.md | 14 +- maps/tests/Metadata/customMenu.html | 15 + maps/tests/Metadata/customMenu.json | 279 ++++++++++++++++++ maps/tests/Metadata/floortileset.png | Bin 0 -> 81856 bytes maps/tests/Metadata/getGameState.html | 42 +++ maps/tests/Metadata/getGameState.json | 279 ++++++++++++++++++ maps/tests/Metadata/getGameState2.html | 40 +++ maps/tests/Metadata/getGameState2.json | 273 +++++++++++++++++ maps/tests/Metadata/playerMove.html | 12 + maps/tests/Metadata/playerMove.json | 254 ++++++++++++++++ maps/tests/Metadata/script.js | 9 - maps/tests/Metadata/setProperty.html | 12 + maps/tests/Metadata/setProperty.json | 266 +++++++++++++++++ maps/tests/Metadata/showHideLayer.html | 21 ++ .../Metadata/{map.json => showHideLayer.json} | 84 ++++-- maps/tests/iframe.html | 30 +- 16 files changed, 1571 insertions(+), 59 deletions(-) create mode 100644 maps/tests/Metadata/customMenu.html create mode 100644 maps/tests/Metadata/customMenu.json create mode 100644 maps/tests/Metadata/floortileset.png create mode 100644 maps/tests/Metadata/getGameState.html create mode 100644 maps/tests/Metadata/getGameState.json create mode 100644 maps/tests/Metadata/getGameState2.html create mode 100644 maps/tests/Metadata/getGameState2.json create mode 100644 maps/tests/Metadata/playerMove.html create mode 100644 maps/tests/Metadata/playerMove.json delete mode 100644 maps/tests/Metadata/script.js create mode 100644 maps/tests/Metadata/setProperty.html create mode 100644 maps/tests/Metadata/setProperty.json create mode 100644 maps/tests/Metadata/showHideLayer.html rename maps/tests/Metadata/{map.json => showHideLayer.json} (70%) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 8eb00397..01d3e636 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -356,5 +356,17 @@ Example : WA.getStartLayerName().then((starLayerName) => {console.log(starLayerName)}); ``` +### Add a custom menu +``` +registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) +``` +Add a custom menu named "commandDescriptor" in the menu that call the callback when clicked. - +Example : +```javascript +let chatbotEnabled = false +WA.registerMenuCommand('help', () => { + chatbotEnabled = true; + WA.onChatMessage ... +}); +``` diff --git a/maps/tests/Metadata/customMenu.html b/maps/tests/Metadata/customMenu.html new file mode 100644 index 00000000..59f579ba --- /dev/null +++ b/maps/tests/Metadata/customMenu.html @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/maps/tests/Metadata/customMenu.json b/maps/tests/Metadata/customMenu.json new file mode 100644 index 00000000..49840d0b --- /dev/null +++ b/maps/tests/Metadata/customMenu.json @@ -0,0 +1,279 @@ +{ "compressionlevel":-1, + "editorsettings": + { + "export": + { + "target":"." + } + }, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":6, + "name":"exit", + "opacity":1, + "properties":[ + { + "name":"exitUrl", + "type":"string", + "value":"showHideLayer.json" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"customMenu.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":217.142414860681, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass, an iframe open.\nResult : \nOpen the menu, a new sub-menu is displayed.\n\nTest : \nExit the grass\nResult : \nOpen the menu, the submenu has disappeared.\n\nTest : \nClick on the 'HELP' menu.\nResult : \nChat open and a 'HELP' message is displayed.\n\nTest : \nWalk on the red tile then open the menu.\nResult : \nYou have exit the room to another room, the submenu has disappeared.\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":15.1244925229277, + "y":103.029937496349 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":7, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/floortileset.png b/maps/tests/Metadata/floortileset.png new file mode 100644 index 0000000000000000000000000000000000000000..82de9c908ad4a15eeea48995f758f1f0d95a00ac GIT binary patch literal 81856 zcmV)XK&`)tP)gWyg6Y_MGMJTkT8lJ9dB| zAg)7+;*jFVBhA?67_q;9)L-{VB&tp6u%l-VU*YmqP zZX!)m*a7&+g*n9V;ClwX8IKtWf*_CBT*FstK&R}({MPUF4UC+Dl^`%fP0|SEQr?c+ z!1rWKW*h^*fVp9(*NJ#@9yl%_tk1u_7i_Q zbLI@X-LC9Aj!9qqEiiqu@gBbC_xhequi0fpW~i}&ujSI z%*>4Re{gUhee?V6?QN7wCBX;Y-|O`zIKylC`P8XXXt&$)9sA(#J3Bkl&)nRce6R3Z zt(JV&F|!Ze!+w^RmydmKZ^mX2)oj~DNJlCJL6F#78~AzCS121h>US|14M4J1 zDsjw_`Q6T+*L%L5tAU>XN#*|64}OGyvGQM|+vz?8Kh4>-{jA~3MmG0w-ld={`-=N#dj5nz91i7v zA|E%eGMufgE!k)P)J9mBE?p8hd~yFa8jT6E9S5I?#?Oa`hw@o*f}i=G_qc8P^X=QW zC-3+6_HgmyMVUKcvtJiJ8}}dAi17J68`p{bDE=J>pZ&Q_$A27rojVDG5=+7j6}VC$ zr6_y|I(gxg=4K)@7fUHQDG;wyE}(Imu1dKVP7P6k}uvWX?BSAnFTe-x#gqC&BlyQCi0f?N=}t%nSU% za4=baa)eI{KQ@v~keD?q8R8I{^$5qvrFkJZy17U^jm%&qqY=EMkj>wFDjMJp@b*vmJzUN_(W1+PG&BAX5^f@w}n}l_jW%h;S49p zr`PZ|&Xavm`e5IR^e%k<<#qg>FRlmSu@8=w-?{J!OBw9r;1dS#)9*h1_~VH*!~Lxi z59c0|(ok$;hg=~2%Lyv=nMQ67TE8O@PErYjE;8>`sbTtlU07Z>9L6YBOn)etYYo>h z{5LY2E+&yn&BITLY-aOuGa43TmQea76QVjW62fG@Gg3q%uu?$=A4WV3%;p@Cka)t4 z3~!@yVa8Sv2_sHN7-sV)qKlXg&cSe|vE8KPhG{nbIJKfbr2)cO3RlsKI{3%)|2N|I zj5s+mM5Jgoz|bI7d4!*DzkzRt|0=s5kIbJ4+v{}={5r6*^Zj7ZH)_lX#eC5qZwGJgzK*J2Lpd;Ftbx0CYSXN5i0{7r zSNPqz@5uc4n_d41`usW1MmmRDFk?4r>^=1S6~5VCi1Q@Ku}B2%xG7^_Dz1pMFc|lR zK!=7{lCUOROQSYeUgtgX{0X0Xi2Fy?M{amNV_74!VHI&yt^71i#dIP7MQU;Y=JI-~F1$yH7ZHsFXklSN#Q$mdDh04F5=X*P_{x;| zm$0=Fmg3%V@U=fS!XyDA(K&neEbiUAC;f9xgwe5MSGPS*>^hFKE3ueHepf8fK_7Sj zL_LW4o;CwcBoO3R`QJ;k1)^9Ua3hXnlaafp8u7 zzBhrNl8BJRaA6I9qHUmWxOrp{focZ{2c-hvGYd{tL~Id$hPkJyf zEOz5Sj|V-lv+Y>ftaM6^yZ-{!KDg^Gm=G%BD_Y>4Fmhq*Je+S9P+_z;o^Q9q{b0?7V%yTjl z6(#&(G%(!RtVis9iszrAl^hBY?MH?v8~7csg%@XEL2uN-c4rIMx*y{C+RH{InzjA@ zlIKr&e6PB7cTEv71nHW!!bmU zrlHBeOzdx|Q3)(RG8;HD2XTn!-Qf`^u$PH7B8^yXdj?DK?9>mI`7eg75grB*8sdgy0SNLila}i776FC(r zc`f@;8yXQC2sY4 z{UP|FK3vxm@JSkhsl7n&S3>Yfn-C2epgenjDjUViHVk2SR^O*6PV`MPv6O#(tHV?D zhnV$@x?wnelG;9K7dT?Ni6FHVB`va(&?sV4{72%O#W44K!m|vQkA&0Hu8^7+y9x}E zIbXVr++hiYzgk4;Ob)xN_u(JrNrnvK9%6tV3S}dKw2ioE_6!lL^Vn= zzqX2>j(&vg`E^83_b_f5)$2iouSVa(r+fbPHzIn^?_xGukoh)(2KJ*}JSf~Tu$!pt z*YRIY{3*V%_TS*y%8O5Y{&(-*#mdTxY*IxaZfLcaxSWs8B?xM@S8jV;Bf=61cnzTNH_(Al8MX-4TA=0{lMr%NoYL;DP4(ya3p#ZJYkm>sRi+oOx%3r^ZA_7os39L_^?-r z$bFdXqY@g`2SVk*qp&C@t^San7-9@Khk?OBkEmA#IeD0C; zr#ewK_sn7eo$GCpdUm62S-+*;NnBrf$1Z2jtk-^sGsAOuuJkfK?elLZO|gH>hl^+r zTOy5Ywl;7(zK)hbet#iBaj$};l;X!re~T-f=VWZ2qXN0lUkQ%t`HFDlRKO8oIl3IG?JK zj8uqBIY?U2zuhbjs*FwSZ|Tv_hJ$Mqfshd z5c#>h!<+HfIbQcHP2RM~G zi}hQ#F+NPN@N~t9;DPCXgy#mIKNk7j`TL>W>{J1$;>-mLVi+WW+w48Sx_29`YU>fC zy4ZYLh{yE$hm=s3jPzi*`|j-rz=@tn-iM8yqvy7lL&2=$Z_KK+q>6ssq_q{RRDedY%0#GN~v5{ zjc!kB%4x|#iCEK3nHBq@g`Hee)sKnvlo_sx803)3Wj|~9oR^CCt{$%Jb4Ih@wtKM5CisiJF*oVHdz>3+R7P9o96 zJ&%(XEuD%tVvb4FZd#j3Tw=rB(@bQK#4>INKz)o<+q$yE+HZdMlB1v>_8-vTg|QKd z6X{3b^F0xpJ_xh1={dN%`wMJ+{RYymhxf0)gMYX1?{VPmqJ%1+3O*#8gVx5qU=>4JAXl9^RF0G4Dt_+-ajxBNgivx zU*PTMzke)JeY|;Hbo%M_=lq{48R=ljNAF%22TNTfqXc({w^1x*o63CtYWLfism}?a zp{nyqpFdrT)>e>;<-ePD@b3N_cxV4DGz?kkT-t(fBr&>c(@oRYh~WZ7c?Ns&wh%Z< zQSSWNrp4?}(|E5U&L?e30N99#^qWsx^?x1kl}Qpw)my;(NR-%*x(D6$pnXJ%0LQ9$ zrjh~QyYOAYrYfQunsr_-{7@G{eV1&?eIK_FYM@XZL){QMIM;pjxcha0UP!K-h}bTi zTP$1F;6@Q%^!LnqkL-UNG-M5ikxb0GheAJZ5Smmw5kzO48#%rwHh^)a``f-rIL0*o zBpZ0E`#L@zUdI<3U&CH=AHy4lAYAsb-P(k==%E-Joj)yNKfjIqpk#;(#QM(fTH~e_ zh0WIPZ4QjI0(91fD4Z-CgdSrLJ17{bVN~g()U7@=e~ytHpO$&gNCSzVpc{4YX8Sd~ z(|Yp>NL7%vI`oY=8P#xqd>2Iq>M*D$4RO!AgLKYtkM0<+Bwxi^`xXv!+ZY^<@U6!0 z<3jl|21(z{tBg4OfY37LWNHRS3{s8 zta{m8TLRaQ+*_pq7rq)NUE2=tQ`JVL5w#zLE;Z(0T(M_bKhvh%LOGb~8Pi6LC*7}` zOTvHyUjls!Vdft4ESDA|nMCy^nP(ug#nZKyWI;+I2H6P0I2wpmoMgf?gun>n!hNjn z4q(-@!+vcg4qk#d{vhFRY5+ypyzW&%cc~>fgh2GcVx+o`pX!$V_7;V-*Zi zkdtntcX1_t4sA5?=a>G2fPNfO&5joh`WFO&g|0;@&gL)3+HAykvESLlV0(=H!9MzC zE^igzKqY5HJwL=BEdE<@O>P*1Q8VPFXlC?jon74`g!m{|DBNKoLI? z51@Iaa;@cNp_Ly*CE$0tNeJx4@G0E8b_eCEkKAPs^_d)cR}J@EOL21c6#k*{S0bW6 zv;8@PFjXNmzTsqdch^uW)$oOjUq-1=!g9JII(X6L;Hi)W?m%hv=L-#Kl`L z8q}K?spUbkj)ip5AXNz){dHVB_z-6|U&QQ{D&DRA>{z6ld;c{0wE@O0BUz*+YZNl- z4hh?ecM|1F75-TtuliracsRm(Zw-y&EN(?tu~=L|Kj~p?)@%-oX16?S(ETLOf7w5Q z`+*@?b5G-M?)+!;-|gY0xv%2Q^he^0@e*I`CFA`>Vg&ZWE!4s~Iygiveg2W>KMn6! zZLVMbag7|7O_73gqhU-rr~bz4D0=_8;B&pzD5zHZiCrk;&?@#TUTIXJB0rl;bTraX z4V>zBWK$_Z;cFAm$3%aeLfmPtt)DeA%Z<*`P2~3R%kI~QKO9DxOHQQ*8{sGM?34b~ zkMBt=zSs#;dwtCBjd*Xl`;qI9W&&gqLqh9)Ml5-MlBn?}!KLt7qi=tVTR*yn%5z3U z9eX%EcLrUvI32HzbkD$U#L`dCe9lEB^MJ-!uB~9UI4`2Ds6c+C-Peq;RK$2=jA4F={ECmu)hk#IPKa8=hf?vZReSpR>!$xz z8j<&tBB~oY>v}zi7@Ab0$m5RfvxcuB$I3wUvkRX{u4;fvBQDq1;2!p&@YNH*&m>~j z!0t_4f2!)x3qUyP>I{{#sQBj^gWN1E{hmPG@7+*h6<4O+JQH!>xnDVspIQPChSbMY z{PZ$+Uowdipmm?-I!5iO8lY-NApTMkB5Tmfdq=x;@7TbPqCCE} z@_V>@a}DjE8NK*K4)>FLs2Dx4=#??-#K;?DqFZo0Fbf{#Mf7F}Y>z400jf<2T%i&VX+kJs<~ z2zi54qm2Z%68Qp!(NDQ%rMW-mGmC5@1UQS~4%bv}4BY|vqvv?}^yj;g+jm+9F zdnY7tXq?#m4Bhab zAz&UZ=baL_$OXJjOXQi!>NLF&T}<_+T0U|6fvF=|@_;R0jd$9)_;IKNfv_m&KD`CeY4{lup)QfMOffLIb^tQ1f-3pE-JvN0O|lMh9| z&leh5&(X)NC`OO9~5?9A> z;_JC@W4pH{NWa_Wgue*NBsuT9~*L`&fxXE#y!if1a# zO&j2~51G3@d=>vRi*LHA%TM)1QYqD6G(}SN3>~1l7?mSwPPQ((4M?!5x2fT9p5*SE zO%oKv)hE{biB;bsK9QOt<;e6Ci;IIPu_cM>^Tjn;6(d5DWHA5~_r*<^bKnmQ4C6l$NN=A69@{IWAJBH(Jcek)qT7ftA#W+|m&S0gs zD$;-uLqo*2_BPQQc5$YD4kxRpajtg}N!y@=fw@#zkp!G^JQ9gT*1wdK?8Ao9lZo_= z@(d25J=B6a_J_NuhIK3ymrxnhFrptYp*LUw+sOk-M;7F#5!7SkS17K@&bTf1fOg!% zGFHV_aWLA$cr-SIs)i_xCIKOz=J}V6#E>)3iO-+)4Dz`G&Q#9}{8uYqc?kZ3zbx>1 z-^u(L?Dn@Ff$wfg)mL@jxY=@UQ<2$ikINF&YY9umYBtvfpt`XlhMQ*lS;FTvssbp? zC&AaKKXnbN!SFcv#}O)i=N25%3`I>hmW)JQ6!k@_ex{T|MF`d1-0VR%E1E~LkH4<%pWTIT~4f+F@Cn^;MI&j=}j z1SPGMPa+;Bll2etp@c5G&!6!3OzESas|#EFDN_4VWWa_e2FIIq{Mg!);-*PL1*zr^H+m4~9Qrsq$tDM&XiVAvl%vi?*@n2+B}dlDx=F982m&6udJ$oeO?a?jAH zLG84KT$snz(YsiC`UBkQp2t5=zk^}i#~UmEFAg5;;XC6$#6q|%MABVM4)}^UiZ5>6 z43(fYIZ5}6;*y(!thO07XcE2_4&isx@OA$k2S0SJy~>$&GrQJ%x9Q@zlXC|=-KOtX z!Xkr{vR$DdFVz4E(BYxkv~Ux5ZWfKck4YkcRZ1SYjbXMA(nS z?zy4&$@zCEojZBs=)mJoOyBVLJVm5Gz6~;YtW0#{C?8 z%$l4@q!z$>cw3fWcVPoRzWROqv-&qgg>ct@m<&+zN@8bVF^`*_kMM5k4Q$sQ;FZCb zFqc~t_);k4*8tz$XWBk(T)?OG*}Kn6E#hjG|5bvNJ}G= z*O*QsMI?6#l)~4)n*OVOCk`E1-|-E zoIhc>>(4-)S$|&OdY&x?!hboV8ZjN&hwrTa7#rao+g7#U#mletg>2#LcliGAqj!)ZM(Vf|NYiny0mE_k2pOOZ-wd&*C zFYJTah^*A3jlZk4-sRrvMpaLNtFox!PeX;(UFh0V6kpX4F5&a4_bKwboAq&Gkanck ztKsiBV)3}9;!awyWxAwnS5^VYPTWw#kQhKTilAA5{71x3vwy^6TI~}lkYV!xRMe-A zpOA|)KOnV8$?JU~dSO5{6R6FnvL!m}Q2;LjyY}H|g zGbf&wDS7f5cG5QP_1ExH`IX7~GrTwSY>YbL68^x5+!a5|+9Of(l(D`s8mF*f6kht_|$w~fv49^NjzhQ`G*Ub*$# zA_Zv`p{4w)1Q=Dks#UjSOg?fcJ~Q}C7GnD}dxy={aetMjY6#bzX}RhW{G?f}zY2Wb zqexG}Lv@4jnIi1YU8Qif321>4#hGdNdatJVYF>vM_@vQ*TF`_w7&bOGECFyu|Kr5k z>86H3eQ2My5QrN&Sdch=QYugMN*Rxhf0Hs_FbE)3WhC$?6)C_HA5RdPb^=xlX60Wm zOCDnK54ksSd-ilLHYqG7EQwJ;Yhpr3YOy%z&9z6o4I1Sttnc^Jk+ zAwE=N&fp?8-noy?*&T^uWDG;xG$W~)Ira@V85)9e-pqF3<6l<)TN}BU&6BVWl3h`S z+CdZVop}wHuD)ztudNU#@}~vHts!&O%^2gZ5&z40zVz~E2ET*OWRp&Zi$AITQ;>i9 zSAn@Lf-v2I{y5bxrJX;j25*4bXEFjkpOwNoE8ayi1#cwGKw?X!%@+Y>G`i8-W6Z{^Tk)i z)zu3+$i+rH_iX{uU?TFnB`_Xsv;(k!hpvA)EQ@QAVZtOnd9Q$?mlb@-2tvs#izVK! zpD*RdIHRxBzK*~6;7^gC4aFcyRUsVtsN`yh8)HN}LwsZRU!#{Z(hHW*N)Du|Pt|MS zO5+(^TmJy9;x_hAZR2M3eTj3JTU){V!?&@$aPOfiLSKo#3G0^qY~T|iG&4^{aP@tw zt>Cz(#XPl;=i{0h!PM8TdzLVj6SJC*a#oF3`E|f2erc?R23K($)A0GdO4x4vj2q7E z!e<|@i0?++@;k}<&*1Yrg-6vRRMB54g-&=n3B+w`BvIs7%c2|h`=sU?7pbBoLtFA& z;3G5kXCl5Qp};oTMG)Mx@d0USr2@JThpbE-`Zn}8NwQK~M^R7|8>G5!)+F07iKVEe z&OdPG?>SR`$R=X`ogQAm)#P1VpL-WQe}Gb4l*~F-3MNv=)`yvm|4H-Lx`Z}OnQ;n) zFSYt?2^0IEjTAs~R5r*@BP7*?N?McO36B9nok1J_-Rd9WZ`S_;-NfjaX1>+>3`UJU z23uo%ap^Y^mB*QF!943UXGT0LNkJtef-`cjeWNK=g!ZBxS-*wuDsHX*!p_^NB6O+t zw5SQ66@1;$Cr+FYQJjsU@h>y1apUv4X&2dabN4qr3|b@q{{8!t+EhyF21`^M2>jWec zGR)ZaDC4%Qr^ot$bfMFBV9ySK%`AcvwIq8e<1E!U!ei&J9)~pJ<(}o}%xtUe&mwAc z;j>cqrWtq6AUz2f?|o$cj_cx~`5(pHvn~PqXJsHt0-|Somg*DX>zQYQ`3Mb`3XhN0 zpUF7+K>@FKeqiPk;Pm2YyfXh4Z1o?AN2It^Mzvg(IY>T(`6mR65?|U9mEz38IYe6# zHa}hmP7Yn0lSGilKz^?kex?($^b7%w zz|{;tH*P`m8&vOSQ`-PfDAK;9D5&}rT^EQe(j4ar(1CEWK?JhtYsVKgjxv1u^^}OC`z*fmrmjet+v# z;5U(#Ct{7E4aYv3{DhJVs-HZW^!|) zXMd^oo5HCXkG~adNHreX9H?4E8Q~j8BeCRPE#uJ={U*B0dn zw9gX05g1+=cF;J1$38_&Ohj z?;cp9aVQ#F!TYra!Q^N#_lDz)Fw?4l>jG4SQFp_qsRy8hCp8G}%ZWac>t`+WBF2wJ zyk{N1zz6go4A<}{u0n$lB0Y#ClG!ChN!BS-zaQyZB z-w0n5L!Rpy9EJn*7a3l=0&mBkSX_UV`M1(0s&Pf?8qzDE)_!}9&Dd)MRqV&RsChNX zP863=SP+Bd$hXy)*6^{|3tr5>Do1fyV}~b3!!zM|)VX~;KAd6s;;!Rhj3)Z_Yi zO$wdd#&!5cr9ZBU&{yltAF zYf7vpzPOEgFAZOc_~e-6y1a+*HCxVwuZBVG+hr2UU0t`E=Ef*|?c+H3BnWy?h$5pN zlA@K1-2-^sc!g>B8p%6d(#(x=ThvyP?e zvQ*u9#Dn4;83L#0f4{#jasR{NNFx5&Z{Jf#<+*e!AfpjKem){+(e5e!<5} zxi6UhGQY4!7}@p|p$};CuF^QHvZe4;Rrh2K5Lu_RSZ|pC1QbJVF_K zB^*4

I3QPd|;1KKe+$S7ZA$eEuatqvXL5UkxfEfnnc-#p_jq;8;}+d8i(MQYY8P zui~vMw(IYjll-gJ6OeoTq3FY*80NB5g^c)5?k_Z6&g}CuH((atn_7{c20uv<3T%x& znh02RDoQl;HqA~APO`&5l8G@;bgv|mbMl0ma{i13@DlOAPvQ>DYk#mS#;xI@p`OFY zh_YvJx_DkhW#-54^>(ly>|&|7io79WEu$tJj`ro8zSYvnhvvW2-$p++B4K`B+-8K& zq#D{SyFkdWXqr2@{|kB?pdy?6)9!HUqTe%zM>N!E?{P9J?xw1j1XI4qz_ z0_fS0WrqIFMvE8}yEuL76kZNq5rVMZwN->}4nM@H$~ie}aAYL48E;Nb2>vYLYaKiy zqL$Ytr#y~}PY5d>mZTo{8yjJhqpH}fhBv~{gqUggM0h>;PZ7H{NrjX5H?>L*rc%oBn*09XGqGS z8G6&f5UzBf1r6CWA6btY{-pWjs?+FuiDzbY6rQ>}8r!0va!7#H-N)H6U9`~WjMzJp zLK~hG5bgDNJTgUL>d&kPz_ZS5Wg!v|dIb{6FtjHP=Xu06_3Y4|1uzg_X@Hr=jHJp^ zk`NA!p+v*UskjC~i(yIJTCAlT zXBGe*^+u?cYd963L8srwetTce{NwTJjdIWsDK3J$ zC9;nDT?1-V*QY41#y91l)9}@{#h2y>Xyn{+fkG+~>7J*wKx9@ggIe;5W7F_eDs=NA zG$mPbG<^RP!&iI4G<>%LGYy>zUrq<++3jAz6OlV%MIM73W#4Z4hHrE0B?y5TZ|1>C zXsY3yM2oC(sG%~#Awv0HzrwyhgG8kw`Nc(RLuGtZqn(AN8{@AZ{T$2A{Mt#i8K)#^(Qez zgRa72qlA0CHH725kvx`BuheDzUHI+%AsW$~z+dm&!De;cs4WZddqxBejOrAZ3^EsR z(nvJ9ECR8fuVXP?wnwzvY%DC~=H*$@+Y!Yh5#{G+7tm_9q##SRWXMIOF$rqneR4o+ z$OBK>=z;YNmL>)$;mYPg@o0E0sm4ZTqzFyXTajN8%Uyp(6g85$n}2%!ndn8yM(s3w zQ4Ht$f9-2uoAj-}Yo%+|zukncW-zY?B`O& zAZN`I2n*BRlV+Z`B(a2nM1$A1_JQu9{k=A0?{f<+nrYhrqBIMRN{`Z`#gA&lUnUN9 z&4!-Eyqv=q6wSlTQ);oQ1|^QEBcE?_eQ)X_7v6{k2biuLd=ha8=!!PJ#br%|&=cbdB~?$wK}7ZX~YWtFit{0H!^0 z#|0i87m@1{EzX~FbVK&Vl_%}JWC2`O zilWpc*}V+4?OATkapn!;(~VDVF5JIhkvoo#2*+ge29^Mj`x{|J?yokCzGTm`1f?m? ze^N@zAcGni-2e=}Mv`S{<{281v0Xxxk5DoLphaG)%mijl3_@~k=sqll#R(->eT(na zI3)4@+<5g4&Zd`8%9kY8{-c?L1uQ6rBFtl8+v1%ni2 z26oXVCzYt^hNEy8>fsUqWH7nYG@{?U{ho-*byRWP-~?(*FgmK00yL&ah(K&RBr=nD zkQh*v81}7%z($FpKhC5Ihq357n*I84QPc5J$ul=NNEdPt_R#g(s2Jpk5M@?v!(sED z#I;j(795JD!4QL*o?D^N?H|n zTw+wcg~2NNjXuK7I>KciYx_5GA-!zoUzd!>v%y7-3PY(lL}Emvq!>-DJ?=YK716&6U;9<5$3=ek zbRd@ixN$a*Yi^Y7w79RtMhk|DG(v7qot_4_L4SbWpqF{RvaGgL7f*cJ23iof3lSXD8f$oTb}3;+;P9M;0}sJZX@i(yz;5qTRkVVp6Ipg;hCQ zkoWF{o2VppA&zl2vEw+Cil?)KMUgCMd=y08^RRvA5XITN=;$j?EsOo+)WLZyRF)8q z@<@wj?eA65d#ZzOv12%D9dA{Bh*8tbV=lt(U>ghJ5~?s<+#BF_a1GT#9h=y|g1>~V zr45YDl#2C|5IsAVK#Y*gv?TJ=&LBlQQ=7Icgx@?AIgrG&=NZyj+x1#_e&%zA(Dv|? z-5=s=`CZg5mhh#Ie@6m{CYgn~Rf%pC#$oOsMrOTuTwCltas4M*pIpiGNCZ}5F^&9c zS7CFD)I4tel>oR%sh)vpuZ!-L;|z~>UwIF4YmL@ZqqwV=D`8TkcVDiH)3qbG;{0*V z75QBP;1;Hl{p`REX(i`B>iQJ_MU+TkbLKP4oYm`n5$jq}Q{vMZu|_{JeZOIP6avhm z5v+&Dv{>qnOm7v7x|hY(ig*7=G!a8zoax`O<<^9jWCpu*$|m61oSy9L080RPkC9{r zsa3q6zVG3M%8ZH8QBdn-Onyf6e}5cEVNmMY zm0sN%z<7Fbs!@rL*4)<(#caPrZ%2+0Z$~Yhm_Lcl+6nZBJ?!`P(R}9+^Nj_J=f^0H zOCs(wHo)%&7~C*w$kQR(_gfe@M)2BZEWHx$4ep>`nvv4w!(tCBIE7xJV+cw?Dh)q} z&*SyrdpH%Jm-!Q!DY0-~Bm&Lk0OxX-Fo^qTjt+2R@R1b!V2N)YWuBxq%=$3h$I09| ziDH!O#mE|ddtn=Io%sh``S2CH_N`FPGHk{NSRbz0NVNbVdquDe}39gC_+>P1lLU>f-q*(oVa8&icqacLNWn`XXqZg!>kTz4^u*_D?rameITwi}qu>}8e5Zd4 zCI1B!iuSZzk)+I^XVV3%JNl8$U62ex@7UZxd3b@*vw2)t5@K_(flm1lbLCl-;?o$< zjnN)9QSZ;8&?#fzh(mEBmbie!)DVGtMI>jDEj=t2Yv|aB?4~0YD{$3PCvWVyp+iCdzF%uaM9x;hl5t~6`K;9rW0|? z#=S!$I^``zzqX;^qhu(XH8MISQ&+i(NF-!&cpzt-X4~CNBu%oQ7MsLlO$R7M?!&p zgP@m_=TI1x(CjzGz1OT6Ng&)uZ@+{6;TA52Por$~o?y?2?T3c4&lwW4Yc@u2ghIur zWhWE-#{Sn)>&zi3#n>7?z+$k9&HO!_OwJj-{ZOI{y}l8jYc`jmJ#L8(zZfjbnFCd$ z!_$kfRl18#p^3_V9e=(0r}*;iZ{t$oY0QUpxkeN!2Fj8A6}i(Q#&KaetD5Zn{ke3eh{@+6&YU zFzp^x(OrLYo2nq%w_Bc_%~dxzUh3cs$WiXhh`nibz)h2OZ3wfNB6YyevL{^D~!)m3`$} z&B4zgTLr*;WF0!c5M+xt#r2)%_>e@H*$L9@{688C`5pg`pK!6c+H_-rM-;(|;#NnHNq3 z=&y~?{y0MIWJT7wIkS88EV9hP-zt9_l|okO$Z<_Qu1!k=lStAaI2IwF)ZFz~$w3K< z5&<_!$jy3H?yL3(cRZSG!#15#tbs-vG3(}zxGI2){Hj9ewaVf39_8kohl=-V>8BmT zB@(K3xV09f4;q0a0BGXBPu*pnNCmujCO0qHa4ZU0mV+|0d}o_8D^E$H?vK0z*`389_OVxe zfKz)HQ8v;^5*lP#8KJShgy)uC#A~g;N7^uRF9s5|_f+>KEEP{-p|pr*!AK6tzGU!K z)4F&X23{YBw61aiidj;Y`Bw}o64pG32a=?-*82tCe*XJ{)ago$?a>Ad{lMtV03UDO zz-s;!x@jBl?!SR|_TQQuWgf;MiiR=rj9;&F2 z)o0Z8bCFqHd~U?slbXB!(}ptlMO~l$D>7>k|7gFPrM(0HVxJH`L3s`o>PO5|lgTE2Wl zBq%|U_=z3BaT!X`Pa3q`Xyw@Iw^x-wk@%Ob z|8%6E-Z!1D%WK_|-J0gBu0oAK)M6frta`s9yTW#BaJnu(7fFfGn)|QnhxV;U`sujc zaD9~sl+dXv;KnE@?9d*Q9f^R zNlT8Arp20ieyk<3Q>AuCDT{Gpk(o$bFmoHl59{l?At)*A-8tgksxpwsG7yZ?fa3v@ z0H82$gNDSU5oG@VOdU|-z&dwnKE~D4Kf{;yzlq!^CxjrB0;NDBm^GVv#y;G93+d3T z!(o7?-xO(wqJKVbEBk2GUKR)49B+tg@LchdU2JGrr+pY&Jy`4pxe$N-)SuuBH-1NS z|BcaomMlOsJ;0meAB)R%tG2R!}=^h=;(7JbWqt+xTen7f5mm&XzA2WHtJ{ z5%+sRTi`QISDv9k?s#Z6ZY31SWIx`+JeI_3vytA#mH0Uc9QyN1|3TJe=0=s4MtF;6 zE!rW*zAai(9nFXo_@KFgh23*F`P2&DpLq*04X{Cs-d-Q0Ei<#8L88L}t`^^yXh3?5 z{$TOnit%w{d{>Hs6j6SN8(Z->nnVml#aD(3H5i z<+}9*Ecad_sg~JRL{^KtOIW58<=lQ$0&op|>N(J$CHAL5Q|>&Jkh!VC8Z@Qz(Cd^K zJw#;4{e4pZB%LHAB=9x?7 z+{Eh8()UCZ%Blh-N8XJ z%lm$IhJ#8S9MAjr-@z-DSIs6L3MY(=TI3sI)jyY`d$3?uq{tiluHGFjT zXGYhqid!$Y?c?u*|4T|~rCDX&cTfK#Ui$ghF)A8eGA^QDZR2A33eJQV&?wGG1S4Iw z?{=8KrUQpLNq zpBbcP(3jDJx!5FNIS-2;oI|(Lk^F<(n>P`?8{x&dui&lp#|ST&jav&OH)Ql6#me{; ziunR&%X6YaEE*k-WzSg(Yz~WbKRsm7lZ-a*lgJhQVFQtHgs5!paak_so{pAtiGcf8 z36C~c5>S;ulZf0%K!xLG-?_-F$wit_q(wVaO3>gRmkVnjZVUnclFPf{#I8ZlRWDo* zgh~M#aF0Id~7{A%Z`ck8nVl4eE%p+*RdT=ba)#4k__pUqo-Ls zfaDUyM}b7u1#2@<^M&Ic zEAF_BxsTB@qPu61UnK)(0xp(Uu@&6Mv&%2wuWtPXn(vhH^6b~})8vP?K6By=0Uz%t z*p43Tu$NSxN zoXuUFAdl+r(}*kkPn=Oc+ybp`JqfMAqa4?*%{R^Ur|)->-{t789b#HKptnFdvbypp z@@v0pR8;Qo`row>sH+Aj(z-~`reoBxX|97FB%*FTtxKpL4EOv%RbkYCsoy zH=`8Uh^^mVif>6oPNuK0q7F0=!b$;t_MS!~#(dc)k$8*l_v- z+q+xOGt3L3vO?DXz*IGQg%WTtMIJAvCH6>*l3d`SGux{Wd<@ zdk=&00PXrAN{yoE>Q#TnaPV`et=A1Kqs=!e$TdRjd)w5*(C)UeI)6d}uYPd(FY!Ac z|MxguIFIekb);rp*27ykpBg>i5TpkMBYGb!U_02rbG=t^wf7!QM(1#EyoQ5dPdp*B zrCIc%K3>1`BjgRS8f};v=ZDCz1UOSTV~9-=y+H?ehihUB8V_TcKTCx5+eYP?KQF2v z31y3fB3G3M@ND>!)Now(PFS@u8Bb!;)tIJ9MAoAONwDIRQe;v~wu>-ypYi+s{XGMw zWF(H_MBjFUcXVIs{Yp4oBzL*-H1g|l_JpT_H_Yi*(O(IGA|0Dl+{yg=F5(|YoRk=_ zsSfYvJ}9EA+mwG%>eWyf6BVFBD#p-9=Ag4M2kY}OU?3NW!HMbt zOK%knlCxM3-G0o^?+tsxAts&*iToMUS09~j2S0B81D+2)FXAhY6WjOp4cDv6 zQC;Oi3B6Gt6~89dcLw1cU_&3< z=6tXql)W`NL~s%~fBz{ALL&(nPFdNl;Y$5^sTI)8x1=2T-TXB}uySHxJDHxt;>wC4 z0v+rGw~a*5!{49(PpH4UVi#xR$zdG#$Lms{WT&vf+-9Uktk3TiQOcFX7}p>7aq!>} zSK|*Pr-Q_+TrEi;l-Kcadg-*acO87E-9HX44mu2p0 zFpcW!~q4ls;fmUZplt`D8FWqU?bu z$WQBkoE7yDj_s6LpSbXXBaTj~fVBZQS6*9d9N7;FWhXK)vm-=9dmSYW<_gdTASuY^ zJNn$+gCNubOOaNz9*UwyO<~Ocr0Ak=#m9WNj2R~=pB)=jB7Gny9iOS57o>W* z`~^uDf6%`#_t74)GulSOpOb9K8{Mmte6;MHlkf+6lTflYOXGNY%y0B18&@pY`niA7WuGX2}WwIs=^^@C`mKFDB;#D@={D! z-@b5qSmaf!zaoEE#fBRN4GeOF3D;oE!H(aPR9|LP zp3a{`GN0gf_a^3zczwHfLpD042fAW;-@WiQ+HuR!izW2R9Yli&UqAg#eE0s}pnbcI z+6jBC6(a__2Q7KesLgtR7S9bokDYKEyV0g3A~D66c8qugZvzv}waX5|(Hm0Xm>MhlV%X$?RPtWlj<&Kxk@V|j7e*0{);BC5LHRF_vT zfO2LxrI+uODX>D6n*-o-ay4*14(Z+R6{cGA^}VVzTII+kDtu`rC|6BTH|cTp0w)Au zWH>U7IP%~P_OR}rO#rg>>uCX(LK!?sCp&q!oG(vAbn16J8(v)6H13QeF#^#iE~TNh zkV0}aN$cYrNgzUeItsOuimredF1(X-G{&Y$P|$=Z#rMI<_>pAf3#1ZQR z*n*UDy0KYw68Nq70p2})6N_^zlKDxG0aKD!gHz}j!b4RlNOEE%r4jjlbVqXhKZ@SP z_@%bt`giaz@jswFZsNPEe}@0K`M=`d4gM!wC|aZEWxS!<&_(yTvX_~1Rkb)Ur7NJM3OfF3w zT{(E-1O?f9EfG++9uZlQUSkEK2uG1*k+uBW2asI{t7^#ohHecUJxs+sH>1kk7~0%O zEp5DJCO?Pnpo7%tP4pJ*kM@w{B9xLc8u6^9&^WSaOXy}2qHd6!hjcQIidA-5KmQ;w zB6L*2lHb5?V-s`HBG!Z3D2_@v@b^Uudyu;;wF3L-N)e7TbLWhtaTy=)+!XHyi4spP zJ~=#(SGr%uQu(Av5%-ccoJlW=bVdYcUIz92fq7mZcHYB>#ka6i+rk%zUlV%(PbQ-J zM;|^tKvWG_7){QvH~0VT-e2OC`j_Bu6)-HekiTd);xNI@;)j+A%#ZPBKmQZ_o25TO z&%mK!+4WI>+Vz(->P*~MLzf222*Ts20uPbhy`N>tSoBmgZtza)PqWo}E5cEv$0zPVefam8w zZ`8092c0sr~%KVs16A)nQC z=sdH7|Kr;Kg8y;h-%r+&M2vw}d@vF$6GxwT{gvCPJwS=EFsXd*p+2-9dI7rKju^Tr zfx5{uu0MX-ILE(=bgGAIFpcWtyoSG%Fe!IegP`^`O>A6sMJ%k>T4K!ef;2q@8jH=bGZEUCCqKFqPSVJ`3Ma&`C^Qp z=D&x<-E(La_wl90-xNJQU(DgX?%TK*-$C9Gm)G}xi2J{B71gAU^B=s33%G)hgKK!Z z@ERHy%XsP5*QBO^RPnhm#6o^qqzl&aBPVB`Lc)B9)Y^4+#+$gh^FETf6#EzMW2b%( zgWCymYi72y1El2`gDi^CtH<#9 z)Tx0)a;#SvpfS@Bm!`xUIO>5*09@{`-@6ff%HiF_9Jl_y5(*_2(=V4Wxrjbpdq4?^ zYvtGT4cOHEr~ybSDYzy1-Lh!zi%pW>n9L*9P$GNIJr96n@edmMc&dvwKJ<>{ird^} zEvhKU)#8N8))pmCO@ppjhS(^fG~k z!Hbd~kQES39fF~MsS5Z`DK$!#L8uXkM^#y^&g6;llUDGp;RY&=GQuc_S7*M0#r_IB zqpOcYqxT!BsFfVz!Pto5r5I;BPf6cmFEQ&$(K&C_rKS3cBu%x@lyG2{06W2gosE6e z_GhfI29d-PNG$@HLn1l*@3h~<&FZ_T7Hh)I*YB)jadiRdi4@D*7x2OO=QwC>V|jiF zC+}Snn*onBYmN`FTwaxfOn zf4B4tQ3|18VGEU{r8J(~D@Pe9uEQTTFv~Z+*2_W-tcf5stgE)<_ zVXfe1jq+Ym@&Qt{6>ze!$whoAVrwX{!0|I~?l1sXl=rjx0lwoNWN9Nh9n{)yH-Niw zobP>`Ktuzgnp0Umi^al<=+rcNk@_-GhdS|@;Jgv}A7Jjm zst{5Z)t~{C+*y3#LI8cUrbS6HE{)4L(LIOF;yQNYE%b9OtoF`|QLYlz1X)>=kA%3> z>|k^^MfXx$2oLK7+}yZ<&n>@*?+yNoq!KUBEP{szUGbhntK7u3(Ju_QFG=xI=3>y* z7ZiOg=T~v7@&S@00iFJZ%T>&v(~yo%Qr z{tn|yJw%-t!>tHkh`ufag0>%eEJ*NQD!qy~KX?uK+0f=pFj#ElN!&r$2r%5~;+gxO z$DvV6c;CHv4NXHlPkR?0S^sHdpOymD7^j3oxwCHghlzkKBc|%+z5DmY^{6^E$KvYd zN(5X4XP;W8+cmgNH!V-@_NQsRZlxcW0J!!4T+ZyKD66eRLyGyGp75iRf!YpS31zyP z(R7~^0>G4Ck5zkUnDMP%O3{}YTrB!Ajz@NdsXulqbkhF zW?*SBda~867zqovDgq_HxNrURUKaLCV!-rYTKQECn4|*7M_z$RI-#Lp+?*Dr0A91d55qYD_uhveY*fILm074*<*bw0UurGdYo{XD} zQ?aTKjowS7uNn^d!{*=N+44)+i*}^S&&k3WYnU=bQc`~VLmbq1&^28Dd~zPm-l4e8 z2><(ge=E|*T)2qkg;m_SwgzVN1{F`d8caXFvvC&>+V}DFg{Kks5|oQ23qJ{QHoSt?-PfKl}}@Hza3MDDe3G|lg+jG1k|w~X5> zA6g{qn~ilC;`Hz=PF2sKn3jdJvRv9TjTdp){0Drs@eTaw!S}QEH@a`dh~x7Cnh(0T zFmn-6V~kV&IV&os6|*k&iF^2H{g04qIvD2vWA9CREXlI`zH7sqe0C4_n1`IZv#P7B znqA_c7TF|4NP<8CS_sglAp#O0K!Co1w9rO?7Fy{OXrZM*hzki4MH0=P)U0ArU6s{U zIYee;#_03x{zfy?{hf2q^BWe=BRnSeY*pPvq`TWQvt!rZJ@fyZYs36~i^9iDJB}Hk zXsBMTbiD#SCivI)f^YfS4eeKzW@Bwhn$d$3NXmf~zeRbwHHwA%V z+S^j0#*{H8!tQV9nxz!?Jupol2U6{4%=ob-K&(PCSQ3mX=z&*iDQ2b(EHVi}H53R_ z8}@}+p#gAGGtJ~PFJ+GpyY9d}@ILZY$!AOTfIx{g#4j&d9xgNh4a|*c4seJ1erp4s z2GCAbp11~C)EZ2zftdgsPEK|NG67%#KobU_0uMJV=5T_Y2Ksz&`BS%;FS^B}W!Em- zZo1=5!2JW4%{Ij103zKx>`O~9%-gM*b=U5C={v|>w{_?~?flGr()-tLer3kZjON^v z-Z!#+*py%Nywx%(WDZvjZ%SoSd$;ZSQ=5_vpef1P_4{tL(D$0Z>&@#s?t?oYxL^F@ z=WgydrzF2UduiHz^^1Eh@#lArXWU_D&&{nb3;hREU%9pBBlr37&t2m;N|*PW?(xo- zZp$Zk{^t_om|AK|Ao9u4BRA>|-Ib+|o1dK*ZTq-0I^c*+K%8prWfz&EU zA3v}8*{p+~(glaI*swK}Y?K*HKATV+JtdM$A-vom(zilJN`Bo!f_iKcW zWCRB?Qq9<>g*BaVxBKqLcmAdOt?YN*weD><;}%?#yl@^mu=w}G4oXDPA5YzL!vk+3 zesR;4ZNGR&4Pk6RQ=jhq-2L{{@4Cy`HEEgMZ}hxV)Dbu}LZr1h<6WgCsgdaRj>LtM z9gesB`JMb>Z?$9&Yv}+EUUaR_hZce+#&a7LV zedv}4SEQf7kE%a))mL7mU!g$Bxi8m0bN4%6x_p>RL(bMh)Aj$ja#J^FB<}NG=Ob4w zdy8mw%N<=FcuS*@Enp1U-CS(=1ym78wL-?m;n!4mZKl+)h z6WWhq>HWh?|B2uhJ{kN(ij7vXtL`_Oza`)!%bxUyC&fVV*4uF$AZDPwyaMm$88+}tn-WaaAfPg^A^`ht$7et z^X6<*>%3uZ>Lx!P{f_&~-Ji%F3%}vM=dS0sMe`Cfkfy2r!P!WI_rRAxz_2^e6pzsV zvwz`cevr$KJD-j|@qYddx4qJJ?NQs^yne%N9&WnD&XU``ci`rm3*u`dh}*+yx1H>` z5329D`=c*ix|Rrth#+I-1=MJ}6amjW`A^^dM{f1tv3u0K@20(&`_lbV{B??qez*KR z_w~V-Zl|&4`d;At?%dyUzcu{>=>#;FEV!knYTct$qt8Do{zy{B|8Dy~atq#ivWA|- zGJd!9Z%cESANBv(eUpCWKF)tzzD|TBN}TG9-GE8yQF~`~@Kmhz<3^`r0lD6~*Ux(O#I{QwLGY??e# zl3`LOk$ehy(DK8OgK z_y2Wkf41r_-SN-7=%hJFRi=^^85|81T%lp^dpmi+sZ)Yv{x3hoWpRe`!vs3dDSHJ>$C;z~GlK+LL|HMsS z_cp`I$ldk=!~6`;}M_BR6Hx|6@>rn@t; zw?Mf(a$oL#?vCzyhMQH4M$s)~4+7Gae4ks#o8Izhxt-x7*G&fQC+&YFrNIcszj^8J zxf_jJ(nnw}(^h2CfO4peyW8K9jz<4p`#+Yf1A{J0YlFw`-Oh*NPSUXCYI;L90+IIH zVf*tet)AL}y1t<6f6q+M2;y&XVbN`EZOWSE{XN)!;8xdH-7i1=h3-sM=!T$IyvDzE zH%j?ITh;c)#K*=_f zjWZN=yuze(X+4-|g2j$ow_~e`5CJgo0-%{_w->pIxB-PQ-xN*vs}pIXC85O_%TG~- znqE${nrs-Fq)$mB?uuY(q`9VK!rpl#38}Q}g}nf)mK*o~E2EsfX?YO>eP#SnumZ3K zKn@}RnnA;x1;9UqY8JL7u%FToFvJ9~1_W=-HeLcA(cN#Z&)jtDN2_kQSxTkeadj*j zoHQp;=YoChlOtEnjNIYg!BgE{Q+ct8yVLkUf?mDRkz4l+`b+m0?(6$syUvmq7>~V0 zaYKFI&Aknm9C_cl({byM*WAskw`BY9_3jhbSe=r1!yo4Vw+P#*1n`IVrSCp*mzS=1 z!80ornTMl2?-F=znhpgtG&P!$Qr%%TkjlNQb2r_mvp;nYpFDD%1#g&d&Wg)2?`U_H zO55)%H!iy$B!u_LrZlS&8J{x}GKAig4YfZ8vyKW&_lHYBC@%*3)Kgz!68bwo5 z$Lt#Q7e_ymUJ320<1RO^1uf=HU~gHn^*RFtBlqI@%sh_s@G-_DHmgq>YF6&f?RNy! z!y=odC!fC$@djK>dJnJ#`-T@3BmaE~T-~3yIJY=P2b#|fb9#hB4!S1Gni?A_I){RA3GXWIEDd~#kKEuUaU z1@I`x;jc<9yGXBGUYeLGNeFrjyNamtFBeSzAZ+-Vg}kUpRew*8$%_m%+)dADt#&Jb zG7`7wea~JuH2QEV46H^2X60`*J{y2i0mwU`@MmvZONS8v$NT>8fd&h$zo66y4E1{6 z6FmUfhmdMPDiHT~)CJ&+fq^AZf*{Kh_x<$Wa?RPcI~pFkueR>G`PQOanYk>_-}8>| z<=M;LpKiEI)n(V3ZhI@HCofk5Tiyhpsb>8B)Uvx7x|Hgmdc8+&k*FQrw zUC8Dmx7~aG8=rRjZdcp|;K<(@{*Eh-O1D{UxSLaV+{W>m>(S{sBZr!JAAHgMX8Aq0 zf4t|u+P^F2KLubP6yKF?$NSz|+U{*hNjM7-GrSqLQ~zr33n>_TcmBii`!}s==5TBs zSaA%)u<}>}vZ+RP5}~IzfMg2%F|4Yqm#?^K?lc6vVfVJKyKxZCDgf&_ z^g5%(X1sIm8EqXi@uf?b#^=P=K%Bl~*t>{@Lku0Z``Y>Ss>XWI&`f_TT(g*f@ag}w z{@=SdIhOv;lsovT*OYs;_RRaIT=0MWk8hOz8y#Li{CxBiY0&9nNW{@8=MPVrf9OLf z9moB5^5>8K@Y!p-lj+;|(dHkW{9);GyJk1K#^9FmIE;Sx*Z%m?pN#+f&j$asTXxsz z;p6}DC8b^zd@P^Q!M~gI+?=-*_K#J2fbXcn{dSL)FbfK6g6sli#Vo*XzZb|+7cmru zV<7ld+wi=C`~*`KQNk`qqCX z#)Z%SS&WK~NrE8^78*=wW+x3cHa0e%I;S3)o;2*7NuQ(rwzjs$3l9y;f)}eQl&i)_ zH%6T5dS*JO9G?Wzu|^(dQNUEpmpOj$!3P&ge^MO5?jKtLu^^g6Z&KiN((}}D783;k z+g+D~(^k^+NB^_ZwZEIXx$m~!{$JMWkh$gL_x8r<*GK!NPO^sL?)cg}RlIg1u zIhB!LVI%=V;jB_J{wy+wuU^$wVl0y7<>iTs`Lq!S?ItZcJ|pkVz+HkSf7{MGu}RFR zqvhhjmOXdO5T`A4qb>X31r1A^uzUCJ2?O4|dGkW)U%7H+oRYNr#vOd)YDdPTU}T+s z{CgcE5epW^GXh}dp2;h&Af=fe!F=*hP@0YP*I=6_lGFB+X| zEtj;aGYf!=oPXsl@N_nOIcJww&mDry^VWOPem;E~T3DN@*e{Nw&@5CIvK8V0k*znp zv@xj*O+09*$#o_GpcnhLR@4(C@apDkoEm$crZc~nIl_GR@85TyefHV6fE>pMf2qIiv5!v zlwUOBEvRg9$GLH10s?Pwnd>C&bDH%~2dEeWGGaeDZVd7~2Ao7EJ{AY*5MJMW^NsuZ z>#xNfVRO!lrXM5r;*?{|=yuOosK&x)674uMQ4e6oR>LdD00?#ofhSE@Jn=8A?ZwxQrRlp?F!9Q`pZydY}*aCAM;%AG0 zuM3G6x&UVx#g_MD{#oD6|LvCaj8C_lln4b1PJkin|NLO$;wv_soBf@p8}$k|*nIIu zjy6usF2uvHx1-Ijo6g&=yxDgPAI`e+uyTXDrKB?#Zq2#!c5l2t{mamQY7TF6{%5dK z(Dv1l*ACOE6umqZ;Y&__oa({@*I?sb4eXE8Q?}shi_I2QY>qnjtTvB*=y-6B0b8uq z6~3=sZ#(Ch#*1mzg-ZO>?mg-E`1vf#&vh`LRnHmoz7GAbzWPe$Vrj#drC(1O8Yn3) z4YvEnDMiMlcO5^Q2{XG-oH4M^UP%DR*4&;EH~;rz*S^$r*>ulM6`3@kpvx`gr0K$B z^Owzn!IqB>PWKNdjTc7O6Qy^w+Lgs0cgH<=aO_sTzo4gu{pm*sgUR>eyU0$`UfUmkB`#V{dZ_crDk&*_xNd;PiM0YlLU6!RX;hjsNet^d082_k;}`RDGV zk3M=O`Z2Bg`{!S5nV8>i$1O%MY3}y7#THHzWX~+otP#o%hbP);>iwoW{_=!jQp{Qw z;kI+V&4J6io}vD*bPMlmn_@P^NKP?j(Te@`myd8gH@Y6*f7bi)YibuyEo;}5h4)WX zG5gbJ)Q9yatH*Ea{GWbEb!W;wue~T-fi<;Y3SFuKZYAzE@+`7MRyXA6UV?2h@dK2`S z->cHMd&HZZTAOsU6zW+3qhtPkoF+^MXl~9k0-!b3aP9AFXWQ-n=g1|6 z_xrBrvI*wy7ZIYwKaX^ZqO{bj=h3cT*n2~lwNkhL4UHF7+q~*{spz`Ak(1|2MC*4& z0E~|PiyW5D+<&z1&fR@)PE5Ydw`Kk>8WPW-(lK#Qm268(>}@JMPrLAG=ASg;0FqpC zN~&wpb+)h!%|`J~-9j)EH}=2l=5DODj0q<_V|>meKRsUbu~{FN%)So&xX30xepdSN zeeD_Q8HVSLxFp(s#%8}+Ua?TO`%BEBe#67B`!1Pkxz>lN_^X$HFz+uMxD+?>i)SCe z0&AGIyLS)N^cp?{uAy5q7xeRr!T409TPT-5xtwr7mq zOD6y8>%%LD(Qct;ekg^0l~HF{#v~>flZ_UgExdRiyLgyY5o^Lp3>YugNuwV0ivPtX zZj7OinQu~c+{@C(wLzwxsN+8U-4$o z7nEuG8wIFqbA=s7`s2>7OFx+P=J&B|pIsjk@H$1SzRY;l==#_^MJvvDEx1>@!>uFN zn9X#rzNC~!naT9CG%tGo)E`u}Sl%m*%(-YUm$TEaEwo8F<)`9kO|NuhfBLwyYcp$k26!>d^;HmfuM=G#Pp)#ZC0XVfotk}i z&0!pD9jbdU!7P6p^H1BMa_dD}U3wRI`t4M=2dfWT4=*Vg&P?Au%jB`CdRofQ&a0cr zc5bX`>~A~I7U)?9EZ({zhGt!P)0kZe1r&kiA$Wy76AHP4EvIyz05Z}Ukh=WL`ofwlg>$G7)AV#i< zX&FIi<34pp=d{Id8gr6aUe~U5e|wUUsGnc|_pg`{0QIfGpGQBY zC9U}bBCzg8oHpvU3X=pvOgqMSFyxzs@v72)f%~cJ_J(fiR@3c2I&!1I$gO;|S-1XYly<=Pmk4?Z)Z?U=n=-d=DQ!90Pm^^jY6O zH2?bgx)e3p_FNQFAp|&%E5LPF2QQ)@Gq43E<2GV18gUCSdj}Tav(84Rr7@qz0YGcP zOY45_`dcGcwF)uG*Z$2J7XM2i@D4sX!P;B>zz@4zE1_H$k7_U8ZE9 z?b+#ggSkK28_C?0R_$6U7KhIQeO_nSKJ>8`e-ZQBar>+u{Hn(Z;`Y^bCN%5AvIoX+ zlg5jlD>lFFXKaesgMW4UFgM^HLkMExBLpnRZgm4-`)}R4B`yI>Pk|JmD$chSUyKJ2 z9=L1Qu02EFe0Zz>w>=N6OVMdUpw85BLlK)xTw@TA7~GXtp+wY7>#`MIcvzR&vi>AG zUv?|E`{R?&6&&k58VN||tOz`*cMSvPuhXv&i>}*dA$l|SMi#y-fHThjZP9<`SThRh z0ND)zPrk$PI*)SyxGUA@%}9Yd*1T?BPcpO5>QmeOVGy)yEEJ4J{hwVkX-u*JCLN3a zjx}TbnmTO|eldNtIu(qV{4l5O7=-4xNW8S!4)2Xp=hf9!xj)sD%zG03_+8blg?d15 z(%fG(>R68Y`^qN;)TZvV+~}ZigKcF7_Mc1E8ZNyuboo>!;F``{TUundE@xfNL#9$`Ctgj6n4bm3r#ExsxWt>J|2Btw=g{w@VjZySlJs$WL(I=G zX02oX8Fe9050Xt+h_cW^@_NU|Y*vrs|;q4#V-umkE zk7Jnrl=|Ac<34Eo_}xvSKj~TH=b7~0>(BkXaato08xx~DY!=aeuj$HnO1J;Xu^Vh@ zYvs_ww)QPi2@ zW#|*&!ves>Cl^#^=Pz2c@x5Or zRTk5$|9e^bFe^n=e2!Z{V~^9G<$3huNKuh~+he6Rv^HS!fKk~=BsoVO~!!slBUVb)? zu9QxgAe05a2^8P!(0}12Cgnq$uh;5H@GA5JuHa?pKQGuP_k0e6KQ9truYhC3TDLA3 zCf(P5pA>gEZA@ZhyY^M-Q`u+F&p%=WuR_0Wg~U<)y174T{%0MNpvsJ#-FV7f{~~4+ zH~ntQbyk{g>yMAz(OS<<9nQO!XYRr?IcaD%`aE3iy1CoalD8i8hORZ;boq@^;sK+F zPRwJGVC1y()E(^}%fd}tXRjoCnejGId~a+dZX8blT=X{P|GWXsGQ}S|M1WyUuJIUuTM*_{MkEG?&!XPc)E|&$EO9=@q?aQ z{0&9G(9oha6!Y4ch|il8JgeXTRq0!5kU(GkoxUu6 zn}=ZlY~R58ye8fMMI#pIF;>8aP(cV3-lW|4qkYltQ!8!Pxz==5r*I3`=H0>Op&NSB zd2l%L7Qm4N`SNz=hDRfJwAyoh@8hHSli(RxYKk;gV=;Auts>g<@69g$i$?KH8VEg@ z?>y#zDt+j%k7KTQ0V6w!z8wSG&H&-|A`nVFEjVeB8}ru#Uh(yO4m}3JG>+NsInQg$ zJ)Ub6T#FgQ7Q1ao!aXg|&LEJ-d9O-8HrZc?e%$4U^AG~30f;93tbb22!`pMj_o}-Z z;~-$Rf-B&yf%`|IwK~f!SA+oH)clk?7#_&JT@n-U7xoW&?(p%kG^P}gO!OSQho(2X zi39Y$4nAM`b{77Hqxh_fFIp$W9GaJ3asEjVptUsPsjbQ<&_~)d7jjqhy+%KNapxgx z2?jIJ+#)tJ>r7oYMeSHUP&mnljjyGR7WBxE8>7K2wtI~+kTJ|@y%vkn;aK_;(LmAZM@F>^O?*Q z-KUwBK%Tl%69m91^auC-d&t7~^Bg70LLi!r5P%sBx@!x?7@^)XKh`qwyxNip1LfnJ9mN6vr_D8$y>~mTxb)tp_`5k}PT;dGV#a8Q(pa(0=O$@rR+; z#8oTN-F}l7Yrg4)DG@62@SN`XCZEc6lSi+~&#FDgD83OI*H7-!`O>%Xvh(lEwq>tB zspt29Q^gq57epY6==4r#PYpK1tU5;j`RB&W8iRG>ion>+u3r=TuyJeadY<24sVwOD zdh0UGKhw5W6myz}jmIQQBxVp8jr+!X58B3@hSz^p`e^d^-h1!0=+^~ky}v@8{v<7L z*VW?{b&I0DY3W!1tp9S`Ext47_BQr4S3h65{Wb6R4~FiQhHMgi_RthJ8jd%l4`wYg2gJRDc^|sxUG_ajx{rPMzFy%$lk81+r0x0`V zVn9+|Sj6<}X}&nkX_kZuUjsdj1pooOoiFy?%oVQ*`-6f!XaSDjZ$0WP^3DRM$cE1l zLNJ3ZP?+SjYCs$DrW!H*I7)6^dk|V|&jk(UY;Ma%(l;QIZADhkB-CAi`geJnfVN?7 z4DUVe?_id}$=%6QpSHggAGiF?4&Km)brT8vn*NLE54)o`p2B3oSxU+l2uxv3E$TVv zSP;}LggCD~$sa}t)B{yteDQ_k(-AnfKcShc3>f7sb2u$9#`T!qFaQyG5PWEP{)Qnh zn!de@*e_>H!cWBS*Zz)k`;+hiX70y*78q96od0*%{@%%#3t}(TvbRy;eG#NTrUT}i zIGtWvC73FhNQr+*_)nw-y?H8-Q>14zXpK_p{T+*d8}r4NUNcyrjYDXX-e0(xDerGK zym{-z(Qs6`<8I|Pw!J3ue($vZjAP6@3v-|9FmWeAuHAhv#r$#3BY2twz|F%aBR4;r z`G1K!?p1DYzjTM*e{MHZ*J^N&)NSw4cRdmMJb#*0uGvW4+UCd|9#w93IvLa7J1E`d zOPM@7!WzM!`=3wN3U}v5?p8Mnd9FOy`#)NHmcF$okTu^31Hm8u=LEEcpt8k1wJ>I3RB=VP5a~fhlM*h^nSY+BrwVFNhM5lX(@Nz zUg?$=GMUe;|NO`chfdow-%uNIz<4n5tY_Ayr*+&N$T^3HmAiQ@m*czpg}+zk9_~dE&GhT2Z6f1wu`X;C{|2{9JBD8pa%>{bedHPK^)=n&b^XqM4z6l0kp?&bd z2SSH`SQltPvkoTF$0w)UHuisChdvBwn)odA(f(KjZ;Czw<}~{DIkfo<;edO@{NoY3 zRHroxwR0wY4qTb{YQogOMqUV4!uVMLtyjX}2!)J0$?vIG6;?T-+U z&snvJXZT7HaDo#ky#z-PV9u1IalW(kzjH?{2NrJ9@{7|G9(YZOFgQHafY*xGxLZS z?m!sTQ*jIPnY+AvLZ7+MOnb&Z4A517UaPI|oLAjyJGbZOEyCbf=Ll{7m6e%zSOt~q z`)5W__^-j=`&s&(R_12rQek`qQ99Nl+G(gLDtS+=Zx$nq4Z+W%psEe#hbhb#ex1R6 zS$N#nKrhg<$~Rn%m_8Ol95{Ou^v&n~Hqu8Z7!Co;!v;d&EU}}r3==lCgAu|80mt9D z;*LYX2C18>loV7EHkJ_6t4j5cDhV4-q#-vR0zgQTkaVVxpGqRt)FZ!2G5b?l!~s;2 zRPuY`g~-kxi;^8wz3B`jnZ=nWVyPT$rNgg#cO) zIb`pIALEAq+)&_!Q4&m0U)O9G;#lm_j!|yBv z%T=Q#&=5v0Qm3=$Sw;?$WgD>c7arB#uR0YFuW#x6p2OX`{lDV;)E zd`U;^DlFWh3P{yz+)@k1XVL3%Wikgc&Vsy691LxoJW-?~{(t=;;hid(_yx%=Dm5G16 z_sDAk5jNgm>zA&(TZ&bZdyV{XeI!Cjp09G^qHqq{TEZPe^|?F#ew|h&mWa{cKU8bu z`qhRAG~x-}z88RAAYfS-eco6){@&Fc7Q;EDTU1>CuFM}8+AX1R72qM;CB3`UGK zcoX!Ejz#uOGha0QiypZJ6)WM+O#F4>U(EN629>NJOn)__ZGn!;MBIZcMBS<+RqzQF zfI*aqIKgyv0oTlZB{txHdd6c>u3S2if(Kq}q9M^xpy4w7T$s>nRMCU!<%tL2Eg<7eY1W72MT4To8uCi*f4BW3tIH=2@_*yf@?6|fu}juP9(Olv8kGUb9*TF zUYhp|e^iL2ad{bkJ{4hAY*!KwU>YC4-w+d=$a||%ioZQS>)h85hw>gaz1F{e1=wfm zU5rXH1w0!J4dd~1x}8X%4`G89c6?k3eamFPtgOE|&*YQnbF3wTu@tla#P97k0V@DE0XdA&;j7r*J;9Hg1~O1ejPZY+VOw6C28_3@Hf?wj^kI5S zQC>8COOKw{fG!P8iOb|g6>3RI|D|Z(hA_Y7`XyAZuD+Q35+W2gJ;V-@EbMP*3pX%% zrT(=j{!BH#U;?B)j+1MNFA%IEzz2hn#=;MVvCyDsFc=E0hyOn}o5^+f@=J@UFetYr zIEbd*!h%>)zkh2-bN*M~&4h8VFs53naS;NT%?O1r?+=7AGe5!I<3cn(^ndY1UzmtY z!>4zL!qknxpyEq6RrnAvgmFpl9eGRR-CMc)^h>n@B%{zKW>E-^pwmi){&1veKCBPu zUtRI$V4jNL@p?i6iT583WWJN=6PQNOnfpeR|I%V6c!PIt=I--*BZp<#@f7pl3OSpk*!s~W&l(|#mr!AczgQT=7G_W9#vdn>^JiBnpM_7^WC zfN#*4nC9wtsWmY>or#&xb(%AG!W`2b4Q>&<`|PWMTlS3B^h|+v+}?vZ)pwqq;rvXZ z`P_$N3d$)Yjn*Bc;;SF}$_zznuoSv+!HE`7nsXcE!b-X~LpCW`1Dr6`y+54V;sfm=Q=-<4mxP);q zwhF)}k;s*#1bP3Ly(Iz=3ihya5 zoJ$B1?^E{%rT6=DclX{v=FW2=j8yZd?&b}(Z0>$DkboXRNdyEz&IgZ&VtL>W@ZEqj z;I+r}hmxB;`66u%@hlb>!GZ#bSf`KAKRvBNgWGfkbMe;K+NtBTeFDyN{HoHA>o@X* zZWT!`a8#Oj>P|T)nqPFe`1M)P>^U?4J7gd70MqS|{Kl%z)K$=Uup&duDdZ;m8Y z$7g8Ry^(58nE29yXQDj~vXvp&Df9LJv3qxxSMuBz6daATpod@|bO~f)3EaAti=}}; z;`vBHl1(xCfPG^6^WLAob|n)bGqmT=!)r~P2$x`3Ia@zEZ`JUeyR?Yg^DOkc~Fl-nJbt zA+iTa71DyG!h?%|39t?J@c#>KUA5LPJVO>zm@_v+C7Ze!RN_g+TEx&2lv~$gBFyZ= zN+atC1?GYOoTuRL3kiM^RnJ5qDF_J$=IJRKBCQ5;u={8v*8=Y))4)GW@>|z4W$40* zJ7SPtiGWlJ_!;s!ZpfUvCI}1ynmj6?B%uDdCS)zpz63A@x8G68kFeX=noOT_xDU^) zH5ZDikhrVt9<0n>2CYwu6u})MO0jY%LaNipiU8hm*gb#q*tFh@nti@)`WH1Wnm!}8 zzVf`$^yd6X^XVyd!?`dgDZ!%D;GSq#zp%?7wW%E#4hN!vn$3n3_ee@mP-L_OFN6U` zQgovlsUhZfUs8gNj2>yk3vw~pmlvC2mSdJ$!3#)3Ok}hl_;$4A;(YGzKOPEmAizv3 zf)_BqoWGPk}P_CQ0C+mf{30N(>tJXp$RtADDrVsP4TuP;u zp<`vwiKaUxb($JpLxY9l4h%G{7q6`(2nMW^_utLj-Fu^n^e=K;Br{y33vki&p9%s> znQxwInQcb(S6c*u6z~Z1Yq5^NeSrp7r4;-i!HZ(381yQ4X|CxkY4zl+lWd~cf6&CE zzH4Xg0NO!tw8Xatl_uu$K!GiMhGs)!!(7UcEaXHq8K%GF(nB>I3mjp=Aizf@9sgks z@YrMrxR*{^4IB`6Xls}pS3s;3PltQM==UFw+=uTpL?|KU5KL0y41Qjan;KIfe$Z^F zx!uULt|60vp4QrP74-;@R<$IT=>Pk-wYrQn9U7U}#{Cg$CUEXQD%^+f=3{f-B`0AS z=r@}x2-L+ik2fz}jDrcoU9IaBV7L;_KEWBV1c%hNy4P{!&ZF4opT~&y%NcCi`3>=jb zxh@JV1=fB5ikT;ZK0W0^fDx^(&MrPS3mxr9@C-&Fx{t5j3mS}N44fFsNp4`X4TW9D2-?Z-B*6sN3$y1^KOjLh%$Ph=qrWP~ zjX@GjoN6d$u#^awiX@cgmU1^`hPD?bhh43kht}b-b36M(xi=;{i@G^V#KfMRO{F%U zwq*za%x}dCs4(Cfu=Q0~*ZBVw1MMCvj-I#x!A8@ZxC^A?9u?|Z;CE91WGFmLcP-XQ zg%LsfVXc70$7(=efJnsO-#;>wipC$Bp#Y*x5bpDPT2Y42ji93x89{;okW%PoC3C?F z(vC*eQ}o-dT%Om=eqsK~>MfpSevWl}>K;(Zc=sE9pU@|6LHz@k#nJJ_#sGdjE^drB z2h~(ks6ZQ0tibA5pT7)Q0BP_Om|ss1AfGfDJD-^QH29F8)ky4yGHj?})q%D~wM$SX z7y}j|2)j+`B!)2?GfvQQbbi&x zI16By{i2|A&qzvqD?tR5((X$bI#m>(R`n9~%TySY*7+w5X|__JXjQ2H*F<$_>}b(z z4wXr$KdQt$|IYg@x8cp@qpnu}0Zu|N0F~8}TkRXzY-qY{G}LxojXZQ63dJ>OT&xXp z>fD!N8yFU?5A#n?YxG_r#eVWlt&GD8poU;$Yv^fe@C{9Uc_o!bqQh`M1j(?dguxLI z5+qGRGt;347NN(vG&Kd>gP%{VL5g*{3VK?l{5VTQ8}ml+$$MfQ1jw_~z~Yt5C-jMl zm@9DF;63c^W0@4*B{`vwV4?Y_eAAUOKVQU(Kla7?uVVneieuaqRDmRg0D6*A6W!zG zkd#5o1kLZXOYk@=Ko^0~c9?tUmNkk5tj5Jc$+&_*?olP7*a-8z&>|oI-=zhj@(NOc z`Oxs|n;JBPv3K?hDHuvZlgv@r_g*^aX4>dN>h}HdVTg`j@#mw}jj1FqFw*RXbo$-U zo&Y>1@Zo+xl>ppOKsk*-TT6doK4Jh;|KCcaph(J(Ls>FRbsU%##se-)vlFZkPI~aA86-c>p3_#qx69mL&LCK z5~xizkV(wpqQtP01Q)!;#~nlC`29EJwWE6T@; zL{Mu|q+<`0SmB?V=$g~7B!veCK!k!*JbN{3hlBmqXE>AW9RP!%=?f!!z9Lf1kW#f6qHUi`;3~_1i*;acZmV`YtW8F-G>1; zfaZpIxPE$Car<-yrZyi_9cCQRsPmG}@A676a9ytb`r$~Md3vFA_v?{F(=omAx$)!Y zyhk-HEy@%3aCIp6T-zM_&r@xRS~+R{kq4J$##NFrPz;p{m?Y#m1t8>~b#AsHu;rLO zf@fnZk$Qoc{*?4SNJ9OCqA(?$Ijv1d(jb_42MCX;sgs?3u3x_{ExPKv%${W-J#X0V zHZTASo>o+J!+G@R(YWg_3`cVe+br{K(PyqOJAc!S$UeVF`i%2#3C8^R9;8*7n(oT3 zNxEIxhOk$_%A)S* zBYw4CtXtcKXt3GYM1;WB=13SAW~OH!Kpg?}^fh=!u6t!U7Y3rBhxPpMiPqNRFL(Qz z@*<*7P?02u6ao#j67VYixfc%Yj?zbP%+2PZYY$qp5P$x-n+i0Vxd=kg(f3a~9gu27 z>(c_Py{#!r1P(n1hGB;uf|;BL{W(9ktzCWIxe(Zs^5Q~EkFhvZxT>E%D-4`U`j3Jp z*|f#aH>PiM!p!G$T&7l2Q;hP)OAV&VV$2c|dX#_D2$aU0H0r!@Anlo!5G#U)0%U>4f?kIH^S%JL?0nYOR)140@f0YJt1J~gjI5qQcQHG9++=y zTQT&DA!2`Y>_qdbP*F4=n#)Rg@vn*M(?<}dg~@RfXbpyTHwF@@E(`up`xwm^UV{&{ z^f(Iv3fzW`O~vzHU1^Hj@x)sjME7M2uw4CTo{OTIMuYO*~wY>sM026Og~3 zolc|wE-FDd*kdD9> z{WnwC=yM;K0xJO~dDHX}Krs5Zjs8W9*lNiuLF!pvUmh)l0KAqi6_j6A191V+_Gzd{ zD+1hAZW8tYR1i@TFaeqgNJGF+lxM1bKUc~1Nr>1Vha#8YDp1`=J8)WHEd;2rwEa#~ zi5YMXT90Zx0)0ftc~r`2p@XlDz!223zdx=6z48zYM{K9nNy0W@%G}VG*g_Ci2pY7$ z>==|Oif`xZfe0SJKirdmCA8QB5RES7!=dx=kj_B2a%~9WpOJh#X*k>wY2rD@i_XLX zpiqczLXD70Y_&84(jRK19xI1tEt|WO>91{#B>TZ!1!d_JP{c799>K(SGS$)j6}T25 zljoU$h0r`OrkSN^Da=$X16d8H)U4azld$adbFCM?_1I(KqkWc^mSksMYmjN(a&6hZA+-7tz2`%a2w{ zWW$ikX;x3Qj$i;po>U=zp!))-J5foAt}N3^wGjd_X*y}{fxpV)RL!m0o~%F_9;ww- zSS))1+TMCBY>I^VX-q@_5ObFtIPL=NzUU2zFcD;8q4oG$Y@{v%Sp)7lJEMg}Fz#3P z6^O*|%&j9((t13~}!`V~}|F-+24#_;Xv(c0Fb;Rt3z(@#W=Z5eVz+>%wd?eU7t%NSdZ^ zj6MU`!|1aM55HsepqcCRc_!NgU9J9GJDkTrCZo!^j~1(o!M6=7tP+cA-JMQiFvq2!v5th~`E+ zkIE`&`LLgzAObZYpl!btJ5YrEFz^zs|y>QgP11r9u&1)!0W zuDLMG40`~2AwXjd%wM|kYI?2`bRGk3uD~PB91u+0+zs28l*u?qNU;u#ML-Vl&R(G3 z2-}I#>g&Vzn*O|jH|?8pFVb#;GW72eEzjiIp+_ISHp0v3@AjPZKM-r7tj1-~2n>V+ z-G&I-$yQ%OHTAg{kY3(1v5Y%68{Vp56VP065C}ztAnwlIp{6Al7wDzv-1ekoIR~w57C?Q(rmZo|X`eCpj%~MHG%eNuObQL#FYi3*!`yrh z&C}>VZ`YnW4et3O`nCnxB>J`kQQR`zwkVGow=VcN*MwcY!KyaHdHNVF!14Q`#dWq7 zSx!Aa7yv*yFs_uohW-5j{0L|#$#qjtQh!M%0l%TQ-E*V}LSWc;!%*Fq7GYQ5P^@DD zszDlLG?1-`GJpMGq^+pgiK#y*!Y)1OxbjW{V6x?x2F1{ZWDD5!*0KXqd+$%4&Qr-= zTw2V9VXy|sm*aDzAsYcMj6mU$5jN}nLIjFM(V-7h5U*; z_Oz%NY&X><(oHu~Z{9lzT5@0Lqk*S0rH>FnQ=`#oYO4JV6z~LnVSIh1^2`#1BpcGy za%s|c+*`CrI}>+E(S(}j!$(@PM+_;^)&5pX}!gv2;VBhnzW*AHEZ2deGR2xbb$ z{%P!|PFmomwNCq-b;N=;7l4HbquIhXZF^qy5kO{&e;epaDlX5*=|bmJXq?tCrQT4b zZUNLShWKyZeceLI?{9ohb}RkpqmSgKyZ(2i4<;L56n+Z-KK$^*aq8f~g9mQ=V0#?Z zga{MMs!Yr~Cj8T%{!}Ened*u*?swgizt8IGs$1LM9`D(H_n&;~y8fIY=9|}`o8D%h z^zD?M3RUNIQ9pK!m;3@mt6x8^hQZP`2v{L~X+bCWLSi$?F$sE~p{zHBXqY;?U}7lYUc zj+L;@1ieeL>=)$c`$r-edj7Nhz^F(59I^|r%96Jl@>Cn0VkB>Q`R_n2egE5$PncxUe@1w53p3B@ zf?xIw)28Mi?2EFCDabSW^I^3A;=lQC$AKx{`3LXamVn=Apu#N;?S5O0OkJ_Uc2qbK zG`KxknvMNJIiqsAg@a2%XJ+CTXpd52IQ-Y^58Y3G`U~%(r~o()jLZDzy*qWar43#X z&NErCp8RKZ5G)6cP8oXo$iDW|8l2Q$Ce z6pJASS*UzwJNL5wz%JO<+kA({K=v*y)?oMHTGp#+LbLXM73te~T$c+I`h|#u;RH+z z%zqdZa0pC`i2;Lu_0?A*Ecly;=0On%SPSM0aZ`>#lyk@{b5HJXfru}^{LLzbw7XP>EbcVQPGTo5#YOGD69D>0q83#shg zf*{alEx}I}fYynnQA!%MlmMzET0&h%AweTrg15cp(Q}X2Hr(3!_SlNq87X6*=lrLF zZ_VPiK$i~m;bP#KFe|_FkO%;NA`E`~;~xv7V<}iZ7b%3chY*ZyKL6djcZCQHkM)3{Fgmyr z7GFRpOnYs!=NTT8e9mhPH2P()f%*H$YaBEWnq;P-mcXoM>=uH`KNlGU;sQ(l9_;OR z%`foJ_71&;&=MiRHCfVh8{Q3=^A-V?Kt{=~f6)jP+zJx_Fu;Omw4T4;^=2+w43m~Z zA{IO5Y(Hpw{$3*G7_5U!{ur*sO@F^%c+Gg#U*7`njqBp?yzc2OIyHwEr}Q)49eHpv zFl18Lqp_JeC8^MnX)Ftng zdvXoT!#jy#zjnQyf6??!gEQU+eTG>MTo3=EpqVeco?8IIOmdj=_U+qpjNk><0fe{+ zfxtt;#KZwC00=?;@c@_}NEapz^IQ5uOmy$}@_-EJU`e#r)jfdu(b}CX6*CsIK20>0 zcGdfvQ-XgTxeag1Pm@L|E3p6w=y6@QP)W+~kB+;-+z0-%p%)UneQi^=;Dx}pzn;J% z3vf`B;~?EfUg+S6pqbEG+umwuQnu@Vzu}(^bC-u%#eKm4lEq(24}Y}ePNC^dOy>KZ z-er7d;uZej#!!8H+z9_B{O1Gro8ilL*4|sPFsY=A+9`$GFPhIlT1^eDgi7n zu6flmxEq-Ig~SX}2^}<>+Uo7N>$U%rP1p4Tk!{nmV21Oo^I3YX^Is5PgBveio2U7x zX4djMYs-$ahFI8^3S(`>5qy5PSe0S>jR7sLWq~z2c9Hbq5$M=wM#p&OP11)ZO4^jR zq$s%%27nnc_YDAoKtPilG7M?K4G;oMfX^XfQpU_0?t^B72*oAhXZYh>k2`?yFjyr2 zx}F(f$Q=S2L^3foF(WZ?DuuY>zwh{CFf>aR|D6CH49xk%stQ>I6&M;QJn@+YaO6KY z_KSL-jZ9q#6oz6YUgT%pzWCH=K7<2iYEfxBvkiY846$3N$qW2|#osR#M=%WM1+=pS z%3u(Qwma>*g7(Ar?UlN(!MG461o?_k%1kOX$%2W`u1$GE(yto%*S!}NWm&lZ-IT~b z0mC97G2Ix0>4GL11z!+^Wna$CWPa)z5!73C?p)_zL{V?npk-oW-`Aqr7O0IOx|UXR zVUBU|HvWteZ_RBnuIgJxpPzQ@ZP7Pt!|p4YFSHO$&p%8LqW1XtFfSLt%-oRUTx{kF zg(C*&U~n!%ffvcOSPuN-zN7{%Q^0wKyOtt|LiY$%@Q`YD%-JpyE)*!tH$u-r=OoB< zBr$=+&9|H0V({iru4d(qU&tC4NW9h1(nUJb7(>fbcz0$>{Ne4vPy|Ig1TjTO`OimT zF?0Q~fRyyP=3oW_bA=1RGJijR&Lyu|5mZF9F_kw%5RlLAcngF%9F@u(g`ebYG8vu$ zR{Q!zi1n2ZB@@v1Laykvp8|X&L0h9!Ss9k2hwtF zdU{F%tH)g;$wLtWBD@oYQlIDi^AOH7^qwt9b1&mES=+ih&d!(_Y>{mXl39cug<}k7 zDPE3oo+0ooC;wNSKKHiR!Sm?D-xi!Vt0T8+B=aE{Fe|62)xPmqLRl1rYsSG_+;ux=_~sW16s zdm$2!6+obT&1>$RgCqC7rFn1u=k6OnmmAGa2pno<-a_KdqG93I2v8ygiy{;~xp6S% zZ_G|fFwCOp*S)*&b#EYxcsevVA^N=?0%r60asKB6|2$ixp8KJ{{@twUzVK%DJMET4 z#2cw*3^EXUo>8|v?R~6}pbeyzTAoM^g;*&(*GOB9A*h;QcAajuhSnCa56>+bf>i!) zw7jq9(y&Kh*miwXgruNa2Q&0rcWUWWp*2t$5S)zfd%*~$^PK--2n@z``R0q8Tglon zkPd_O6#L7Z#~S1q)+Nkhta7E5* z`~UzE+L0*#B{tY>H6)((cHBI-%Ub|6K5&ZTROx({aA{>bwt}`9-cKFLbv2aZ+P2msDQ{v&}SmQK~zm z#aWr8{mQ%y%>&HxDV-oX^8C+{7Jm;gRSc{fdH#3^!cCEg@>RUk{#^oNS zjQD9#=(Ex{7vg#JE$$H0&&?OLTp$-?Q7QNb%}&Ih9R2mFwl^ztVOoR$DL=G!o+x?^fpOVu8Lr{lS;_gQ z0{Xe^&FC9b9e@7FEj8Ps@sCG(Pm3+2;pK_h8~i2AS5_(u{EinM1gY?ip-*58{6HfB zlvcbzA~3e)&mC51#!N5=U;}RWdA;i`6-?+Ae|*C~$05i?e+;u1MqA8J1P{egXk*z= z0cK&}#8Dxddo-ZWLO%Y|lF(Q|_67{8!$~-BS7}>!(uvZuF-U;Y_Iq$Ag&_?5_4A%T zuEsa+1lw+rYLpD?jr9UkSz601Cd+YK^q#*hg>9fS7@G4{d0JebaVPIy20E98yxe0Lq^EWsTf`ER=Wg{p! zjtRnXZhr0BHO(;wd^2Vd@L|hA^71SP`-7zgf#|X@@!w$xa>#cN4o}ik_^(onpeF8Y z@c97@wLwNn9y)b%$oq9$P}G1CHJ~$`dG#m8?(3&_rhI{>lG%^H&m%v+D0E2eG+~1{muNB zEC2yJQW0i;*u>0q=N~u5BqBX%z#)!VA%#gZD~-eo;5ZVLVHHtU1CEffR0vvInpqI3 z^oy1B9g%v>_YoEd;2rM<@Q*@@S7#12~=3b!NVDkOJNbZj%KnhTx zsb%$4B$|OwiobiUnM=f*-}{)ue!*@~x;j!m1oejI`zX=8J&Sv<(ENC})O#YpxF1n+ z7CNpAKR5g{toSdCd(W9ECLFA;0GhuDnqCC~nNRh(T>$>rD1yLHNiMoycUwx-9nh$- zY7DRj3J@x!h)Yw7iFIjlkGwF(%RJBd55v1>U0J@IHDj99EHkrAO+#DI*4$E#qfA&! zalk7E`Iza9Mny@*Yxdhf-=M&!(T{`gMjwogx#ef2kA-0OwSZ%8+88a(O{J(O02MGB zi0mWLi29qUfpo%3fSC~<1}uPpX?+WHSScnGg_flN&1WL|-4Z;%HWnpSHwp`zoc?sC zh`tkaU?l-S79R*df#x>UB4`pk^Pl4`un2n~(lQOA3F?j)R_J~5093I7%oU-rFJ`S2 zExVaC6aN?OwiAvM83!=K{r5vKkvzB{->_l?Q(p=iu3O@AgqCSyN^7@XBIYN>MIri2 zPIoXIYi|OA&7>i1)AZcb#h$yM|3fZVKtKZhRe^F+ETq9j_H~q)fVFcE%xB`{P$1OR zxz3;SQ4g__FzC1mHWMHTwrS5h_j`Tn8q-WxQS4HmH!#Q1B!(`iXyi>NE|99r5{AZQB z=LObPFK}4oq|b0uo=9La5nmc6K@-k<`}qb1`UKVjLw@W{?SbcpnUG@_Gd`d&Wn-3M z-wnq760NCfqUpLM`2XV&X4tVfvj|^er^wz5+UHUI2Z08Q^Ph$$E$VyQ7HUg*9x@~6 zH-Fy!&%(PmlpDiR·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 m14-}S`skTl&cMLneE1(^FfMcz0-ikp0000 + + + + + + +

+ + +
+ + +
+ + + + \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState.json b/maps/tests/Metadata/getGameState.json new file mode 100644 index 00000000..a005ee8a --- /dev/null +++ b/maps/tests/Metadata/getGameState.json @@ -0,0 +1,279 @@ +{ "compressionlevel":-1, + "editorsettings": + { + "export": + { + "target":"." + } + }, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"getGameState.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":8, + "name":"exit", + "opacity":1, + "properties":[ + { + "name":"exitUrl", + "type":"string", + "value":"getGameState2.json#HereYouAppear" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":218.263975699515, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Start the test : \nWalk on the grass, an iframe open.\n\nTest : \nClick on the 'nickname' button.\nResult : \nYour nickname appears.\n\nTest : \nClick on the 'roomID' button.\nResult : \nAn ID appears.\n\nTest : \nClick on the 'UUID' button.\nResult : \nAn ID appears.\n\nFinally : \nWalk on the red tiles to continue the testing.\n\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":14.750638909983, + "y":101.908376657515 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":9, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState2.html b/maps/tests/Metadata/getGameState2.html new file mode 100644 index 00000000..e8529617 --- /dev/null +++ b/maps/tests/Metadata/getGameState2.html @@ -0,0 +1,40 @@ + + + + + + + +
+ + +
+ + +
+ + + + \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState2.json b/maps/tests/Metadata/getGameState2.json new file mode 100644 index 00000000..04127918 --- /dev/null +++ b/maps/tests/Metadata/getGameState2.json @@ -0,0 +1,273 @@ +{ "compressionlevel":-1, + "editorsettings": + { + "export": + { + "target":"." + } + }, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":9, + "name":"HereYouAppear", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"getGameState2.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":200.31900227817, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Start the test : \nWalk on the grass, an iframe open.\n\nTest : \nClick on the 'startLayer' button.\nResult : \nThe name of the layer where you start appears. (only work when the start layer is not 'start')\n\nTest : \nClick on the 'mapUrl' button.\nResult : \nThe url of the JSON file of the map is displayed in the console.log().\n\nTest : \nClick on the 'Map' button.\nResult : \nThe JSON file map appears.\n\n\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":14.750638909983, + "y":119.85335007886 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":10, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/playerMove.html b/maps/tests/Metadata/playerMove.html new file mode 100644 index 00000000..3fecf576 --- /dev/null +++ b/maps/tests/Metadata/playerMove.html @@ -0,0 +1,12 @@ + + + + + + +
+ + + \ No newline at end of file diff --git a/maps/tests/Metadata/playerMove.json b/maps/tests/Metadata/playerMove.json new file mode 100644 index 00000000..db590b05 --- /dev/null +++ b/maps/tests/Metadata/playerMove.json @@ -0,0 +1,254 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"playerMove.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":159.195104854255, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass, an iframe open.\nResult : \nIf you move on the grass, your movement will be displayed in the console.log(). \nYour movement appears according to the following rules : \n - When you stop (the moving attribute will be false)\n - When you change direction (the direction attribute will change value)\n - Every 200ms if you keep moving in the same direction.\n\nMovement are represented by the following attributes : \n - moving : if you are moving or not.\n - direction : the direction where you are moving into\n - X and Y coordinates : Place of your character in the room.\n\n\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":14.750638909983, + "y":160.977247502775 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":10, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/script.js b/maps/tests/Metadata/script.js deleted file mode 100644 index c857d783..00000000 --- a/maps/tests/Metadata/script.js +++ /dev/null @@ -1,9 +0,0 @@ - - -/*WA.getMapUrl().then((map) => {console.log('mapUrl : ', map)}); -WA.getUuid().then((uuid) => {console.log('Uuid : ',uuid)}); -WA.getRoomId().then((roomId) => console.log('roomID : ',roomId));*/ - -//WA.onPlayerMove(console.log); -WA.setProperty('metadata', 'openWebsite', 'https://fr.wikipedia.org/'); -WA.getDataLayer().then((data) => {console.log('data 1 : ', data)}); \ No newline at end of file diff --git a/maps/tests/Metadata/setProperty.html b/maps/tests/Metadata/setProperty.html new file mode 100644 index 00000000..06b029da --- /dev/null +++ b/maps/tests/Metadata/setProperty.html @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/maps/tests/Metadata/setProperty.json b/maps/tests/Metadata/setProperty.json new file mode 100644 index 00000000..06addc2f --- /dev/null +++ b/maps/tests/Metadata/setProperty.json @@ -0,0 +1,266 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"setProperty.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 101, 101, 101, 101, 0, 0, 0, 0, 0, 101, 101, 101, 101, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":7, + "name":"iframeTest", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":157.325836789532, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the red tiles.\nResult :\nNothing happens.\n\nTest : \nWalk on the grass, an iframe open. Then walk on the red tiles.\nResult : \nAn iframe of Wikipedia open.\n\nTest : \nWalk on the grass again.\nResult : \nAn iframe of Wikipedia open.\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":15.1244925229277, + "y":162.846515567498 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":8, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/showHideLayer.html b/maps/tests/Metadata/showHideLayer.html new file mode 100644 index 00000000..391ec449 --- /dev/null +++ b/maps/tests/Metadata/showHideLayer.html @@ -0,0 +1,21 @@ + + + + + + +
+ +
+ + + \ No newline at end of file diff --git a/maps/tests/Metadata/map.json b/maps/tests/Metadata/showHideLayer.json similarity index 70% rename from maps/tests/Metadata/map.json rename to maps/tests/Metadata/showHideLayer.json index 8967ed02..df61a655 100644 --- a/maps/tests/Metadata/map.json +++ b/maps/tests/Metadata/showHideLayer.json @@ -3,7 +3,7 @@ "infinite":false, "layers":[ { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, "id":1, "name":"start", @@ -15,7 +15,7 @@ "y":0 }, { - "data":[46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 33, 34, 34, 34, 34, 34, 34, 35, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 49, 50, 50, 50, 50, 50, 50, 51, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46], + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], "height":10, "id":2, "name":"bottom", @@ -27,11 +27,34 @@ "y":0 }, { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "data":[22, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 22, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":6, + "name":"crystal", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, "id":4, "name":"metadata", "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"showHideLayer.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], "type":"tilelayer", "visible":true, "width":10, @@ -42,34 +65,34 @@ "draworder":"topdown", "id":5, "name":"floorLayer", - "objects":[], + "objects":[ + { + "height":191.346515567498, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass, an iframe open, uncheck the checkbox.\nResult : \nCrystals disappeared.\n\nTest : \nCheck the checkbox\nResult : \nCrystals appear.", + "wrap":true + }, + "type":"", + "visible":true, + "width":306.219266604358, + "x":14.0029316840937, + "y":128.078129563643 + }], "opacity":1, "type":"objectgroup", "visible":true, "x":0, "y":0 - }, - { - "data":[1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19], - "height":10, - "id":3, - "name":"wall", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 }], - "nextlayerid":6, - "nextobjectid":1, + "nextlayerid":7, + "nextobjectid":2, "orientation":"orthogonal", - "properties":[ - { - "name":"script", - "type":"string", - "value":"script.js" - }], "renderorder":"right-down", "tiledversion":"1.4.3", "tileheight":32, @@ -222,6 +245,19 @@ }] }], "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 }], "tilewidth":32, "type":"map", diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index b46b8c32..aa8e55ec 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -12,31 +12,11 @@
-
- -
- From 2f9cc393a79ff6cc23864372f7e961d6bd262544 Mon Sep 17 00:00:00 2001 From: GRL Date: Thu, 20 May 2021 10:57:36 +0200 Subject: [PATCH 033/189] Implementation of getTag of the current user documentation of getTag Adding map for test of getTag --- docs/maps/api-reference.md | 15 ++ front/src/Api/Events/IframeEvent.ts | 4 +- front/src/Api/Events/TagEvent.ts | 10 + front/src/Api/IframeListener.ts | 14 ++ front/src/Connexion/RoomConnection.ts | 7 + front/src/Phaser/Game/GameScene.ts | 7 + front/src/iframe_api.ts | 27 ++- maps/tests/Metadata/TagList.html | 19 ++ maps/tests/Metadata/TagList.json | 254 ++++++++++++++++++++++++++ 9 files changed, 354 insertions(+), 3 deletions(-) create mode 100644 front/src/Api/Events/TagEvent.ts create mode 100644 maps/tests/Metadata/TagList.html create mode 100644 maps/tests/Metadata/TagList.json diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 01d3e636..889ed3ac 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -370,3 +370,18 @@ WA.registerMenuCommand('help', () => { WA.onChatMessage ... }); ``` + +### Getting the list of tags of the current user +``` +getTagUser(): Promise +``` + +Return the list of all the tags that has the current user. If the current user has no tag, return an empty list. If there is no connection with the room, return nothing. + +Example : +```javascript +WA.getTagUser().then((tagList) => { + ... +}); +``` + diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 8383cfbd..114cbb90 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -15,6 +15,7 @@ import type { UserInputChatEvent } from './UserInputChatEvent'; import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; +import type { TagEvent } from "./TagEvent"; export interface TypedMessageEvent extends MessageEvent { data: T @@ -36,11 +37,11 @@ export type IframeEventMap = { displayBubble: null removeBubble: null onPlayerMove: undefined - onDataLayerChange: undefined showLayer: LayerEvent hideLayer: LayerEvent setProperty: SetPropertyEvent getDataLayer: undefined + getTag: undefined } export interface IframeEvent { type: T; @@ -60,6 +61,7 @@ export interface IframeResponseEventMap { hasPlayerMoved: HasPlayerMovedEvent dataLayer: DataLayerEvent menuItemClicked: MenuItemClickedEvent + tagList: TagEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/Events/TagEvent.ts b/front/src/Api/Events/TagEvent.ts new file mode 100644 index 00000000..66665403 --- /dev/null +++ b/front/src/Api/Events/TagEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isTagEvent = + new tg.IsInterface().withProperties({ + list: tg.isArray(tg.isString), + }).get(); +/** + * A message sent from the iFrame to the game to show/hide a layer. + */ +export type TagEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 07246333..35ef6341 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -19,6 +19,7 @@ import { Math } from 'phaser'; import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; +import type { TagEvent } from "./Events/TagEvent"; /** @@ -77,6 +78,10 @@ class IframeListener { private readonly _registerMenuCommandStream: Subject = new Subject(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); + + private readonly _tagListStream: Subject = new Subject(); + public readonly tagListStream = this._tagListStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -145,12 +150,21 @@ class IframeListener { this._dataLayerChangeStream.next(); } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { this._registerMenuCommandStream.next(payload.data.menutItem) + } else if (payload.type == "getTag") { + this._tagListStream.next(); } } }, false); } + sendUserTagList(tagList: TagEvent){ + this.postMessage({ + 'type' : 'tagList', + 'data' : tagList + }) + } + sendDataLayerEvent(dataLayerEvent: DataLayerEvent) { this.postMessage({ 'type' : 'dataLayer', diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 6b2c63af..1cb4a97d 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -598,4 +598,11 @@ export class RoomConnection implements RoomConnection { public isAdmin(): boolean { return this.hasTag('admin'); } + + public getAllTag() : string[] { + this.tags.push('TEST'); + this.tags.push('TEST 2'); + this.tags.push('TEST 3'); + return this.tags; + } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9150b4c1..dee5eb53 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -903,6 +903,13 @@ ${escapedMessage} iframeListener.sendDataLayerEvent({data: this.gameMap.getMap()}); })) + this.iframeSubscriptionList.push(iframeListener.tagListStream.subscribe(()=> { + if (this.connection === undefined) { + return; + } + iframeListener.sendUserTagList({list: this.connection.getAllTag()}); + })) + } private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 00977157..517248ed 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -17,6 +17,7 @@ import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; +import {TagEvent, isTagEvent} from "./Api/Events/TagEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -45,10 +46,10 @@ interface WorkAdventureApi { getRoomId(): Promise; getStartLayerName(): Promise; getNickName(): Promise; - + getTagUser(): Promise; + getMap(): Promise onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void - getMap(): Promise } declare global { @@ -128,8 +129,19 @@ function getDataLayer(): Promise { }) } +function getTag(): Promise { + return new Promise((resolver, thrower) => { + tagResolver.push((resolver)); + postToParent({ + type: "getTag", + data: undefined + }) + }) +} + const gameStateResolver: Array<(event: GameStateEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] +const tagResolver: Array<(event : TagEvent) => void> = [] let immutableData: GameStateEvent; const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} @@ -151,6 +163,11 @@ window.WA = { }) }, + getTagUser(): Promise { + return getTag().then((res) => { + return res.list; + }) + }, getMap(): Promise { return getDataLayer().then((res) => { @@ -389,6 +406,12 @@ window.addEventListener('message', message => { if (callback) { callback(payload.data.menuItem) } + } else { + if (payload.type == "tagList" && isTagEvent(payloadData)) { + tagResolver.forEach(resolver => { + resolver(payloadData); + }) + } } } diff --git a/maps/tests/Metadata/TagList.html b/maps/tests/Metadata/TagList.html new file mode 100644 index 00000000..73bdc368 --- /dev/null +++ b/maps/tests/Metadata/TagList.html @@ -0,0 +1,19 @@ + + + + + + + + +
+ + \ No newline at end of file diff --git a/maps/tests/Metadata/TagList.json b/maps/tests/Metadata/TagList.json new file mode 100644 index 00000000..cced49a3 --- /dev/null +++ b/maps/tests/Metadata/TagList.json @@ -0,0 +1,254 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"TagList.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":131.903791109293, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass, an iframe open, click on the 'Get Tag List' button.\nResult : \nThe list of the tag is displayed in the iframe.\n\n\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":305.097705765524, + "x":14.750638909983, + "y":188.268561247737 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":10, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file From 3506063e65a2b8f62c3c4faec897bf1dffa2e62b Mon Sep 17 00:00:00 2001 From: GRL Date: Thu, 20 May 2021 17:09:10 +0200 Subject: [PATCH 034/189] first step on loading a tileset from a script --- front/src/Api/Events/IframeEvent.ts | 2 + front/src/Api/Events/TilesetEvent.ts | 15 ++ front/src/Api/IframeListener.ts | 8 +- front/src/Phaser/Game/GameMap.ts | 8 +- front/src/Phaser/Game/GameScene.ts | 9 +- front/src/iframe_api.ts | 16 ++ maps/tests/Metadata/ScriptMap.json | 219 +++++++++++++++++++++++++++ maps/tests/Metadata/script.js | 1 + maps/tests/iframe.html | 1 + 9 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 front/src/Api/Events/TilesetEvent.ts create mode 100644 maps/tests/Metadata/ScriptMap.json create mode 100644 maps/tests/Metadata/script.js diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 114cbb90..1ee7d1fb 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -16,6 +16,7 @@ import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; import type { TagEvent } from "./TagEvent"; +import type { TilesetEvent } from "./TilesetEvent"; export interface TypedMessageEvent extends MessageEvent { data: T @@ -42,6 +43,7 @@ export type IframeEventMap = { setProperty: SetPropertyEvent getDataLayer: undefined getTag: undefined + tilsetEvent: TilesetEvent } export interface IframeEvent { type: T; diff --git a/front/src/Api/Events/TilesetEvent.ts b/front/src/Api/Events/TilesetEvent.ts new file mode 100644 index 00000000..eab33bf7 --- /dev/null +++ b/front/src/Api/Events/TilesetEvent.ts @@ -0,0 +1,15 @@ +import * as tg from "generic-type-guard"; + +export const isTilesetEvent = + new tg.IsInterface().withProperties({ + name : tg.isString, + imgUrl : tg.isString, + tilewidth : tg.isNumber, + tileheight : tg.isNumber, + margin : tg.isNumber, + spacing : tg.isNumber, + }).get(); +/** + * A message sent from the iFrame to the game to show/hide a layer. + */ +export type TilesetEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 35ef6341..8af0949f 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -20,6 +20,7 @@ import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; import type { TagEvent } from "./Events/TagEvent"; +import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; /** @@ -79,9 +80,12 @@ class IframeListener { private readonly _registerMenuCommandStream: Subject = new Subject(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); - private readonly _tagListStream: Subject = new Subject(); + private readonly _tagListStream: Subject = new Subject(); public readonly tagListStream = this._tagListStream.asObservable(); + private readonly _tilesetLoaderStream: Subject = new Subject(); + public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -152,6 +156,8 @@ class IframeListener { this._registerMenuCommandStream.next(payload.data.menutItem) } else if (payload.type == "getTag") { this._tagListStream.next(); + } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { + this._tilesetLoaderStream.next(payload.data); } } }, false); diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 24ca60c7..d63a67e0 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -1,6 +1,5 @@ import type {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap"; import { flattenGroupLayersMap } from "../Map/LayersFlattener"; -import {iframeListener} from "../../Api/IframeListener"; import TilemapLayer = Phaser.Tilemaps.TilemapLayer; export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map) => void; @@ -151,4 +150,11 @@ export class GameMap { return undefined; } + public addTerrain(terrain : Phaser.Tilemaps.Tileset): void { + console.log('Add'); + for (const phaserLayer of this.phaserLayers) { + phaserLayer.tileset.push(terrain); + } + } + } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index dee5eb53..120bb303 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -500,7 +500,7 @@ export class GameScene extends DirtyScene implements CenterListener { if (!this.room.isDisconnected()) { this.connect(); } - + console.log('display'); document.addEventListener('visibilitychange', this.onVisibilityChangeCallback); } @@ -910,6 +910,13 @@ ${escapedMessage} iframeListener.sendUserTagList({list: this.connection.getAllTag()}); })) + this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { + //this.load.tilemapTiledJSON('logo', tileset.imgUrl); + this.load.image('logo', tileset.imgUrl); + this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); + this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); + })) + } private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 517248ed..5a3336a4 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -18,6 +18,7 @@ import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; import {TagEvent, isTagEvent} from "./Api/Events/TagEvent"; +import type { TilesetEvent } from "./Api/Events/TilesetEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -48,6 +49,7 @@ interface WorkAdventureApi { getNickName(): Promise; getTagUser(): Promise; getMap(): Promise + loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void } @@ -163,6 +165,20 @@ window.WA = { }) }, + loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void { + postToParent({ + type: "tilsetEvent", + data: { + name: name, + imgUrl: imgUrl, + tilewidth: tilewidth, + tileheight: tileheight, + margin: margin, + spacing: spacing + } as TilesetEvent + }) + }, + getTagUser(): Promise { return getTag().then((res) => { return res.list; diff --git a/maps/tests/Metadata/ScriptMap.json b/maps/tests/Metadata/ScriptMap.json new file mode 100644 index 00000000..93972a73 --- /dev/null +++ b/maps/tests/Metadata/ScriptMap.json @@ -0,0 +1,219 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":10, + "nextobjectid":2, + "orientation":"orthogonal", + "properties":[ + { + "name":"script", + "type":"string", + "value":"script.js" + }], + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/Metadata/script.js b/maps/tests/Metadata/script.js new file mode 100644 index 00000000..d04d7952 --- /dev/null +++ b/maps/tests/Metadata/script.js @@ -0,0 +1 @@ +console.log('script chargé !!!!!'); \ No newline at end of file diff --git a/maps/tests/iframe.html b/maps/tests/iframe.html index aa8e55ec..e0ba05d6 100644 --- a/maps/tests/iframe.html +++ b/maps/tests/iframe.html @@ -17,6 +17,7 @@ chatDiv.innerText = message; document.getElementById('chatSent').append(chatDiv); })); + WA.loadTileset('TEST', 'https://gparant.github.io/tcm-client/TCM/paris-map/tileset1.png', 32, 32, 0, 0); From 1110f4fb7f6132a07c808ccc2522b1ce524420af Mon Sep 17 00:00:00 2001 From: GRL Date: Fri, 21 May 2021 16:24:48 +0200 Subject: [PATCH 035/189] Revert "Merge branch 'update-game-tiles' into metadataScriptingApi" This reverts commit 796a9418d3b6c356c5c25bfbc4503207b08572c4, reversing changes made to 3506063e65a2b8f62c3c4faec897bf1dffa2e62b. --- front/src/Api/Events/IframeEvent.ts | 4 +-- front/src/Api/Events/UpdateTileEvent.ts | 15 --------- front/src/Api/IframeListener.ts | 14 ++++---- front/src/Phaser/Game/GameScene.ts | 45 +++---------------------- front/src/Phaser/Map/ITiledMap.ts | 21 +++++------- front/src/iframe_api.ts | 22 +++++++++++- 6 files changed, 42 insertions(+), 79 deletions(-) delete mode 100644 front/src/Api/Events/UpdateTileEvent.ts diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 6a76f870..1ee7d1fb 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -17,7 +17,6 @@ import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; import type { TagEvent } from "./TagEvent"; import type { TilesetEvent } from "./TilesetEvent"; -import type { UpdateTileEvent } from "./UpdateTileEvent"; export interface TypedMessageEvent extends MessageEvent { data: T @@ -44,8 +43,7 @@ export type IframeEventMap = { setProperty: SetPropertyEvent getDataLayer: undefined getTag: undefined - tilesetEvent: TilesetEvent - updateTileEvent: UpdateTileEvent + tilsetEvent: TilesetEvent } export interface IframeEvent { type: T; diff --git a/front/src/Api/Events/UpdateTileEvent.ts b/front/src/Api/Events/UpdateTileEvent.ts deleted file mode 100644 index 5817622c..00000000 --- a/front/src/Api/Events/UpdateTileEvent.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as tg from "generic-type-guard"; - - -export const isUpdateTileEvent = tg.isArray( - new tg.IsInterface().withProperties({ - x: tg.isNumber, - y: tg.isNumber, - tile: tg.isUnion(tg.isNumber, tg.isString), - layer: tg.isString - }).get() -); -/** - * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. - */ -export type UpdateTileEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 2406e92d..8af0949f 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -21,7 +21,6 @@ import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; import type { TagEvent } from "./Events/TagEvent"; import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; -import { isUpdateTileEvent, UpdateTileEvent } from './Events/UpdateTileEvent'; /** @@ -36,6 +35,12 @@ class IframeListener { private readonly _openPopupStream: Subject = new Subject(); public readonly openPopupStream = this._openPopupStream.asObservable(); + private readonly _openTabStream: Subject = new Subject(); + public readonly openTabStream = this._openTabStream.asObservable(); + + private readonly _goToPageStream: Subject = new Subject(); + public readonly goToPageStream = this._goToPageStream.asObservable(); + private readonly _openCoWebSiteStream: Subject = new Subject(); public readonly openCoWebSiteStream = this._openCoWebSiteStream.asObservable(); @@ -81,9 +86,6 @@ class IframeListener { private readonly _tilesetLoaderStream: Subject = new Subject(); public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable(); - private readonly _updateTileStream: Subject = new Subject(); - public readonly updateTileStream = this._updateTileStream.asObservable(); - private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -154,10 +156,8 @@ class IframeListener { this._registerMenuCommandStream.next(payload.data.menutItem) } else if (payload.type == "getTag") { this._tagListStream.next(); - } else if (payload.type == "tilesetEvent" && isTilesetEvent(payload.data)) { + } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { this._tilesetLoaderStream.next(payload.data); - } else if (payload.type == "updateTileEvent" && isUpdateTileEvent(payload.data)) { - this._updateTileStream.next(payload.data) } } }, false); diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 33013454..120bb303 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1,4 +1,4 @@ -import { gameManager } from "./GameManager"; +import {gameManager} from "./GameManager"; import type { GroupCreatedUpdatedMessageInterface, MessageUserJoined, @@ -80,7 +80,6 @@ import CanvasTexture = Phaser.Textures.CanvasTexture; import GameObject = Phaser.GameObjects.GameObject; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import DOMElement = Phaser.GameObjects.DOMElement; -import EVENT_TYPE = Phaser.Scenes.Events import type { Subscription } from "rxjs"; import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; @@ -186,7 +185,7 @@ export class GameScene extends DirtyScene implements CenterListener { private characterLayers!: string[]; private companion!: string | null; private messageSubscription: Subscription | null = null; - private popUpElements: Map = new Map(); + private popUpElements : Map = new Map(); private originalMapUrl: string | undefined; private pinchManager: PinchManager | undefined; private physicsEnabled: boolean = true; @@ -911,33 +910,12 @@ ${escapedMessage} iframeListener.sendUserTagList({list: this.connection.getAllTag()}); })) -/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { //this.load.tilemapTiledJSON('logo', tileset.imgUrl); this.load.image('logo', tileset.imgUrl); this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); })) -*/ - - this.iframeSubscriptionList.push(iframeListener.updateTileStream.subscribe(event => { - for (const eventTile of event) { - const layer = this.gameMap.findPhaserLayer(eventTile.layer); - if (layer) { - const tile = layer.getTileAt(eventTile.x, eventTile.y) - if (typeof eventTile.tile == "string") { - const tileIndex = this.getIndexForTileType(eventTile.tile); - if (tileIndex) { - tile.index = tileIndex - } else { - return - } - } else { - tile.index = eventTile.tile - } - } - } - })) } @@ -967,19 +945,6 @@ ${escapedMessage} } - private getIndexForTileType(tileType: string): number | null { - for (const tileset of this.mapFile.tilesets) { - if (tileset.tiles) { - for (const tilesetTile of tileset.tiles) { - if (tilesetTile.type == tileType) { - return tileset.firstgid + tilesetTile.id - } - } - } - } - return null - } - private getMapDirUrl(): string { return this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); } @@ -987,8 +952,8 @@ ${escapedMessage} private onMapExit(exitKey: string) { if (this.mapTransitioning) return; this.mapTransitioning = true; - const { roomId, hash } = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); - if (!roomId) throw new Error('Could not find the room from its exit key: ' + exitKey); + const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance); + if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey); urlManager.pushStartLayerNameToUrl(hash); const menuScene: MenuScene = this.scene.get(MenuSceneName) as MenuScene menuScene.reset() @@ -1190,7 +1155,7 @@ ${escapedMessage} this.physics.add.collider(this.CurrentPlayer, phaserLayer, (object1: GameObject, object2: GameObject) => { //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) }); - phaserLayer.setCollisionByProperty({ collides: true }); + phaserLayer.setCollisionByProperty({collides: true}); if (DEBUG_MODE) { //debug code to see the collision hitbox of the object in the top layer phaserLayer.renderDebug(this.add.graphics(), { diff --git a/front/src/Phaser/Map/ITiledMap.ts b/front/src/Phaser/Map/ITiledMap.ts index 2f5d45bc..d381e9d4 100644 --- a/front/src/Phaser/Map/ITiledMap.ts +++ b/front/src/Phaser/Map/ITiledMap.ts @@ -36,7 +36,7 @@ export interface ITiledMap { export interface ITiledMapLayerProperty { name: string; type: string; - value: string | boolean | number | undefined; + value: string|boolean|number|undefined; } /*export interface ITiledMapLayerBooleanProperty { @@ -65,7 +65,7 @@ export interface ITiledMapGroupLayer { export interface ITiledMapTileLayer { id?: number, - data: number[] | string; + data: number[]|string; height: number; name: string; opacity: number; @@ -117,7 +117,7 @@ export interface ITiledMapObject { gid: number; height: number; name: string; - properties: { [key: string]: string }; + properties: {[key: string]: string}; rotation: number; type: string; visible: boolean; @@ -133,12 +133,12 @@ export interface ITiledMapObject { /** * Polygon points */ - polygon: { x: number, y: number }[]; + polygon: {x: number, y: number}[]; /** * Polyline points */ - polyline: { x: number, y: number }[]; + polyline: {x: number, y: number}[]; text?: ITiledText } @@ -152,7 +152,7 @@ export interface ITiledText { underline?: boolean, italic?: boolean, strikeout?: boolean, - halign?: "center" | "right" | "justify" | "left" + halign?: "center"|"right"|"justify"|"left" } export interface ITiledTileSet { @@ -163,14 +163,14 @@ export interface ITiledTileSet { imagewidth: number; margin: number; name: string; - properties: { [key: string]: string }; + properties: {[key: string]: string}; spacing: number; tilecount: number; tileheight: number; tilewidth: number; transparentcolor: string; terrains: ITiledMapTerrain[]; - tiles: Array; + tiles: {[key: string]: { terrain: number[] }}; /** * Refers to external tileset file (should be JSON) @@ -178,11 +178,6 @@ export interface ITiledTileSet { source: string; } -export interface ITile { - id: number, - type?: string -} - export interface ITiledMapTerrain { name: string; tile: number; diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index f253c48d..5a3336a4 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -26,6 +26,8 @@ interface WorkAdventureApi { onEnterZone(name: string, callback: () => void): void; onLeaveZone(name: string, callback: () => void): void; openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; + openTab(url: string): void; + goToPage(url: string): void; openCoWebSite(url: string): void; closeCoWebSite(): void; disablePlayerControls() : void; @@ -165,7 +167,7 @@ window.WA = { loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void { postToParent({ - type: "updateTileEvent", + type: "tilsetEvent", data: { name: name, imgUrl: imgUrl, @@ -274,6 +276,24 @@ window.WA = { window.parent.postMessage({ 'type': 'removeBubble' }, '*'); }, + openTab(url: string): void { + window.parent.postMessage({ + "type": 'openTab', + "data": { + url + } as OpenTabEvent + }, '*'); + }, + + goToPage(url: string): void { + window.parent.postMessage({ + "type": 'goToPage', + "data": { + url + } as GoToPageEvent + }, '*'); + }, + openCoWebSite(url: string): void { window.parent.postMessage({ "type": 'openCoWebSite', From a3165a0540f8aef8477c62e6b4d4dad6adac1150 Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 09:39:04 +0200 Subject: [PATCH 036/189] pause for loading tileset on the fly --- front/src/Phaser/Game/GameScene.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 5b049ebc..3df7e093 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -910,12 +910,12 @@ ${escapedMessage} iframeListener.sendUserTagList({list: this.connection.getAllTag()}); })) - this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { +/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { //this.load.tilemapTiledJSON('logo', tileset.imgUrl); this.load.image('logo', tileset.imgUrl); this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); - })) + }))*/ } From b18b2fe0e31c5c6481f184b754c581ac2e4cd6a7 Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 09:50:59 +0200 Subject: [PATCH 037/189] preparation for merge with metadataScriptApi --- .../{ApiUpdateTileEvent.ts => ChangeTileEvent.ts} | 6 ++---- front/src/Api/IframeListener.ts | 6 +++--- front/src/Phaser/Game/GameScene.ts | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) rename front/src/Api/Events/{ApiUpdateTileEvent.ts => ChangeTileEvent.ts} (70%) diff --git a/front/src/Api/Events/ApiUpdateTileEvent.ts b/front/src/Api/Events/ChangeTileEvent.ts similarity index 70% rename from front/src/Api/Events/ApiUpdateTileEvent.ts rename to front/src/Api/Events/ChangeTileEvent.ts index 094596a4..5a9183ca 100644 --- a/front/src/Api/Events/ApiUpdateTileEvent.ts +++ b/front/src/Api/Events/ChangeTileEvent.ts @@ -1,9 +1,7 @@ - import * as tg from "generic-type-guard"; -export const updateTile = "updateTile" -export const isUpdateTileEvent = tg.isArray( +export const isChangeTileEvent = tg.isArray( new tg.IsInterface().withProperties({ x: tg.isNumber, y: tg.isNumber, @@ -14,4 +12,4 @@ export const isUpdateTileEvent = tg.isArray( /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ -export type UpdateTileEvent = tg.GuardedType; \ No newline at end of file +export type ChangeTileEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index f97e80ae..d59c9140 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -13,7 +13,7 @@ import { scriptUtils } from "./ScriptUtils"; import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent"; import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; import { isLoadPageEvent } from './Events/LoadPageEvent'; -import { isUpdateTileEvent, UpdateTileEvent } from './Events/ApiUpdateTileEvent'; +import { isChangeTileEvent, ChangeTileEvent } from './Events/ChangeTileEvent'; /** @@ -58,7 +58,7 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); - private readonly _updateTileEvent: Subject = new Subject(); + private readonly _updateTileEvent: Subject = new Subject(); public readonly updateTileEvent = this._updateTileEvent.asObservable(); private readonly iframes = new Set(); @@ -114,7 +114,7 @@ class IframeListener { this._removeBubbleStream.next(); } else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) { this._loadPageStream.next(payload.data.url); - } else if (payload.type == "updateTile" && isUpdateTileEvent(payload.data)) { + } else if (payload.type == "updateTile" && isChangeTileEvent(payload.data)) { this._updateTileEvent.next(payload.data) } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 674087e0..fc5bf80f 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -134,7 +134,7 @@ export class GameScene extends ResizableScene implements CenterListener { MapPlayers!: Phaser.Physics.Arcade.Group; MapPlayersByKey: Map = new Map(); Map!: Phaser.Tilemaps.Tilemap; - Layers!: Array; + Layers!: Array; Objects!: Array; mapFile!: ITiledMap; groups: Map; @@ -395,12 +395,12 @@ export class GameScene extends ResizableScene implements CenterListener { this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels); //add layer on map - this.Layers = new Array(); + this.Layers = new Array(); let depth = -2; for (const layer of this.gameMap.layersIterator) { if (layer.type === 'tilelayer') { - this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth)); + this.addLayer(this.Map.createLayer(layer.name, this.Terrains, 0, 0).setDepth(depth)); const exitSceneUrl = this.getExitSceneUrl(layer); if (exitSceneUrl !== undefined) { @@ -1105,13 +1105,13 @@ ${escapedMessage} this.cameras.main.setZoom(ZOOM_LEVEL); } - addLayer(Layer: Phaser.Tilemaps.StaticTilemapLayer) { + addLayer(Layer: Phaser.Tilemaps.TilemapLayer) { this.Layers.push(Layer); } createCollisionWithPlayer() { //add collision layer - this.Layers.forEach((Layer: Phaser.Tilemaps.StaticTilemapLayer) => { + this.Layers.forEach((Layer: Phaser.Tilemaps.TilemapLayer) => { this.physics.add.collider(this.CurrentPlayer, Layer, (object1: GameObject, object2: GameObject) => { //this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name) }); From a7b09e91ba95dcd17207179c8b9dd1e6a313028d Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 10:09:58 +0200 Subject: [PATCH 038/189] Revert "Merge branch 'update-game-tiles' into metadataScriptingApi" This reverts commit 428625e61b558004ae37385b21270fdf11864b2a, reversing changes made to a3165a0540f8aef8477c62e6b4d4dad6adac1150. --- front/src/Api/Events/ChangeTileEvent.ts | 15 --------------- front/src/Api/IframeListener.ts | 9 --------- 2 files changed, 24 deletions(-) delete mode 100644 front/src/Api/Events/ChangeTileEvent.ts diff --git a/front/src/Api/Events/ChangeTileEvent.ts b/front/src/Api/Events/ChangeTileEvent.ts deleted file mode 100644 index 5a9183ca..00000000 --- a/front/src/Api/Events/ChangeTileEvent.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as tg from "generic-type-guard"; - - -export const isChangeTileEvent = tg.isArray( - new tg.IsInterface().withProperties({ - x: tg.isNumber, - y: tg.isNumber, - tile: tg.isUnion(tg.isNumber, tg.isString), - layer: tg.isUnion(tg.isNumber, tg.isString) - }).get() -); -/** - * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. - */ -export type ChangeTileEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index d14a3486..8af0949f 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -21,8 +21,6 @@ import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; import type { TagEvent } from "./Events/TagEvent"; import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; -import { isLoadPageEvent } from './Events/LoadPageEvent'; -import { isChangeTileEvent, ChangeTileEvent } from './Events/ChangeTileEvent'; /** @@ -88,9 +86,6 @@ class IframeListener { private readonly _tilesetLoaderStream: Subject = new Subject(); public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable(); - private readonly _updateTileEvent: Subject = new Subject(); - public readonly updateTileEvent = this._updateTileEvent.asObservable(); - private readonly iframes = new Set(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -163,10 +158,6 @@ class IframeListener { this._tagListStream.next(); } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { this._tilesetLoaderStream.next(payload.data); - } else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) { - this._loadPageStream.next(payload.data.url); - } else if (payload.type == "updateTile" && isChangeTileEvent(payload.data)) { - this._updateTileEvent.next(payload.data) } } }, false); From 343ad6ea9636838d12e6127f6a8aba59a9d3c324 Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 10:11:25 +0200 Subject: [PATCH 039/189] Revert "preparation for merge with metadataScriptApi" This reverts commit b18b2fe0e31c5c6481f184b754c581ac2e4cd6a7. --- front/src/Api/Events/ApiUpdateTileEvent.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 front/src/Api/Events/ApiUpdateTileEvent.ts diff --git a/front/src/Api/Events/ApiUpdateTileEvent.ts b/front/src/Api/Events/ApiUpdateTileEvent.ts new file mode 100644 index 00000000..e69de29b From 36f0cd1a23206c14b718165875ba4d970def49ed Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 10:11:27 +0200 Subject: [PATCH 040/189] Revert "pause for loading tileset on the fly" This reverts commit a3165a0540f8aef8477c62e6b4d4dad6adac1150. --- front/src/Phaser/Game/GameScene.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 3df7e093..5b049ebc 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -910,12 +910,12 @@ ${escapedMessage} iframeListener.sendUserTagList({list: this.connection.getAllTag()}); })) -/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { + this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { //this.load.tilemapTiledJSON('logo', tileset.imgUrl); this.load.image('logo', tileset.imgUrl); this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); - }))*/ + })) } From d4bc999c54a2e7d9cb961c26d847777e9f0e8ad6 Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 10:15:56 +0200 Subject: [PATCH 041/189] pause loading tileset on fly --- front/src/Api/Events/IframeEvent.ts | 2 +- front/src/Api/IframeListener.ts | 10 +++++----- front/src/Phaser/Game/GameScene.ts | 4 ++-- front/src/iframe_api.ts | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 1ee7d1fb..8e4a76f5 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -43,7 +43,7 @@ export type IframeEventMap = { setProperty: SetPropertyEvent getDataLayer: undefined getTag: undefined - tilsetEvent: TilesetEvent + //tilsetEvent: TilesetEvent } export interface IframeEvent { type: T; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 8af0949f..647a95dc 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -20,7 +20,7 @@ import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; import type { TagEvent } from "./Events/TagEvent"; -import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; +//import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; /** @@ -83,8 +83,8 @@ class IframeListener { private readonly _tagListStream: Subject = new Subject(); public readonly tagListStream = this._tagListStream.asObservable(); - private readonly _tilesetLoaderStream: Subject = new Subject(); - public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable(); +/* private readonly _tilesetLoaderStream: Subject = new Subject(); + public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable();*/ private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -156,8 +156,8 @@ class IframeListener { this._registerMenuCommandStream.next(payload.data.menutItem) } else if (payload.type == "getTag") { this._tagListStream.next(); - } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { - this._tilesetLoaderStream.next(payload.data); +/* } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { + this._tilesetLoaderStream.next(payload.data);*/ } } }, false); diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 5b049ebc..3df7e093 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -910,12 +910,12 @@ ${escapedMessage} iframeListener.sendUserTagList({list: this.connection.getAllTag()}); })) - this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { +/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { //this.load.tilemapTiledJSON('logo', tileset.imgUrl); this.load.image('logo', tileset.imgUrl); this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); - })) + }))*/ } diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 5a3336a4..b2eac975 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -49,7 +49,7 @@ interface WorkAdventureApi { getNickName(): Promise; getTagUser(): Promise; getMap(): Promise - loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; + //loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void } @@ -165,7 +165,7 @@ window.WA = { }) }, - loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void { +/* loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void { postToParent({ type: "tilsetEvent", data: { @@ -177,7 +177,7 @@ window.WA = { spacing: spacing } as TilesetEvent }) - }, + },*/ getTagUser(): Promise { return getTag().then((res) => { From 7c44d747de474ea8c476ff77d75158ee7d1339f5 Mon Sep 17 00:00:00 2001 From: GRL78 <80678534+GRL78@users.noreply.github.com> Date: Tue, 25 May 2021 11:02:25 +0200 Subject: [PATCH 042/189] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David Négrier --- docs/maps/api-reference.md | 22 ++++++--------- front/src/Api/Events/GameStateEvent.ts | 4 +-- front/src/Api/Events/HasPlayerMovedEvent.ts | 2 +- front/src/Phaser/Game/GameMap.ts | 31 ++------------------- 4 files changed, 14 insertions(+), 45 deletions(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 889ed3ac..30d0f1ea 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -258,7 +258,7 @@ WA.hideLayer('bottom'); WA.setProperty(layerName : string, propertyName : string, propertyValue : string | number | boolean | undefined) : void; ``` -Set the value of the "propertyName" property of the layer "layerName" at "propertyValue". If the property doesn't exist, create the property "propertyName" and set the value of the property at "propertyValue". +Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`. Example : @@ -266,12 +266,12 @@ Example : WA.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/'); ``` -### Listen player movement +### Listen to player movement ``` onPlayerMove(callback: HasPlayerMovedEventCallback): void; ``` -Listens to the movement of the current user and calls the callback. Send a event when current user stop moving, change direction and every 200ms when moving in the same direction. +Listens to the movement of the current user and calls the callback. Sends an event when the user stops moving, changes direction and every 200ms when moving in the same direction. The event has the following attributes : * **moving (boolean):** **true** when the current player is moving, **false** otherwise. @@ -281,7 +281,7 @@ The event has the following attributes : **callback:** the function that will be called when the current player is moving. It contains the event. -Exemple : +Example : ```javascript WA.onPlayerMove(console.log); ``` @@ -292,7 +292,7 @@ WA.onPlayerMove(console.log); getMap(): Promise ``` -Return a promise of an ITiledMap that contains the JSON file of the map plus the property set by a script. +Returns a promise that resolves to the JSON file of the map. Please note that if you modified the map (for instance by calling `WA.setProperty`, the data returned by `getMap` will contain those changes. Example : ```javascript @@ -360,23 +360,20 @@ WA.getStartLayerName().then((starLayerName) => {console.log(starLayerName)}); ``` registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) ``` -Add a custom menu named "commandDescriptor" in the menu that call the callback when clicked. +Add a custom menu item containing the text `commandDescriptor`. A click on the menu will trigger the `callback`. Example : ```javascript -let chatbotEnabled = false -WA.registerMenuCommand('help', () => { - chatbotEnabled = true; - WA.onChatMessage ... +WA.registerMenuCommand('About', () => { + console.log("The About menu was clicked"); }); -``` ### Getting the list of tags of the current user ``` getTagUser(): Promise ``` -Return the list of all the tags that has the current user. If the current user has no tag, return an empty list. If there is no connection with the room, return nothing. +Returns the tags of the current user. If the current user has no tag, returns an empty list. Example : ```javascript @@ -384,4 +381,3 @@ WA.getTagUser().then((tagList) => { ... }); ``` - diff --git a/front/src/Api/Events/GameStateEvent.ts b/front/src/Api/Events/GameStateEvent.ts index 72e40898..946febe8 100644 --- a/front/src/Api/Events/GameStateEvent.ts +++ b/front/src/Api/Events/GameStateEvent.ts @@ -23,6 +23,6 @@ export const isGameStateEvent = startLayerName: tg.isUnion(tg.isString, tg.isNull) }).get(); /** - * A message sent from the game to the iFrame when the gameState is got by the script + * A message sent from the game to the iFrame when the gameState is received by the script */ -export type GameStateEvent = tg.GuardedType; \ No newline at end of file +export type GameStateEvent = tg.GuardedType; diff --git a/front/src/Api/Events/HasPlayerMovedEvent.ts b/front/src/Api/Events/HasPlayerMovedEvent.ts index 28603284..e7750367 100644 --- a/front/src/Api/Events/HasPlayerMovedEvent.ts +++ b/front/src/Api/Events/HasPlayerMovedEvent.ts @@ -11,7 +11,7 @@ export const isHasPlayerMovedEvent = }).get(); /** - * A message sent from the game to the iFrame when the player move after the iFrame send a message to the game that it want to listen to the position of the player + * A message sent from the game to the iFrame to notify a movement from the current player. */ export type HasPlayerMovedEvent = tg.GuardedType; diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index d63a67e0..cc109751 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -117,41 +117,14 @@ export class GameMap { } public findLayer(layerName: string): ITiledMapLayer | undefined { - let i = 0; - let found = false; - while (!found && i layer.name = layerName); } public findPhaserLayer(layerName: string): TilemapLayer | undefined { - let i = 0; - let found = false; - while (!found && i layer.layer.name = layerName); } public addTerrain(terrain : Phaser.Tilemaps.Tileset): void { - console.log('Add'); for (const phaserLayer of this.phaserLayers) { phaserLayer.tileset.push(terrain); } From a5cb93541afad9a95fe4614bd96a8f7d8ee99a9b Mon Sep 17 00:00:00 2001 From: GRL Date: Tue, 25 May 2021 17:21:02 +0200 Subject: [PATCH 043/189] correction from code review --- front/src/Api/Events/ApiUpdateTileEvent.ts | 0 front/src/Api/Events/GameStateEvent.ts | 25 ++--- front/src/Api/Events/HasPlayerMovedEvent.ts | 2 +- front/src/Api/Events/IframeEvent.ts | 5 - front/src/Api/Events/TagEvent.ts | 10 -- front/src/Api/Events/TilesetEvent.ts | 15 --- front/src/Api/IframeListener.ts | 15 +-- front/src/Connexion/RoomConnection.ts | 9 +- front/src/Phaser/Game/GameScene.ts | 27 ++--- front/src/iframe_api.ts | 111 +++++++------------- 10 files changed, 58 insertions(+), 161 deletions(-) delete mode 100644 front/src/Api/Events/ApiUpdateTileEvent.ts delete mode 100644 front/src/Api/Events/TagEvent.ts delete mode 100644 front/src/Api/Events/TilesetEvent.ts diff --git a/front/src/Api/Events/ApiUpdateTileEvent.ts b/front/src/Api/Events/ApiUpdateTileEvent.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/front/src/Api/Events/GameStateEvent.ts b/front/src/Api/Events/GameStateEvent.ts index 72e40898..704cd962 100644 --- a/front/src/Api/Events/GameStateEvent.ts +++ b/front/src/Api/Events/GameStateEvent.ts @@ -1,26 +1,13 @@ import * as tg from "generic-type-guard"; -/*export const isPositionState = new tg.IsInterface().withProperties({ - x: tg.isNumber, - y: tg.isNumber -}).get() -export const isPlayerState = new tg.IsInterface() - .withStringIndexSignature( - new tg.IsInterface().withProperties({ - position: isPositionState, - pusherId: tg.isUnion(tg.isNumber, tg.isUndefined) - }).get() - ).get() - -export type PlayerStateObject = tg.GuardedType;*/ - export const isGameStateEvent = new tg.IsInterface().withProperties({ - roomId: tg.isString, - mapUrl: tg.isString, - nickname: tg.isUnion(tg.isString, tg.isNull), - uuid: tg.isUnion(tg.isString, tg.isUndefined), - startLayerName: tg.isUnion(tg.isString, tg.isNull) + roomId: tg.isString, + mapUrl: tg.isString, + nickname: tg.isUnion(tg.isString, tg.isNull), + uuid: tg.isUnion(tg.isString, tg.isUndefined), + startLayerName: tg.isUnion(tg.isString, tg.isNull), + tags : tg.isArray(tg.isString), }).get(); /** * A message sent from the game to the iFrame when the gameState is got by the script diff --git a/front/src/Api/Events/HasPlayerMovedEvent.ts b/front/src/Api/Events/HasPlayerMovedEvent.ts index 28603284..5fe2a1e2 100644 --- a/front/src/Api/Events/HasPlayerMovedEvent.ts +++ b/front/src/Api/Events/HasPlayerMovedEvent.ts @@ -4,7 +4,7 @@ import * as tg from "generic-type-guard"; export const isHasPlayerMovedEvent = new tg.IsInterface().withProperties({ - direction: tg.isString, + direction: tg.isElementOf('right', 'left', 'up', 'down'), moving: tg.isBoolean, x: tg.isNumber, y: tg.isNumber diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 8e4a76f5..1bab019a 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -15,8 +15,6 @@ import type { UserInputChatEvent } from './UserInputChatEvent'; import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; -import type { TagEvent } from "./TagEvent"; -import type { TilesetEvent } from "./TilesetEvent"; export interface TypedMessageEvent extends MessageEvent { data: T @@ -24,7 +22,6 @@ export interface TypedMessageEvent extends MessageEvent { export type IframeEventMap = { getState: GameStateEvent, - // updateTile: UpdateTileEvent registerMenuCommand: MenuItemRegisterEvent chat: ChatEvent, openPopup: OpenPopupEvent @@ -42,7 +39,6 @@ export type IframeEventMap = { hideLayer: LayerEvent setProperty: SetPropertyEvent getDataLayer: undefined - getTag: undefined //tilsetEvent: TilesetEvent } export interface IframeEvent { @@ -63,7 +59,6 @@ export interface IframeResponseEventMap { hasPlayerMoved: HasPlayerMovedEvent dataLayer: DataLayerEvent menuItemClicked: MenuItemClickedEvent - tagList: TagEvent } export interface IframeResponseEvent { type: T; diff --git a/front/src/Api/Events/TagEvent.ts b/front/src/Api/Events/TagEvent.ts deleted file mode 100644 index 66665403..00000000 --- a/front/src/Api/Events/TagEvent.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as tg from "generic-type-guard"; - -export const isTagEvent = - new tg.IsInterface().withProperties({ - list: tg.isArray(tg.isString), - }).get(); -/** - * A message sent from the iFrame to the game to show/hide a layer. - */ -export type TagEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/Events/TilesetEvent.ts b/front/src/Api/Events/TilesetEvent.ts deleted file mode 100644 index eab33bf7..00000000 --- a/front/src/Api/Events/TilesetEvent.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as tg from "generic-type-guard"; - -export const isTilesetEvent = - new tg.IsInterface().withProperties({ - name : tg.isString, - imgUrl : tg.isString, - tilewidth : tg.isNumber, - tileheight : tg.isNumber, - margin : tg.isNumber, - spacing : tg.isNumber, - }).get(); -/** - * A message sent from the iFrame to the game to show/hide a layer. - */ -export type TilesetEvent = tg.GuardedType; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 647a95dc..ec340b16 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -19,7 +19,6 @@ import { Math } from 'phaser'; import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; -import type { TagEvent } from "./Events/TagEvent"; //import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; @@ -80,9 +79,6 @@ class IframeListener { private readonly _registerMenuCommandStream: Subject = new Subject(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); - private readonly _tagListStream: Subject = new Subject(); - public readonly tagListStream = this._tagListStream.asObservable(); - /* private readonly _tilesetLoaderStream: Subject = new Subject(); public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable();*/ @@ -154,9 +150,7 @@ class IframeListener { this._dataLayerChangeStream.next(); } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { this._registerMenuCommandStream.next(payload.data.menutItem) - } else if (payload.type == "getTag") { - this._tagListStream.next(); -/* } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { +/* } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { this._tilesetLoaderStream.next(payload.data);*/ } } @@ -164,13 +158,6 @@ class IframeListener { } - sendUserTagList(tagList: TagEvent){ - this.postMessage({ - 'type' : 'tagList', - 'data' : tagList - }) - } - sendDataLayerEvent(dataLayerEvent: DataLayerEvent) { this.postMessage({ 'type' : 'dataLayer', diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 1cb4a97d..8bfa3b6a 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -169,9 +169,9 @@ export class RoomConnection implements RoomConnection { } else if (message.hasWorldfullmessage()) { worldFullMessageStream.onMessage(); this.closed = true; - // // } else if (message.hasWorldconnexionmessage()) { - // worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); - // this.closed = true; + } else if (message.hasWorldconnexionmessage()) { + worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); + this.closed = true; } else if (message.hasWebrtcsignaltoclientmessage()) { this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage()); } else if (message.hasWebrtcscreensharingsignaltoclientmessage()) { @@ -600,9 +600,6 @@ export class RoomConnection implements RoomConnection { } public getAllTag() : string[] { - this.tags.push('TEST'); - this.tags.push('TEST 2'); - this.tags.push('TEST 3'); return this.tags; } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 3df7e093..5e540770 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -864,15 +864,6 @@ ${escapedMessage} this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(() => { this.userInputManager.restoreControls(); })); - this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => { - iframeListener.sendFrozenGameStateEvent({ - mapUrl: this.MapUrlFile, - startLayerName: this.startLayerName, - uuid: localUserStore.getLocalUser()?.uuid, - nickname: localUserStore.getName(), - roomId: this.RoomId, - }) - })); let scriptedBubbleSprite: Sprite; this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(() => { @@ -886,12 +877,10 @@ ${escapedMessage} })); this.iframeSubscriptionList.push(iframeListener.showLayerStream.subscribe((layerEvent)=>{ - console.log('show'); this.setLayerVisibility(layerEvent.name, true); })); this.iframeSubscriptionList.push(iframeListener.hideLayerStream.subscribe((layerEvent)=>{ - console.log('hide'); this.setLayerVisibility(layerEvent.name, false); })); @@ -903,12 +892,16 @@ ${escapedMessage} iframeListener.sendDataLayerEvent({data: this.gameMap.getMap()}); })) - this.iframeSubscriptionList.push(iframeListener.tagListStream.subscribe(()=> { - if (this.connection === undefined) { - return; - } - iframeListener.sendUserTagList({list: this.connection.getAllTag()}); - })) + this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => { + iframeListener.sendFrozenGameStateEvent({ + mapUrl: this.MapUrlFile, + startLayerName: this.startLayerName, + uuid: localUserStore.getLocalUser()?.uuid, + nickname: localUserStore.getName(), + roomId: this.RoomId, + tags: this.connection ? this.connection.getAllTag() : [] + }) + })); /* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { //this.load.tilemapTiledJSON('logo', tileset.imgUrl); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index b2eac975..f62b77a4 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -17,8 +17,6 @@ import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; -import {TagEvent, isTagEvent} from "./Api/Events/TagEvent"; -import type { TilesetEvent } from "./Api/Events/TilesetEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -42,18 +40,26 @@ interface WorkAdventureApi { displayBubble(): void; removeBubble(): void; registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void - getMapUrl(): Promise; - getUuid(): Promise; - getRoomId(): Promise; - getStartLayerName(): Promise; - getNickName(): Promise; - getTagUser(): Promise; - getMap(): Promise + getCurrentUser(): Promise + getCurrentRoom(): Promise //loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void } +interface User { + id: string | undefined + nickName: string | null + tags: string[] +} + +interface Room { + id: string + mapUrl: string + map: ITiledMap + startLayer: string | null +} + declare global { // eslint-disable-next-line no-var var WA: WorkAdventureApi @@ -101,12 +107,14 @@ class Popup { }, '*'); } } -function uuidv4() { + +/*function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); -} +}*/ + function getGameState(): Promise { if (immutableData) { return Promise.resolve(immutableData); @@ -131,34 +139,21 @@ function getDataLayer(): Promise { }) } -function getTag(): Promise { - return new Promise((resolver, thrower) => { - tagResolver.push((resolver)); - postToParent({ - type: "getTag", - data: undefined - }) - }) -} - const gameStateResolver: Array<(event: GameStateEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] -const tagResolver: Array<(event : TagEvent) => void> = [] let immutableData: GameStateEvent; -const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} - +//const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} +const callbackPlayerMoved: Array<(event: HasPlayerMovedEvent) => void> = [] function postToParent(content: IframeEvent) { window.parent.postMessage(content, "*") } -let playerUuid: string | undefined; window.WA = { onPlayerMove(callback: HasPlayerMovedEventCallback): void { - playerUuid = uuidv4(); - callbackPlayerMoved[playerUuid] = callback; + callbackPlayerMoved.push(callback); postToParent({ type: "onPlayerMove", data: undefined @@ -179,45 +174,17 @@ window.WA = { }) },*/ - getTagUser(): Promise { - return getTag().then((res) => { - return res.list; + getCurrentUser(): Promise { + return getGameState().then((gameState) => { + return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags}; }) }, - getMap(): Promise { - return getDataLayer().then((res) => { - return res.data as ITiledMap; - }) - }, - - getNickName(): Promise { - return getGameState().then((res) => { - return res.nickname; - }) - }, - - getMapUrl(): Promise { - return getGameState().then((res) => { - return res.mapUrl; - }) - }, - - getUuid(): Promise { - return getGameState().then((res) => { - return res.uuid; - }) - }, - - getRoomId(): Promise { - return getGameState().then((res) => { - return res.roomId; - }) - }, - - getStartLayerName(): Promise { - return getGameState().then((res) => { - return res.startLayerName; + getCurrentRoom(): Promise { + return getGameState().then((gameState) => { + return getDataLayer().then((mapJson) => { + return {id: gameState.roomId, map: mapJson.data as ITiledMap, mapUrl: gameState.mapUrl, startLayer: gameState.startLayerName}; + }) }) }, @@ -411,22 +378,18 @@ window.addEventListener('message', message => { resolver(payloadData); }) immutableData = payloadData; - } else if (payload.type == "hasPlayerMoved" && isHasPlayerMovedEvent(payloadData) && playerUuid) { - callbackPlayerMoved[playerUuid](payloadData) + } else if (payload.type == "hasPlayerMoved" && isHasPlayerMovedEvent(payloadData)) { + callbackPlayerMoved.forEach(callback => { + callback(payloadData); + }) } else if (payload.type == "dataLayer" && isDataLayerEvent(payloadData)) { dataLayerResolver.forEach(resolver => { resolver(payloadData); }) - } else if (payload.type == "menuItemClicked" && isMenuItemClickedEvent(payload.data)) { - const callback = menuCallbacks.get(payload.data.menuItem); + } else if (payload.type == "menuItemClicked" && isMenuItemClickedEvent(payloadData)) { + const callback = menuCallbacks.get(payloadData.menuItem); if (callback) { - callback(payload.data.menuItem) - } - } else { - if (payload.type == "tagList" && isTagEvent(payloadData)) { - tagResolver.forEach(resolver => { - resolver(payloadData); - }) + callback(payloadData.menuItem) } } } From c8e2416e081a5450b24b3498b384038ebb82cd6d Mon Sep 17 00:00:00 2001 From: GRL Date: Wed, 26 May 2021 10:41:33 +0200 Subject: [PATCH 044/189] documentation of getCurrentUser, getCurrentRoom and on working with group layer --- docs/maps/api-reference.md | 111 +++++++++++++------------------------ front/src/iframe_api.ts | 4 ++ 2 files changed, 44 insertions(+), 71 deletions(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 30d0f1ea..6a4dd7ab 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -236,8 +236,7 @@ mySound.play(config); mySound.stop(); ``` -### Show / Hide a layer - +### Show / Hide a layer ``` WA.showLayer(layerName : string): void WA.hideLayer(layerName : string) : void @@ -245,7 +244,6 @@ WA.hideLayer(layerName : string) : void These 2 methods can be used to show and hide a layer. Example : - ```javascript WA.showLayer('bottom'); //... @@ -260,8 +258,7 @@ WA.setProperty(layerName : string, propertyName : string, propertyValue : string Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`. -Example : - +Example : ```javascript WA.setProperty('wikiLayer', 'openWebsite', 'https://www.wikipedia.org/'); ``` @@ -286,74 +283,42 @@ Example : WA.onPlayerMove(console.log); ``` -### Getting the map - +### Getting informations on the current user ``` -getMap(): Promise +getCurrentUser(): Promise ``` - -Returns a promise that resolves to the JSON file of the map. Please note that if you modified the map (for instance by calling `WA.setProperty`, the data returned by `getMap` will contain those changes. +Return a promise that resolves to a `User` object with the following attributes : +* **id (string) :** ID of the current user +* **nickName (string) :** name displayed above the current user +* **tags (string[]) :** list of all the tags of the current user Example : ```javascript -WA.getMap().then((data) => console.log(data.layers)); +WA.getCurrentUser().then((user) => { + if (user.nickName === 'ABC') { + console.log(user.tags); + } +}) ``` -### Getting the url of the JSON file map - +### Getting informations on the current room ``` -getMapUrl(): Promise +getCurrentRoom(): Promise ``` - -Return a promise of the url of the JSON file map. +Return a promise that resolves to a `Room` object with the following attributes : +* **id (string) :** ID of the current room +* **map (ITiledMap) :** contains the JSON map file with the properties that were setted by the script if `setProperty` was called. +* **mapUrl (string) :** Url of the JSON map file +* **startLayer (string | null) :** Name of the layer where the current user started, only if different from `start` layer Example : ```javascript -WA.getMapUrl().then((mapUrl) => {console.log(mapUrl)}); -``` - -### Getting the roomID -``` -getRoomId(): Promise -``` -Return a promise of the ID of the current room. - -Example : -```javascript -WA.getRoomId().then((roomId) => console.log(roomId)); -``` - -### Getting the UUID of the current user -``` -getUuid(): Promise -``` -Return a promise of the ID of the current user. - -Example : -```javascript -WA.getUuid().then((uuid) => {console.log(uuid)}); -``` - -### Getting the nickname of the current user -``` -getNickName(): Promise -``` -Return a promise of the nickname of the current user. - -Example : -```javascript -WA.getNickName().then((nickname) => {console.log(nickname)}); -``` - -### Getting the name of the layer where the current user started (if other than start) -``` -getStartLayerName(): Promise -``` -Return a promise of the name of the layer where the current user started if the name is different than "start". - -Example : -```javascript -WA.getStartLayerName().then((starLayerName) => {console.log(starLayerName)}); +WA.getCurrentRoom((room) => { + if (room.id === '42') { + console.log(room.map); + window.open(room.mapUrl, '_blank'); + } +}) ``` ### Add a custom menu @@ -367,17 +332,21 @@ Example : WA.registerMenuCommand('About', () => { console.log("The About menu was clicked"); }); - -### Getting the list of tags of the current user -``` -getTagUser(): Promise ``` -Returns the tags of the current user. If the current user has no tag, returns an empty list. + +### Working with group layers +If you use group layers in your map, to reference a layer in a group you will need to use a `/` to join layer names together. Example : -```javascript -WA.getTagUser().then((tagList) => { - ... -}); -``` +
+
+ +
+
+ +The name of the layers of this map are : +* `entries/start` +* `bottom/ground/under` +* `bottom/build/carpet` +* `wall` \ No newline at end of file diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index f62b77a4..8da1fa23 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -201,6 +201,7 @@ window.WA = { } as ChatEvent }, '*'); }, + showLayer(layer: string) : void { window.parent.postMessage({ 'type' : 'showLayer', @@ -209,6 +210,7 @@ window.WA = { } as LayerEvent }, '*'); }, + hideLayer(layer: string) : void { window.parent.postMessage({ 'type' : 'hideLayer', @@ -217,6 +219,7 @@ window.WA = { } as LayerEvent }, '*'); }, + setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { window.parent.postMessage({ 'type' : 'setProperty', @@ -227,6 +230,7 @@ window.WA = { } as SetPropertyEvent }, '*'); }, + disablePlayerControls(): void { window.parent.postMessage({ 'type': 'disablePlayerControls' }, '*'); }, From e1f0192e617b8118474abfcf7382f1cefb6bd649 Mon Sep 17 00:00:00 2001 From: GRL Date: Wed, 26 May 2021 17:18:38 +0200 Subject: [PATCH 045/189] Adding and updating test map for metadata --- maps/tests/Metadata/ScriptMap.json | 219 --------------- maps/tests/Metadata/TagList.html | 19 -- maps/tests/Metadata/TagList.json | 254 ------------------ maps/tests/Metadata/getCurrentRoom.html | 16 ++ ...{getGameState.json => getCurrentRoom.json} | 46 ++-- maps/tests/Metadata/getCurrentUser.html | 15 ++ ...getGameState2.json => getCurrentUser.json} | 43 ++- maps/tests/Metadata/getGameState.html | 42 --- maps/tests/Metadata/getGameState2.html | 40 --- maps/tests/Metadata/script.js | 1 - 10 files changed, 87 insertions(+), 608 deletions(-) delete mode 100644 maps/tests/Metadata/ScriptMap.json delete mode 100644 maps/tests/Metadata/TagList.html delete mode 100644 maps/tests/Metadata/TagList.json create mode 100644 maps/tests/Metadata/getCurrentRoom.html rename maps/tests/Metadata/{getGameState.json => getCurrentRoom.json} (90%) create mode 100644 maps/tests/Metadata/getCurrentUser.html rename maps/tests/Metadata/{getGameState2.json => getCurrentUser.json} (86%) delete mode 100644 maps/tests/Metadata/getGameState.html delete mode 100644 maps/tests/Metadata/getGameState2.html delete mode 100644 maps/tests/Metadata/script.js diff --git a/maps/tests/Metadata/ScriptMap.json b/maps/tests/Metadata/ScriptMap.json deleted file mode 100644 index 93972a73..00000000 --- a/maps/tests/Metadata/ScriptMap.json +++ /dev/null @@ -1,219 +0,0 @@ -{ "compressionlevel":-1, - "height":10, - "infinite":false, - "layers":[ - { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "height":10, - "id":1, - "name":"start", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, - { - "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], - "height":10, - "id":2, - "name":"bottom", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, - { - "draworder":"topdown", - "id":5, - "name":"floorLayer", - "objects":[], - "opacity":1, - "type":"objectgroup", - "visible":true, - "x":0, - "y":0 - }], - "nextlayerid":10, - "nextobjectid":2, - "orientation":"orthogonal", - "properties":[ - { - "name":"script", - "type":"string", - "value":"script.js" - }], - "renderorder":"right-down", - "tiledversion":"1.4.3", - "tileheight":32, - "tilesets":[ - { - "columns":8, - "firstgid":1, - "image":"tileset_dungeon.png", - "imageheight":256, - "imagewidth":256, - "margin":0, - "name":"TDungeon", - "spacing":0, - "tilecount":64, - "tileheight":32, - "tiles":[ - { - "id":0, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":1, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":2, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":3, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":4, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":8, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":9, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":10, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":11, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":12, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":16, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":17, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":18, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":19, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":20, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }], - "tilewidth":32 - }, - { - "columns":8, - "firstgid":65, - "image":"floortileset.png", - "imageheight":288, - "imagewidth":256, - "margin":0, - "name":"Floor", - "spacing":0, - "tilecount":72, - "tileheight":32, - "tilewidth":32 - }], - "tilewidth":32, - "type":"map", - "version":1.4, - "width":10 -} \ No newline at end of file diff --git a/maps/tests/Metadata/TagList.html b/maps/tests/Metadata/TagList.html deleted file mode 100644 index 73bdc368..00000000 --- a/maps/tests/Metadata/TagList.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - -
- - \ No newline at end of file diff --git a/maps/tests/Metadata/TagList.json b/maps/tests/Metadata/TagList.json deleted file mode 100644 index cced49a3..00000000 --- a/maps/tests/Metadata/TagList.json +++ /dev/null @@ -1,254 +0,0 @@ -{ "compressionlevel":-1, - "height":10, - "infinite":false, - "layers":[ - { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "height":10, - "id":1, - "name":"start", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, - { - "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], - "height":10, - "id":2, - "name":"bottom", - "opacity":1, - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, - { - "data":[0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "height":10, - "id":4, - "name":"metadata", - "opacity":1, - "properties":[ - { - "name":"openWebsite", - "type":"string", - "value":"TagList.html" - }, - { - "name":"openWebsiteAllowApi", - "type":"bool", - "value":true - }], - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, - { - "draworder":"topdown", - "id":5, - "name":"floorLayer", - "objects":[ - { - "height":131.903791109293, - "id":1, - "name":"", - "rotation":0, - "text": - { - "fontfamily":"Sans Serif", - "pixelsize":9, - "text":"Test : \nWalk on the grass, an iframe open, click on the 'Get Tag List' button.\nResult : \nThe list of the tag is displayed in the iframe.\n\n\n", - "wrap":true - }, - "type":"", - "visible":true, - "width":305.097705765524, - "x":14.750638909983, - "y":188.268561247737 - }], - "opacity":1, - "type":"objectgroup", - "visible":true, - "x":0, - "y":0 - }], - "nextlayerid":10, - "nextobjectid":2, - "orientation":"orthogonal", - "renderorder":"right-down", - "tiledversion":"1.4.3", - "tileheight":32, - "tilesets":[ - { - "columns":8, - "firstgid":1, - "image":"tileset_dungeon.png", - "imageheight":256, - "imagewidth":256, - "margin":0, - "name":"TDungeon", - "spacing":0, - "tilecount":64, - "tileheight":32, - "tiles":[ - { - "id":0, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":1, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":2, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":3, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":4, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":8, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":9, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":10, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":11, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":12, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":16, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":17, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":18, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":19, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }, - { - "id":20, - "properties":[ - { - "name":"collides", - "type":"bool", - "value":true - }] - }], - "tilewidth":32 - }, - { - "columns":8, - "firstgid":65, - "image":"floortileset.png", - "imageheight":288, - "imagewidth":256, - "margin":0, - "name":"Floor", - "spacing":0, - "tilecount":72, - "tileheight":32, - "tilewidth":32 - }], - "tilewidth":32, - "type":"map", - "version":1.4, - "width":10 -} \ No newline at end of file diff --git a/maps/tests/Metadata/getCurrentRoom.html b/maps/tests/Metadata/getCurrentRoom.html new file mode 100644 index 00000000..b290c6a4 --- /dev/null +++ b/maps/tests/Metadata/getCurrentRoom.html @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState.json b/maps/tests/Metadata/getCurrentRoom.json similarity index 90% rename from maps/tests/Metadata/getGameState.json rename to maps/tests/Metadata/getCurrentRoom.json index a005ee8a..c14bb946 100644 --- a/maps/tests/Metadata/getGameState.json +++ b/maps/tests/Metadata/getCurrentRoom.json @@ -9,6 +9,24 @@ "height":10, "infinite":false, "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":10, + "name":"HereYouAppered", + "opacity":1, + "properties":[ + { + "name":"startLayer", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, { "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, @@ -43,7 +61,7 @@ { "name":"openWebsite", "type":"string", - "value":"getGameState.html" + "value":"getCurrentRoom.html" }, { "name":"openWebsiteAllowApi", @@ -56,31 +74,13 @@ "x":0, "y":0 }, - { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "height":10, - "id":8, - "name":"exit", - "opacity":1, - "properties":[ - { - "name":"exitUrl", - "type":"string", - "value":"getGameState2.json#HereYouAppear" - }], - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, { "draworder":"topdown", "id":5, "name":"floorLayer", "objects":[ { - "height":218.263975699515, + "height":191.607568521364, "id":1, "name":"", "rotation":0, @@ -88,14 +88,14 @@ { "fontfamily":"Sans Serif", "pixelsize":9, - "text":"Start the test : \nWalk on the grass, an iframe open.\n\nTest : \nClick on the 'nickname' button.\nResult : \nYour nickname appears.\n\nTest : \nClick on the 'roomID' button.\nResult : \nAn ID appears.\n\nTest : \nClick on the 'UUID' button.\nResult : \nAn ID appears.\n\nFinally : \nWalk on the red tiles to continue the testing.\n\n", + "text":"Test : \nWalk on the grass and open the console.\n\nResult : \nYou should see a console.log() of the following attributes : \n\t- id : ID of the current room\n\t- map : data of the JSON file of the map\n\t- mapUrl : url of the JSON file of the map\n\t- startLayer : Name of the layer where the current user started (HereYouAppered)\n\n\n", "wrap":true }, "type":"", "visible":true, "width":305.097705765524, "x":14.750638909983, - "y":101.908376657515 + "y":128.564783835666 }], "opacity":1, "type":"objectgroup", @@ -103,7 +103,7 @@ "x":0, "y":0 }], - "nextlayerid":9, + "nextlayerid":11, "nextobjectid":2, "orientation":"orthogonal", "renderorder":"right-down", diff --git a/maps/tests/Metadata/getCurrentUser.html b/maps/tests/Metadata/getCurrentUser.html new file mode 100644 index 00000000..318fdf1b --- /dev/null +++ b/maps/tests/Metadata/getCurrentUser.html @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState2.json b/maps/tests/Metadata/getCurrentUser.json similarity index 86% rename from maps/tests/Metadata/getGameState2.json rename to maps/tests/Metadata/getCurrentUser.json index 04127918..9efd0d09 100644 --- a/maps/tests/Metadata/getGameState2.json +++ b/maps/tests/Metadata/getCurrentUser.json @@ -22,10 +22,10 @@ "y":0 }, { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], "height":10, - "id":9, - "name":"HereYouAppear", + "id":2, + "name":"bottom", "opacity":1, "type":"tilelayer", "visible":true, @@ -34,11 +34,17 @@ "y":0 }, { - "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, - "id":2, - "name":"bottom", + "id":9, + "name":"exit", "opacity":1, + "properties":[ + { + "name":"exitUrl", + "type":"string", + "value":"getCurrentRoom.json#HereYouAppered" + }], "type":"tilelayer", "visible":true, "width":10, @@ -55,7 +61,7 @@ { "name":"openWebsite", "type":"string", - "value":"getGameState2.html" + "value":"getCurrentUser.html" }, { "name":"openWebsiteAllowApi", @@ -74,7 +80,7 @@ "name":"floorLayer", "objects":[ { - "height":200.31900227817, + "height":151.839293303871, "id":1, "name":"", "rotation":0, @@ -82,14 +88,14 @@ { "fontfamily":"Sans Serif", "pixelsize":9, - "text":"Start the test : \nWalk on the grass, an iframe open.\n\nTest : \nClick on the 'startLayer' button.\nResult : \nThe name of the layer where you start appears. (only work when the start layer is not 'start')\n\nTest : \nClick on the 'mapUrl' button.\nResult : \nThe url of the JSON file of the map is displayed in the console.log().\n\nTest : \nClick on the 'Map' button.\nResult : \nThe JSON file map appears.\n\n\n", + "text":"Test : \nWalk on the grass, open the console.\n\nResut : \nYou should see a console.log() of the following attributes :\n\t- id : ID of the current user\n\t- nickName : Name of the current user\n\t- tags : List of tags of the current user\n\nFinally : \nWalk on the red tile and continue the test in an another room.", "wrap":true }, "type":"", "visible":true, "width":305.097705765524, "x":14.750638909983, - "y":119.85335007886 + "y":159.621625296353 }], "opacity":1, "type":"objectgroup", @@ -264,6 +270,23 @@ "spacing":0, "tilecount":72, "tileheight":32, + "tiles":[ + { + "animation":[ + { + "duration":100, + "tileid":9 + }, + { + "duration":100, + "tileid":64 + }, + { + "duration":100, + "tileid":55 + }], + "id":0 + }], "tilewidth":32 }], "tilewidth":32, diff --git a/maps/tests/Metadata/getGameState.html b/maps/tests/Metadata/getGameState.html deleted file mode 100644 index f11dab17..00000000 --- a/maps/tests/Metadata/getGameState.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - -
- - -
- - -
- - - - \ No newline at end of file diff --git a/maps/tests/Metadata/getGameState2.html b/maps/tests/Metadata/getGameState2.html deleted file mode 100644 index e8529617..00000000 --- a/maps/tests/Metadata/getGameState2.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - -
- - -
- - -
- - - - \ No newline at end of file diff --git a/maps/tests/Metadata/script.js b/maps/tests/Metadata/script.js deleted file mode 100644 index d04d7952..00000000 --- a/maps/tests/Metadata/script.js +++ /dev/null @@ -1 +0,0 @@ -console.log('script chargé !!!!!'); \ No newline at end of file From 6dcb0d3750f78838ac03f89131bce9132489869c Mon Sep 17 00:00:00 2001 From: GRL Date: Thu, 27 May 2021 17:06:39 +0200 Subject: [PATCH 046/189] first step to change tile --- front/src/Api/Events/ChangeTileEvent.ts | 14 +- front/src/Phaser/Game/GameScene.ts | 17 +- front/src/iframe_api.ts | 21 +- maps/tests/Metadata/changeTile.html | 28 +++ maps/tests/Metadata/changeTile.json | 275 ++++++++++++++++++++++++ 5 files changed, 334 insertions(+), 21 deletions(-) create mode 100644 maps/tests/Metadata/changeTile.html create mode 100644 maps/tests/Metadata/changeTile.json diff --git a/front/src/Api/Events/ChangeTileEvent.ts b/front/src/Api/Events/ChangeTileEvent.ts index 23599881..4a071403 100644 --- a/front/src/Api/Events/ChangeTileEvent.ts +++ b/front/src/Api/Events/ChangeTileEvent.ts @@ -1,12 +1,14 @@ import * as tg from "generic-type-guard"; export const isChangeTileEvent = - new tg.IsInterface().withProperties({ - x: tg.isNumber, - y: tg.isNumber, - tile: tg.isUnion(tg.isNumber, tg.isString), - layer: tg.isUnion(tg.isNumber, tg.isString) - }).get(); + tg.isArray( + new tg.IsInterface().withProperties({ + x: tg.isNumber, + y: tg.isNumber, + tile: tg.isUnion(tg.isNumber, tg.isString), + layer: tg.isString + }).get() + ); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index b314fe3b..cb820ba4 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -890,19 +890,12 @@ ${escapedMessage} this.userInputManager.restoreControls(); })) -/* this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url: string) => { - this.loadNextGame(url).then(() => { - this.events.once(EVENT_TYPE.POST_UPDATE, () => { - this.onMapExit(url); - }) - }) - }))*/ - - this.iframeSubscriptionList.push(iframeListener.updateTileEvent.subscribe(event => { + this.iframeSubscriptionList.push(iframeListener.changeTileStream.subscribe(event => { for (const eventTile of event) { const layer = this.gameMap.findPhaserLayer(eventTile.layer); if (layer) { - const tile = layer.getTileAt(eventTile.x, eventTile.y) + console.log('layer : ', layer); + const tile = layer.getTileAt(eventTile.x, eventTile.y, true) if (typeof eventTile.tile == "string") { const tileIndex = this.getIndexForTileType(eventTile.tile); if (tileIndex) { @@ -911,11 +904,11 @@ ${escapedMessage} return } } else { - tile.index = eventTile.tile + tile.index = eventTile.tile //+ firsrtgid du layer } } } - this.scene.scene.sys.game.events.emit("contextrestored") + //this.dirty = true; })) let scriptedBubbleSprite: Sprite; diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index a390e616..b8b5ccdf 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -44,9 +44,10 @@ interface WorkAdventureApi { displayBubble(): void; removeBubble(): void; loadSound(url : string): Sound; - registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void - getCurrentUser(): Promise - getCurrentRoom(): Promise + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void; + getCurrentUser(): Promise; + getCurrentRoom(): Promise; + changeTile(tiles: TileDescriptor[]): void; //loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void @@ -65,6 +66,13 @@ interface Room { startLayer: string | null } +interface TileDescriptor { + x: number + y: number + tile: number | string + layer: string +} + declare global { // eslint-disable-next-line no-var var WA: WorkAdventureApi @@ -221,6 +229,13 @@ window.WA = { }) }, + changeTile(tiles: TileDescriptor[]) { + postToParent({ + type: 'changeTile', + data: tiles + }) + }, + /** * Send a message in the chat. * Only the local user will receive this message. diff --git a/maps/tests/Metadata/changeTile.html b/maps/tests/Metadata/changeTile.html new file mode 100644 index 00000000..214908a9 --- /dev/null +++ b/maps/tests/Metadata/changeTile.html @@ -0,0 +1,28 @@ + + + + + + + + + \ No newline at end of file diff --git a/maps/tests/Metadata/changeTile.json b/maps/tests/Metadata/changeTile.json new file mode 100644 index 00000000..48f57e0f --- /dev/null +++ b/maps/tests/Metadata/changeTile.json @@ -0,0 +1,275 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":1, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[33, 34, 34, 34, 34, 34, 34, 34, 34, 35, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51], + "height":10, + "id":2, + "name":"bottom", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":4, + "name":"metadata", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"changeTile.html" + }, + { + "name":"openWebsiteAllowApi", + "type":"bool", + "value":true + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 65, 65, 65, 65, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":8, + "name":"changeTile", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":5, + "name":"floorLayer", + "objects":[ + { + "height":159.866671635267, + "id":1, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":9, + "text":"Test : \nWalk on the grass\n\nResult : \nTiles of the first left colum become red tile (tile find by Number)\nTiles of the below the grass become blue (tile find by String)\n", + "wrap":true + }, + "type":"", + "visible":true, + "width":287.674838251912, + "x":32.5473600365393, + "y":160.305680721763 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":9, + "nextobjectid":2, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.4.3", + "tileheight":32, + "tilesets":[ + { + "columns":8, + "firstgid":1, + "image":"tileset_dungeon.png", + "imageheight":256, + "imagewidth":256, + "margin":0, + "name":"TDungeon", + "spacing":0, + "tilecount":64, + "tileheight":32, + "tiles":[ + { + "id":0, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":1, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":2, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":3, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":4, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":8, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":9, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":10, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":11, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":12, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":16, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":17, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":18, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":19, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }, + { + "id":20, + "properties":[ + { + "name":"collides", + "type":"bool", + "value":true + }] + }], + "tilewidth":32 + }, + { + "columns":8, + "firstgid":65, + "image":"floortileset.png", + "imageheight":288, + "imagewidth":256, + "margin":0, + "name":"Floor", + "spacing":0, + "tilecount":72, + "tileheight":32, + "tiles":[ + { + "id":34, + "type":"Red" + }, + { + "id":44, + "type":"blue" + }], + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.4, + "width":10 +} \ No newline at end of file From 5d8d729bd73711977e3b6a562e34b654961f4893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Thu, 27 May 2021 18:25:27 +0200 Subject: [PATCH 047/189] Uncommenting action --- front/src/Connexion/RoomConnection.ts | 8 ++++---- front/src/Phaser/Game/GameScene.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 58c62a78..159db5a2 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -177,9 +177,9 @@ export class RoomConnection implements RoomConnection { } else if (message.hasWorldfullmessage()) { worldFullMessageStream.onMessage(); this.closed = true; - } else if (message.hasWorldconnexionmessage()) { - worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); - this.closed = true; + } else if (message.hasWorldconnexionmessage()) { + worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage()); + this.closed = true; } else if (message.hasWebrtcsignaltoclientmessage()) { this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage()); } else if (message.hasWebrtcscreensharingsignaltoclientmessage()) { @@ -617,7 +617,7 @@ export class RoomConnection implements RoomConnection { this.socket.send(clientToServerMessage.serializeBinary().buffer); } - public getAllTag() : string[] { + public getAllTags() : string[] { return this.tags; } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 1e4c55f5..a785b7f6 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -923,7 +923,7 @@ ${escapedMessage} uuid: localUserStore.getLocalUser()?.uuid, nickname: localUserStore.getName(), roomId: this.RoomId, - tags: this.connection ? this.connection.getAllTag() : [] + tags: this.connection ? this.connection.getAllTags() : [] }) })); From 1a1ab30574ca31759193c81f5b1017cb131ca7ca Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 25 May 2021 13:47:41 +0200 Subject: [PATCH 048/189] extraction idea # Conflicts: # front/src/Api/ScriptUtils.ts # front/src/iframe_api.ts --- front/src/Api/iframe/chatmessage.ts | 35 ++++++++++++++++ front/src/Api/iframe/iframe-registration.ts | 30 ++++++++++++++ front/src/Api/iframe/zone-events.ts | 27 +++++++++++++ front/src/iframe_api.ts | 45 ++++++++++++++------- 4 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 front/src/Api/iframe/chatmessage.ts create mode 100644 front/src/Api/iframe/iframe-registration.ts create mode 100644 front/src/Api/iframe/zone-events.ts diff --git a/front/src/Api/iframe/chatmessage.ts b/front/src/Api/iframe/chatmessage.ts new file mode 100644 index 00000000..934fb1b1 --- /dev/null +++ b/front/src/Api/iframe/chatmessage.ts @@ -0,0 +1,35 @@ +import { ChatEvent } from '../Events/ChatEvent' +import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent' +import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration" + +let chatMessageCallback: (event: string) => void | undefined + +class WorkadvntureChatCommands { + + sendChatMessage(message: string, author: string) { + sendToWorkadventure({ + type: 'chat', + data: { + 'message': message, + 'author': author + } as ChatEvent + }) + } + + /** + * Listen to messages sent by the local user, in the chat. + */ + onChatMessage(callback: (message: string) => void) { + chatMessageCallback = callback + } +} + +export const commands = registerWorkadventureCommand(new WorkadvntureChatCommands()) +export const callbacks = registerWorkadvntureCallback([{ + callback: (event: UserInputChatEvent) => { + chatMessageCallback?.(event.message) + }, + type: "userInputChat", + typeChecker: isUserInputChatEvent +}]) + diff --git a/front/src/Api/iframe/iframe-registration.ts b/front/src/Api/iframe/iframe-registration.ts new file mode 100644 index 00000000..ceb6daf4 --- /dev/null +++ b/front/src/Api/iframe/iframe-registration.ts @@ -0,0 +1,30 @@ +import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; +import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api" +export function registerWorkadventureCommand(commnds: T): T { + const commandPrototype = Object.getPrototypeOf(commnds); + const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor"); + for (const key of commandClassPropertyNames) { + window.WA[key as keyof WorkAdventureApi] = commandPrototype[key] as never + } + return commnds +} + + +export function registerWorkadvntureCallback(callbacks: Array<{ + type: keyof IframeResponseEventMap, + typeChecker: Function, + callback: T +}>) { + for (const callback of callbacks) { + registeredCallbacks[callback.type] = { + typeChecker: callback.typeChecker, + callback: callback.callback + } + } + return callbacks +} + + +export function sendToWorkadventure(content: IframeEvent) { + window.parent.postMessage(content, "*") +} \ No newline at end of file diff --git a/front/src/Api/iframe/zone-events.ts b/front/src/Api/iframe/zone-events.ts new file mode 100644 index 00000000..11df18d9 --- /dev/null +++ b/front/src/Api/iframe/zone-events.ts @@ -0,0 +1,27 @@ +import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent' +import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration" + +class WorkadventureZoneCommands { + + onEnterZone(name: string, callback: () => void): void { + + + } + onLeaveZone(name: string, callback: () => void): void { + + } + +} + + + + +export const commands = registerWorkadventureCommand(new WorkadventureZoneCommands()) +export const callbacks = registerWorkadvntureCallback([{ + callback: (enterEvent: EnterLeaveEvent) => { + + }, + type: "enterEvent", + typeChecker: isEnterLeaveEvent +},]) + diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index df37e53d..fbf3ec4f 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,5 +1,5 @@ import type { ChatEvent } from "./Api/Events/ChatEvent"; -import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; +import { IframeEvent, IframeEventMap, IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; import { Subject } from "rxjs"; import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent"; @@ -10,9 +10,19 @@ import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import type { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -interface WorkAdventureApi { - sendChatMessage(message: string, author: string): void; - onChatMessage(callback: (message: string) => void): void; +const importType = Promise.all([ + import("./Api/iframe/chatmessage"), + import("./Api/iframe/zone-events") +]) +type UnPromise

= P extends Promise ? T : P + +type WorkadventureCommandClasses = UnPromise[number]["commands"]; +type KeysOfUnion = T extends T ? keyof T : never +type ObjectWithKeyOfUnion = O extends O ? (Key extends keyof O ? O[Key] : never) : never + +type WorkAdventureApiFiles = { [Key in KeysOfUnion]: ObjectWithKeyOfUnion }; + +export interface WorkAdventureApi extends WorkAdventureApiFiles { onEnterZone(name: string, callback: () => void): void; onLeaveZone(name: string, callback: () => void): void; openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; @@ -26,10 +36,15 @@ interface WorkAdventureApi { removeBubble(): void; } -declare global { - // eslint-disable-next-line no-var - var WA: WorkAdventureApi + + +declare global { + + interface Window { + WA: WorkAdventureApi + } + let WA: WorkAdventureApi } type ChatMessageCallback = (message: string) => void; @@ -172,14 +187,7 @@ window.WA = { popups.set(popupId, popup) return popup; }, - /** - * Listen to messages sent by the local user, in the chat. - */ - onChatMessage(callback: ChatMessageCallback): void { - userInputChatStream.subscribe((userInputChatEvent) => { - callback(userInputChatEvent.message); - }); - }, + ...({} as WorkAdventureApiFiles), onEnterZone(name: string, callback: () => void): void { let subject = enterStreams.get(name); if (subject === undefined) { @@ -196,6 +204,7 @@ window.WA = { } subject.subscribe(callback); }, + } window.addEventListener('message', message => { @@ -209,6 +218,12 @@ window.addEventListener('message', message => { if (isIframeResponseEventWrapper(payload)) { const payloadData = payload.data; + + if (registeredCallbacks[payload.type] && registeredCallbacks[payload.type]?.typeChecker(payloadData)) { + registeredCallbacks[payload.type]?.callback(payloadData) + return + } + if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) { userInputChatStream.next(payloadData); } else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) { From 2de2d114a13d8df78b69fe43dd3fa801358b3b3f Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 00:24:08 +0200 Subject: [PATCH 049/189] added typedef for subobject types extracted popup functions # Conflicts: # front/package-lock.json # front/package.json # front/src/iframe_api.ts --- front/src/Api/iframe/IframeApiContribution.ts | 48 ++++++ front/src/Api/iframe/chatmessage.ts | 32 ++-- front/src/Api/iframe/iframe-registration.ts | 7 +- front/src/Api/iframe/popup.ts | 148 +++++++++++++++++ front/src/Api/iframe/zone-events.ts | 57 +++++-- front/src/iframe_api.ts | 151 ++++++------------ 6 files changed, 304 insertions(+), 139 deletions(-) create mode 100644 front/src/Api/iframe/IframeApiContribution.ts create mode 100644 front/src/Api/iframe/popup.ts diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts new file mode 100644 index 00000000..ee2ecff5 --- /dev/null +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -0,0 +1,48 @@ +import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; +import type * as tg from "generic-type-guard"; + + +export type PossibleSubobjects = "zone" | "chat" | "ui" + +export function sendToWorkadventure(content: IframeEvent) { + window.parent.postMessage(content, "*") +} +type GuardedType> = Guard extends tg.TypeGuard ? T : never + +export function apiCallback>(callbackData: IframeCallbackContribution) { + + return callbackData +} + +export interface IframeCallbackContribution, T = GuardedType> { + + type: keyof IframeResponseEventMap, + typeChecker: Guard, + callback: (payloadData: T) => void +} + + +/** + * !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly + * + * + */ + +export abstract class IframeApiContribution>>, + readonly subObjectIdentifier: PossibleSubobjects, + readonly addMethodsAtRoot: boolean | undefined +}> { + + abstract callbacks: T["callbacks"] + + /** + * @deprecated this is only there for backwards compatibility on new apis this should be set to false or ignored + */ + addMethodsAtRoot = false + + abstract readonly subObjectIdentifier: T["subObjectIdentifier"] + +} \ No newline at end of file diff --git a/front/src/Api/iframe/chatmessage.ts b/front/src/Api/iframe/chatmessage.ts index 934fb1b1..7f4f045a 100644 --- a/front/src/Api/iframe/chatmessage.ts +++ b/front/src/Api/iframe/chatmessage.ts @@ -1,10 +1,24 @@ import { ChatEvent } from '../Events/ChatEvent' import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent' -import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration" +import { } from "./iframe-registration" +import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution' -let chatMessageCallback: (event: string) => void | undefined -class WorkadvntureChatCommands { +class WorkadvntureChatCommands extends IframeApiContribution { + readonly subObjectIdentifier = 'chat' + + readonly addMethodsAtRoot = true + + chatMessageCallback?: (event: string) => void + + callbacks = [apiCallback({ + callback: (event: UserInputChatEvent) => { + this.chatMessageCallback?.(event.message) + }, + type: "userInputChat", + typeChecker: isUserInputChatEvent + })] + sendChatMessage(message: string, author: string) { sendToWorkadventure({ @@ -20,16 +34,8 @@ class WorkadvntureChatCommands { * Listen to messages sent by the local user, in the chat. */ onChatMessage(callback: (message: string) => void) { - chatMessageCallback = callback + this.chatMessageCallback = callback } } -export const commands = registerWorkadventureCommand(new WorkadvntureChatCommands()) -export const callbacks = registerWorkadvntureCallback([{ - callback: (event: UserInputChatEvent) => { - chatMessageCallback?.(event.message) - }, - type: "userInputChat", - typeChecker: isUserInputChatEvent -}]) - +export default new WorkadvntureChatCommands() \ No newline at end of file diff --git a/front/src/Api/iframe/iframe-registration.ts b/front/src/Api/iframe/iframe-registration.ts index ceb6daf4..ea9ce5ad 100644 --- a/front/src/Api/iframe/iframe-registration.ts +++ b/front/src/Api/iframe/iframe-registration.ts @@ -1,6 +1,6 @@ import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api" -export function registerWorkadventureCommand(commnds: T): T { +/*export function registerWorkadventureCommand(commnds: T): T { const commandPrototype = Object.getPrototypeOf(commnds); const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor"); for (const key of commandClassPropertyNames) { @@ -8,7 +8,7 @@ export function registerWorkadventureCommand(commnds: T): T { } return commnds } - +*/ export function registerWorkadvntureCallback(callbacks: Array<{ type: keyof IframeResponseEventMap, @@ -25,6 +25,3 @@ export function registerWorkadvntureCallback(callbacks: Arra } -export function sendToWorkadventure(content: IframeEvent) { - window.parent.postMessage(content, "*") -} \ No newline at end of file diff --git a/front/src/Api/iframe/popup.ts b/front/src/Api/iframe/popup.ts new file mode 100644 index 00000000..72ee87c7 --- /dev/null +++ b/front/src/Api/iframe/popup.ts @@ -0,0 +1,148 @@ +import { isButtonClickedEvent } from '../Events/ButtonClickedEvent'; +import { ClosePopupEvent } from '../Events/ClosePopupEvent'; +import { apiCallback, IframeApiContribution, IframeCallbackContribution, sendToWorkadventure } from './IframeApiContribution'; +import zoneCommands from "./zone-events" +class Popup { + constructor(private id: number) { + } + + /** + * Closes the popup + */ + public close(): void { + window.parent.postMessage({ + 'type': 'closePopup', + 'data': { + 'popupId': this.id, + } as ClosePopupEvent + }, '*'); + } +} + +type ButtonClickedCallback = (popup: Popup) => void; +interface ButtonDescriptor { + /** + * The label of the button + */ + label: string, + /** + * The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled" + */ + className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled", + /** + * Callback called if the button is pressed + */ + callback: ButtonClickedCallback, +} +let popupId = 0; +const popups: Map = new Map(); +const popupCallbacks: Map> = new Map>(); + +interface ZonedPopupOptions { + zone: string + objectLayerName?: string, + popupText: string, + delay?: number + popupOptions: Array +} + + +class PopupApiContribution extends IframeApiContribution { + + readonly subObjectIdentifier = "ui" + + readonly addMethodsAtRoot = true + callbacks = [apiCallback({ + type: "buttonClickedEvent", + typeChecker: isButtonClickedEvent, + callback: (payloadData) => { + const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId); + const popup = popups.get(payloadData.popupId); + if (popup === undefined) { + throw new Error('Could not find popup with ID "' + payloadData.popupId + '"'); + } + if (callback) { + callback(popup); + } + } + })]; + + + openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup { + popupId++; + const popup = new Popup(popupId); + const btnMap = new Map void>(); + popupCallbacks.set(popupId, btnMap); + let id = 0; + for (const button of buttons) { + const callback = button.callback; + if (callback) { + btnMap.set(id, () => { + callback(popup); + }); + } + id++; + } + + sendToWorkadventure({ + 'type': 'openPopup', + 'data': { + popupId, + targetObject, + message, + buttons: buttons.map((button) => { + return { + label: button.label, + className: button.className + }; + }) + } + }); + + popups.set(popupId, popup) + return popup; + } + + + + popupInZone(options: ZonedPopupOptions) { + const objectLayerName = options.objectLayerName || options.zone + + let lastOpened = 0; + + let popup: Popup | undefined; + zoneCommands.onEnterZone(options.zone, () => { + if (options.delay) { + if (lastOpened + options.delay > Date.now()) { + return; + } + } + lastOpened = Date.now(); + popup = this.openPopup(objectLayerName, options.popupText, options.popupOptions.map(option => { + const callback = option.callback; + const popupOptions = { + ...option, + className: option.className || 'normal', + callback: () => { + if (callback && popup) { + callback(popup); + } + popup?.close(); + popup = undefined; + } + }; + + return popupOptions; + })); + }); + zoneCommands.onLeaveZone(options.zone, () => { + if (popup) { + popup.close(); + popup = undefined; + } + }); + } + +} + +export default new PopupApiContribution() \ No newline at end of file diff --git a/front/src/Api/iframe/zone-events.ts b/front/src/Api/iframe/zone-events.ts index 11df18d9..8f66b45a 100644 --- a/front/src/Api/iframe/zone-events.ts +++ b/front/src/Api/iframe/zone-events.ts @@ -1,27 +1,54 @@ import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent' -import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration" +import { apiCallback as apiCallback, IframeApiContribution } from './IframeApiContribution' +import { Subject } from "rxjs"; + + +const enterStreams: Map> = new Map>(); +const leaveStreams: Map> = new Map>(); + +class WorkadventureZoneCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "zone" + + readonly addMethodsAtRoot = true + callbacks = [ + apiCallback({ + callback: (payloadData: EnterLeaveEvent) => { + enterStreams.get(payloadData.name)?.next(); + }, + type: "enterEvent", + typeChecker: isEnterLeaveEvent + }), + apiCallback({ + type: "leaveEvent", + typeChecker: isEnterLeaveEvent, + callback: (payloadData) => { + leaveStreams.get(payloadData.name)?.next(); + } + }) + + ] -class WorkadventureZoneCommands { onEnterZone(name: string, callback: () => void): void { - + let subject = enterStreams.get(name); + if (subject === undefined) { + subject = new Subject(); + enterStreams.set(name, subject); + } + subject.subscribe(callback); } onLeaveZone(name: string, callback: () => void): void { - + let subject = leaveStreams.get(name); + if (subject === undefined) { + subject = new Subject(); + leaveStreams.set(name, subject); + } + subject.subscribe(callback); } } - - -export const commands = registerWorkadventureCommand(new WorkadventureZoneCommands()) -export const callbacks = registerWorkadvntureCallback([{ - callback: (enterEvent: EnterLeaveEvent) => { - - }, - type: "enterEvent", - typeChecker: isEnterLeaveEvent -},]) - +export default new WorkadventureZoneCommands(); \ No newline at end of file diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index fbf3ec4f..b3126cbb 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,23 +9,54 @@ import type { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import type { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; +import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; +import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; +import { OpenCoWebSiteEvent, OpenCoWebSiteOptionsEvent } from "./Api/Events/OpenCoWebSiteEvent"; +import { LoadPageEvent } from './Api/Events/LoadPageEvent'; +import { isMenuItemClickedEvent } from './Api/Events/MenuItemClickedEvent'; +import { MenuItemRegisterEvent } from './Api/Events/MenuItemRegisterEvent'; +import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent'; +import { updateTile, UpdateTileEvent } from './Api/Events/ApiUpdateTileEvent'; +import { isMessageReferenceEvent, removeTriggerMessage, triggerMessage, TriggerMessageCallback, TriggerMessageEvent } from './Api/Events/TriggerMessageEvent'; +import { HasMovedEvent, HasMovedEventCallback, isHasMovedEvent } from './Api/Events/HasMovedEvent'; const importType = Promise.all([ + import("./Api/iframe/popup"), import("./Api/iframe/chatmessage"), import("./Api/iframe/zone-events") ]) -type UnPromise

= P extends Promise ? T : P -type WorkadventureCommandClasses = UnPromise[number]["commands"]; +type PromiseReturnType

= P extends Promise ? T : P + +type WorkadventureCommandClasses = PromiseReturnType[number]["default"]; + type KeysOfUnion = T extends T ? keyof T : never -type ObjectWithKeyOfUnion = O extends O ? (Key extends keyof O ? O[Key] : never) : never -type WorkAdventureApiFiles = { [Key in KeysOfUnion]: ObjectWithKeyOfUnion }; +type ObjectWithKeyOfUnion = O extends O ? (Key extends keyof O ? O[Key] : never) : never + +type ApiKeys = KeysOfUnion; + +type ObjectOfKey = O extends O ? (Key extends keyof O ? O : never) : never + +type ShouldAddAttribute = ObjectWithKeyOfUnion; + +type WorkadventureFunctions = { [K in ApiKeys]: ObjectWithKeyOfUnion extends Function ? K : never }[ApiKeys] + +type WorkadventureFunctionsFilteredByRoot = { [K in WorkadventureFunctions]: ObjectOfKey["addMethodsAtRoot"] extends true ? K : never }[WorkadventureFunctions] + + +type JustMethodKeys = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T]; +type JustMethods = Pick>; + +type SubObjectTypes = { + [importCl in WorkadventureCommandClasses as importCl["subObjectIdentifier"]]: JustMethods; +}; + +type WorkAdventureApiFiles = { + [Key in WorkadventureFunctionsFilteredByRoot]: ShouldAddAttribute +} & SubObjectTypes export interface WorkAdventureApi extends WorkAdventureApiFiles { - onEnterZone(name: string, callback: () => void): void; - onLeaveZone(name: string, callback: () => void): void; - openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; openTab(url : string): void; goToPage(url : string): void; openCoWebSite(url : string): void; @@ -47,47 +78,11 @@ declare global { let WA: WorkAdventureApi } -type ChatMessageCallback = (message: string) => void; -type ButtonClickedCallback = (popup: Popup) => void; - const userInputChatStream: Subject = new Subject(); -const enterStreams: Map> = new Map>(); -const leaveStreams: Map> = new Map>(); -const popups: Map = new Map(); -const popupCallbacks: Map> = new Map>(); -let popupId = 0; -interface ButtonDescriptor { - /** - * The label of the button - */ - label: string, - /** - * The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled" - */ - className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled", - /** - * Callback called if the button is pressed - */ - callback: ButtonClickedCallback, -} -class Popup { - constructor(private id: number) { - } - /** - * Closes the popup - */ - public close(): void { - window.parent.postMessage({ - 'type': 'closePopup', - 'data': { - 'popupId': this.id, - } as ClosePopupEvent - }, '*'); - } -} + window.WA = { /** @@ -152,59 +147,16 @@ window.WA = { }, '*'); }, - openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup { - popupId++; - const popup = new Popup(popupId); - const btnMap = new Map void>(); - popupCallbacks.set(popupId, btnMap); - let id = 0; - for (const button of buttons) { - const callback = button.callback; - if (callback) { - btnMap.set(id, () => { - callback(popup); - }); - } - id++; - } - - + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { + menuCallbacks.set(commandDescriptor, callback); window.parent.postMessage({ - 'type': 'openPopup', + 'type': 'registerMenuCommand', 'data': { - popupId, - targetObject, - message, - buttons: buttons.map((button) => { - return { - label: button.label, - className: button.className - }; - }) - } as OpenPopupEvent + menutItem: commandDescriptor + } as MenuItemRegisterEvent }, '*'); - - popups.set(popupId, popup) - return popup; }, ...({} as WorkAdventureApiFiles), - onEnterZone(name: string, callback: () => void): void { - let subject = enterStreams.get(name); - if (subject === undefined) { - subject = new Subject(); - enterStreams.set(name, subject); - } - subject.subscribe(callback); - }, - onLeaveZone(name: string, callback: () => void): void { - let subject = leaveStreams.get(name); - if (subject === undefined) { - subject = new Subject(); - leaveStreams.set(name, subject); - } - subject.subscribe(callback); - }, - } window.addEventListener('message', message => { @@ -226,22 +178,9 @@ window.addEventListener('message', message => { if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) { userInputChatStream.next(payloadData); - } else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) { - enterStreams.get(payloadData.name)?.next(); - } else if (payload.type === 'leaveEvent' && isEnterLeaveEvent(payloadData)) { - leaveStreams.get(payloadData.name)?.next(); - } else if (payload.type === 'buttonClickedEvent' && isButtonClickedEvent(payloadData)) { - const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId); - const popup = popups.get(payloadData.popupId); - if (popup === undefined) { - throw new Error('Could not find popup with ID "' + payloadData.popupId + '"'); - } - if (callback) { - callback(popup); - } } } // ... -}); +}); \ No newline at end of file From cbe93d7164e37b9c4928dd5e27f4dce7b4d21447 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 00:34:40 +0200 Subject: [PATCH 050/189] [WIP] fixed cherry pick conflicts --- front/package-lock.json | 6742 +++++++++++++++++++ front/src/Api/iframe/chatmessage.ts | 2 +- front/src/Api/iframe/iframe-registration.ts | 4 +- front/src/Api/iframe/popup.ts | 6 +- front/src/iframe_api.ts | 66 +- 5 files changed, 6762 insertions(+), 58 deletions(-) create mode 100644 front/package-lock.json diff --git a/front/package-lock.json b/front/package-lock.json new file mode 100644 index 00000000..0508681b --- /dev/null +++ b/front/package-lock.json @@ -0,0 +1,6742 @@ +{ + "name": "workadventurefront", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", + "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.4.tgz", + "integrity": "sha512-Kf8v0wljR5GSCOCF/VQWdV3ZhKOVA73drXtY3geMTQgHy9dgqQ0dLrf31M0hcuWkhFzK5sP0kkS3mJzcKVtZbw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "7.2.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.12.tgz", + "integrity": "sha512-HjikV/jX6e0Pg4DcB+rtOBKSrG6w5IaxWpmi3efL/eLxMz5lZTK+W1DKERrX5a+mNzL78axfsDNXu7JHFP4uLg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.47", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", + "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==", + "dev": true + }, + "@types/express": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.20.tgz", + "integrity": "sha512-8qqFN4W53IEWa9bdmuVrUcVkFemQWnt5DKPQ/oa8xKDYgtjCr2OO6NX5TIK49NLFr3mPYU2cLh92DQquC3oWWQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/google-protobuf": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.0.tgz", + "integrity": "sha512-IshlR1QWD9LYQRlYMfF8dG6PqxrZHddlWB8O5+HCGwH1nv2JQ887fMwRRlXOmUEFehvg+k1THx2h7RbqPUPkGA==", + "dev": true + }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, + "@types/http-proxy": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.6.tgz", + "integrity": "sha512-+qsjqR75S/ib0ig0R9WN+CDoZeOBU6F2XLewgC4KVgdXiNHiKKHFEMRHOrs5PbYE97D5vataw5wPj4KLYfUkuQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.9.tgz", + "integrity": "sha512-B53NIwMj/AO0O+xfSWLYmKB0Mo6TYxfv2Mk8/c1T2w/e38t55iaPR6p7pHXTTtqfTmevPK3i8T1YweYFTZlxDw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "dev": true + }, + "@types/node": { + "version": "14.14.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", + "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==" + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "@types/quill": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz", + "integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==", + "dev": true, + "requires": { + "parchment": "^1.1.2" + } + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/simple-peer": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.6.2.tgz", + "integrity": "sha512-FirllZ8397Qo8LfAgD4UuMgIOQmP1zdcP2eFNRDpaFDGQs42j2XxKOcTcvYZjXHv4HD7hgoNXzjB6iiEspKniw==", + "requires": { + "@types/node": "*" + } + }, + "@types/socket.io-client": { + "version": "1.4.36", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.36.tgz", + "integrity": "sha512-ZJWjtFBeBy1kRSYpVbeGYTElf6BqPQUkXDlHHD4k/42byCN5Rh027f4yARHCink9sKAkbtGZXEAmR0ZCnc2/Ag==" + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz", + "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "@types/webpack": { + "version": "4.41.29", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.29.tgz", + "integrity": "sha512-6pLaORaVNZxiB3FSHbyBiWM7QdazAWda1zvAq4SbZObZqHSDbWLi62iFdblVea6SK9eyBIVp5yHhKt/yNQdR7Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "anymatch": "^3.0.0", + "source-map": "^0.6.0" + } + }, + "@types/webpack-dev-server": { + "version": "3.11.4", + "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-3.11.4.tgz", + "integrity": "sha512-DCKORHjqNNVuMIDWFrlljftvc9CL0+09p3l7lBpb8dRqgN5SmvkWCY4MPKxoI6wJgdRqohmoNbptkxqSKAzLRg==", + "dev": true, + "requires": { + "@types/connect-history-api-fallback": "*", + "@types/express": "*", + "@types/serve-static": "*", + "@types/webpack": "^4", + "http-proxy-middleware": "^1.0.0" + }, + "dependencies": { + "http-proxy-middleware": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz", + "integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.5", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + } + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.25.0.tgz", + "integrity": "sha512-Qfs3dWkTMKkKwt78xp2O/KZQB8MPS1UQ5D3YW2s6LQWBE1074BE+Rym+b1pXZIX3M3fSvPUDaCvZLKV2ylVYYQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.25.0", + "@typescript-eslint/scope-manager": "4.25.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.25.0.tgz", + "integrity": "sha512-f0doRE76vq7NEEU0tw+ajv6CrmPelw5wLoaghEHkA2dNLFb3T/zJQqGPQ0OYt5XlZaS13MtnN+GTPCuUVg338w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.25.0.tgz", + "integrity": "sha512-OZFa1SKyEJpAhDx8FcbWyX+vLwh7OEtzoo2iQaeWwxucyfbi0mT4DijbOSsTgPKzGHr6GrF2V5p/CEpUH/VBxg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.25.0.tgz", + "integrity": "sha512-2NElKxMb/0rya+NJG1U71BuNnp1TBd1JgzYsldsdA83h/20Tvnf/HrwhiSlNmuq6Vqa0EzidsvkTArwoq+tH6w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0" + } + }, + "@typescript-eslint/types": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.25.0.tgz", + "integrity": "sha512-+CNINNvl00OkW6wEsi32wU5MhHti2J25TJsJJqgQmJu3B3dYDBcmOxcE5w9cgoM13TrdE/5ND2HoEnBohasxRQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.25.0.tgz", + "integrity": "sha512-1B8U07TGNAFMxZbSpF6jqiDs1cVGO0izVkf18Q/SPcUAc9LhHxzvSowXDTvkHMWUVuPpagupaW63gB6ahTXVlg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.25.0.tgz", + "integrity": "sha512-AmkqV9dDJVKP/TcZrbf6s6i1zYXt5Hl8qOLrRDTFfRNae4+LB8A4N3i+FLZPW85zIxRy39BgeWOfMS3HoH5ngg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", + "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", + "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", + "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", + "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", + "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", + "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", + "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", + "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", + "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", + "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", + "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/helper-wasm-section": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-opt": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "@webassemblyjs/wast-printer": "1.11.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", + "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", + "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-buffer": "1.11.0", + "@webassemblyjs/wasm-gen": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", + "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/helper-wasm-bytecode": "1.11.0", + "@webassemblyjs/ieee754": "1.11.0", + "@webassemblyjs/leb128": "1.11.0", + "@webassemblyjs/utf8": "1.11.0" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", + "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.0", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.3.tgz", + "integrity": "sha512-WQs0ep98FXX2XBAfQpRbY0Ma6ADw8JR6xoIkaIiJIzClGOMqVRvPCWqndTxf28DgFopWan0EKtHtg/5W1h0Zkw==", + "dev": true + }, + "@webpack-cli/info": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.4.tgz", + "integrity": "sha512-ogE2T4+pLhTTPS/8MM3IjHn0IYplKM4HbVNMCWA9N4NrdPzunwenpCsqKEXyejMfRu6K8mhauIPYf8ZxWG5O6g==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.4.0.tgz", + "integrity": "sha512-xgT/HqJ+uLWGX+Mzufusl3cgjAcnqYYskaB7o0vRcwOEfuu6hMzSILQpnIzFMGsTaeaX4Nnekl+6fadLbl1/Vg==", + "dev": true + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001230", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", + "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", + "dev": true + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "css-loader": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.4.tgz", + "integrity": "sha512-OFYGyINCKkdQsTrSYxzGSFnGS4gNjcXkKkQgWxK138jgnPt+lepxdjSZNc8sHAl5vP3DhsJUxufWIjOwI8PMMw==", + "dev": true, + "requires": { + "camelcase": "^6.2.0", + "icss-utils": "^5.1.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.10", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^3.0.0", + "semver": "^7.3.5" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-node": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz", + "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.740", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.740.tgz", + "integrity": "sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io-client": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.1.tgz", + "integrity": "sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==", + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~7.4.2", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "engine.io-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz", + "integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.4", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", + "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + } + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es-module-lexer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", + "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.27.0.tgz", + "integrity": "sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" + }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "generic-type-guard": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/generic-type-guard/-/generic-type-guard-3.4.1.tgz", + "integrity": "sha512-sXce0Lz3Wfy2rR1W8O8kUemgEriTeG1x8shqSJeWGb0FwJu2qBEkB1M2qXbdSLmpgDnHcIXo0Dj/1VLNJkK/QA==" + }, + "get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "google-protobuf": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", + "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==" + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", + "dev": true + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + } + }, + "html-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-rZsVvPXUYFyME0cuGkyOHfx9hmkFa4pWfxY/mdY38PsBEaVNsRoA+Id+8z6DBDgyv3zaw6XQszdF8HLwfQvcdQ==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "html-minifier-terser": "^5.0.1", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jasmine": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.7.0.tgz", + "integrity": "sha512-wlzGQ+cIFzMEsI+wDqmOwvnjTvolLFwlcpYLCqSPPH0prOQaW3P+IzMhHYn934l1imNvw07oCyX+vGUv3wmtSQ==", + "dev": true, + "requires": { + "glob": "^7.1.6", + "jasmine-core": "~3.7.0" + } + }, + "jasmine-core": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.7.1.tgz", + "integrity": "sha512-DH3oYDS/AUvvr22+xUBW62m1Xoy7tUlY1tsxKEJvl5JeJ7q8zd1K5bUwiOxdH+erj6l2vAMM3hV25Xs9/WrmuQ==", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "linked-list-typescript": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/linked-list-typescript/-/linked-list-typescript-1.0.15.tgz", + "integrity": "sha512-RIyUu9lnJIyIaMe63O7/aFv/T2v3KsMFuXMBbUQCHX+cgtGro86ETDj5ed0a8gQL2+DFjzYYsgVG4I36/cUwgw==" + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true + }, + "lokijs": { + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.12.tgz", + "integrity": "sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==" + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "dev": true + }, + "mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dev": true, + "requires": { + "mime-db": "1.47.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.0.tgz", + "integrity": "sha512-nPFKI7NSy6uONUo9yn2hIfb9vyYvkFu95qki0e21DQ9uaqNKDP15DGpK0KnV6wDroWxPHtExrdEwx/yDQ8nVRw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "webpack-sources": "^1.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "nanoid": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", + "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true + }, + "node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "papaparse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.0.tgz", + "integrity": "sha512-Lb7jN/4bTpiuGPrYy4tkKoUS8sTki8zacB5ke1p5zolhcSE4TlWgrlsxjrDTbG/dFVh07ck7X36hUf/b5V68pg==" + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "parchment": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz", + "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "phaser": { + "version": "3.55.2", + "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.55.2.tgz", + "integrity": "sha512-amKXsbb2Ht29dGPKvt1edq3yGGYKtq8373GpJYGKPNPnneYY6MtVTOgjHDuZwtmUyK4v86FugkT3hzW/N4tjxQ==", + "requires": { + "eventemitter3": "^4.0.7", + "path": "^0.12.7" + } + }, + "phaser3-rex-plugins": { + "version": "1.1.45", + "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.1.45.tgz", + "integrity": "sha512-1wRHhmyw9HCPG6T3CYUR1Qoo73WWizMYxpW5xbjm3NQFgXTqeuqUgyqExLrglrxLqiuhXxSVTnbhWH61XDP5Xg==", + "requires": { + "eventemitter3": "^3.1.2", + "lokijs": "^1.5.11", + "papaparse": "^5.3.0", + "webfontloader": "^1.6.28" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + } + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "8.2.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz", + "integrity": "sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==", + "dev": true, + "requires": { + "colorette": "^1.2.2", + "nanoid": "^3.1.22", + "source-map": "^0.6.1" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.5.tgz", + "integrity": "sha512-aFYPoYmXbZ1V6HZaSvat08M97A8HqO6Pjz+PiNpw/DhuRrC72XWAdp3hL6wusDCN31sSmcZyMGa2hZEuX+Xfhg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "queue-typescript": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-typescript/-/queue-typescript-1.0.1.tgz", + "integrity": "sha512-tkK08uPfmpPl0cX1WRSU3EoNb/T5zSoZPGkkpfGX4E8QayWvEmLS2cI3pFngNPkNTCU5pCDQ1IwlzN0L5gdFPg==", + "requires": { + "linked-list-typescript": "^1.0.11" + } + }, + "quill": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz", + "integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==", + "requires": { + "clone": "^2.1.1", + "deep-equal": "^1.0.1", + "eventemitter3": "^2.0.3", + "extend": "^3.0.1", + "parchment": "^1.1.4", + "quill-delta": "^3.6.2" + }, + "dependencies": { + "eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=" + } + } + }, + "quill-delta": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz", + "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", + "requires": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.1.2" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", + "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "dev": true, + "requires": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.34.0.tgz", + "integrity": "sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-11.1.1.tgz", + "integrity": "sha512-fOCp/zLmj1V1WHDZbUbPgrZhA7HKXHEqkslzB+05U5K9SbSbcmH91C7QLW31AsXikxUMaxXRhhcqWZAxUMLDyA==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "simple-peer": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.0.tgz", + "integrity": "sha512-qvdNu/dGMHBm2uQ7oLhQBMhYlrOZC1ywXNCH/i8I4etxR1vrjCnU6ZSQBptndB1gcakjo2+w4OHo7Sjza1SHxg==", + "requires": { + "buffer": "^6.0.3", + "debug": "^4.3.1", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io-client": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", + "has-binary2": "~1.0.2", + "indexof": "0.0.1", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "socket.io-parser": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", + "requires": { + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + } + }, + "sockjs-client": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz", + "integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==", + "dev": true, + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", + "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-6QhDaAiVHIQr5Ab3XUWZyDmrIPCHMiqJVljMF91YKyqwKkL5QHnYMkrMBy96v9Z7ev1hGhSEw1HQZc2p/s5Z8Q==", + "dev": true, + "requires": { + "jest-worker": "^26.6.2", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.7.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "terser": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", + "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "ts-loader": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.2.tgz", + "integrity": "sha512-hNIhGTQHtNKjOzR2ZtQ2OSVbXPykOae+zostf1IlHCf61Mt41GMJurKNqrYUbzHgpmj6UWRu8eBfb7q0XliV0g==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + } + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "watchpack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", + "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webfontloader": { + "version": "1.6.28", + "resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz", + "integrity": "sha1-23hhKSU8tujq5UwvsF+HCvZnW64=" + }, + "webpack": { + "version": "5.38.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", + "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.47", + "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/wasm-edit": "1.11.0", + "@webassemblyjs/wasm-parser": "1.11.0", + "acorn": "^8.2.1", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.8.0", + "es-module-lexer": "^0.4.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.1", + "watchpack": "^2.2.0", + "webpack-sources": "^2.3.0" + }, + "dependencies": { + "acorn": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", + "integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg==", + "dev": true + }, + "webpack-sources": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", + "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + } + } + }, + "webpack-cli": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.0.tgz", + "integrity": "sha512-7bKr9182/sGfjFm+xdZSwgQuFjgEcy0iCTIBxRUeteJ2Kr8/Wz0qNJX+jw60LU36jApt4nmMkep6+W5AKhok6g==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.3", + "@webpack-cli/info": "^1.2.4", + "@webpack-cli/serve": "^1.4.0", + "colorette": "^1.2.1", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "v8-compile-cache": "^2.2.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "webpack-merge": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", + "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", + "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/front/src/Api/iframe/chatmessage.ts b/front/src/Api/iframe/chatmessage.ts index 7f4f045a..19694c1c 100644 --- a/front/src/Api/iframe/chatmessage.ts +++ b/front/src/Api/iframe/chatmessage.ts @@ -1,4 +1,4 @@ -import { ChatEvent } from '../Events/ChatEvent' +import type { ChatEvent } from '../Events/ChatEvent' import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent' import { } from "./iframe-registration" import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution' diff --git a/front/src/Api/iframe/iframe-registration.ts b/front/src/Api/iframe/iframe-registration.ts index ea9ce5ad..41fb7ce6 100644 --- a/front/src/Api/iframe/iframe-registration.ts +++ b/front/src/Api/iframe/iframe-registration.ts @@ -1,5 +1,5 @@ -import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; -import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api" +import { registeredCallbacks } from "../../iframe_api"; +import type { IframeResponseEventMap } from '../Events/IframeEvent'; /*export function registerWorkadventureCommand(commnds: T): T { const commandPrototype = Object.getPrototypeOf(commnds); const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor"); diff --git a/front/src/Api/iframe/popup.ts b/front/src/Api/iframe/popup.ts index 72ee87c7..f45be74c 100644 --- a/front/src/Api/iframe/popup.ts +++ b/front/src/Api/iframe/popup.ts @@ -1,7 +1,7 @@ import { isButtonClickedEvent } from '../Events/ButtonClickedEvent'; -import { ClosePopupEvent } from '../Events/ClosePopupEvent'; -import { apiCallback, IframeApiContribution, IframeCallbackContribution, sendToWorkadventure } from './IframeApiContribution'; -import zoneCommands from "./zone-events" +import type { ClosePopupEvent } from '../Events/ClosePopupEvent'; +import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; +import zoneCommands from "./zone-events"; class Popup { constructor(private id: number) { } diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index b3126cbb..10882149 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,24 +1,14 @@ -import type { ChatEvent } from "./Api/Events/ChatEvent"; -import { IframeEvent, IframeEventMap, IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; -import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; import { Subject } from "rxjs"; -import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent"; -import type { OpenPopupEvent } from "./Api/Events/OpenPopupEvent"; -import { isButtonClickedEvent } from "./Api/Events/ButtonClickedEvent"; -import type { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; -import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import type { GoToPageEvent } from "./Api/Events/GoToPageEvent"; +import { IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; -import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; -import { OpenCoWebSiteEvent, OpenCoWebSiteOptionsEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import { LoadPageEvent } from './Api/Events/LoadPageEvent'; -import { isMenuItemClickedEvent } from './Api/Events/MenuItemClickedEvent'; -import { MenuItemRegisterEvent } from './Api/Events/MenuItemRegisterEvent'; -import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent'; -import { updateTile, UpdateTileEvent } from './Api/Events/ApiUpdateTileEvent'; -import { isMessageReferenceEvent, removeTriggerMessage, triggerMessage, TriggerMessageCallback, TriggerMessageEvent } from './Api/Events/TriggerMessageEvent'; -import { HasMovedEvent, HasMovedEventCallback, isHasMovedEvent } from './Api/Events/HasMovedEvent'; +import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; +import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; + +export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: { + typeChecker: Function + callback: Function +} } = {} const importType = Promise.all([ import("./Api/iframe/popup"), @@ -57,9 +47,9 @@ type WorkAdventureApiFiles = { } & SubObjectTypes export interface WorkAdventureApi extends WorkAdventureApiFiles { - openTab(url : string): void; - goToPage(url : string): void; - openCoWebSite(url : string): void; + openTab(url: string): void; + goToPage(url: string): void; + openCoWebSite(url: string): void; closeCoWebSite(): void; disablePlayerControls(): void; restorePlayerControls(): void; @@ -85,19 +75,6 @@ const userInputChatStream: Subject = new Subject(); window.WA = { - /** - * Send a message in the chat. - * Only the local user will receive this message. - */ - sendChatMessage(message: string, author: string) { - window.parent.postMessage({ - 'type': 'chat', - 'data': { - 'message': message, - 'author': author - } as ChatEvent - }, '*'); - }, disablePlayerControls(): void { window.parent.postMessage({ 'type': 'disablePlayerControls' }, '*'); }, @@ -132,10 +109,10 @@ window.WA = { }, '*'); }, - openCoWebSite(url : string) : void{ + openCoWebSite(url: string): void { window.parent.postMessage({ - "type" : 'openCoWebSite', - "data" : { + "type": 'openCoWebSite', + "data": { url } as OpenCoWebSiteEvent }, '*'); @@ -146,16 +123,6 @@ window.WA = { "type": 'closeCoWebSite' }, '*'); }, - - registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { - menuCallbacks.set(commandDescriptor, callback); - window.parent.postMessage({ - 'type': 'registerMenuCommand', - 'data': { - menutItem: commandDescriptor - } as MenuItemRegisterEvent - }, '*'); - }, ...({} as WorkAdventureApiFiles), } @@ -171,11 +138,6 @@ window.addEventListener('message', message => { if (isIframeResponseEventWrapper(payload)) { const payloadData = payload.data; - if (registeredCallbacks[payload.type] && registeredCallbacks[payload.type]?.typeChecker(payloadData)) { - registeredCallbacks[payload.type]?.callback(payloadData) - return - } - if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) { userInputChatStream.next(payloadData); } From 540e5783b643f8b4b7b719aa47455e931388c590 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:14:10 +0200 Subject: [PATCH 051/189] cowebsite navigation sound player extraction --- front/package-lock.json | 1141 ++++++++++++++++- front/src/Api/iframe/CoWebsite.ts | 29 + front/src/Api/iframe/IframeApiContribution.ts | 5 +- front/src/Api/iframe/Navigation.ts | 35 + front/src/Api/iframe/Player.ts | 22 + front/src/Api/iframe/Sound.ts | 59 + front/src/Api/iframe/zone-events.ts | 4 +- front/src/iframe_api.ts | 115 +- 8 files changed, 1297 insertions(+), 113 deletions(-) create mode 100644 front/src/Api/iframe/CoWebsite.ts create mode 100644 front/src/Api/iframe/Navigation.ts create mode 100644 front/src/Api/iframe/Player.ts create mode 100644 front/src/Api/iframe/Sound.ts diff --git a/front/package-lock.json b/front/package-lock.json index 0508681b..a9c97b33 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -115,6 +115,12 @@ "fastq": "^1.6.0" } }, + "@tsconfig/svelte": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-1.0.12.tgz", + "integrity": "sha512-Ti8SAnNa6zLWcJAHo3ac3B2qkZbFweT6mLPuGS8c4/EtmvdaNBzp5IP7tvRC6QkmQ/yhdh0mTbDWZFwltvzAWw==", + "dev": true + }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -236,12 +242,29 @@ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "@types/mini-css-extract-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/mini-css-extract-plugin/-/mini-css-extract-plugin-1.4.3.tgz", + "integrity": "sha512-jyOSVaF4ie2jUGr1uohqeyDrp7ktRthdFxDKzTgbPZtl0QI5geEopW7UKD/DEfn0XgV1KEq/RnZlUmnrEAWbmg==", + "dev": true, + "requires": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -249,9 +272,21 @@ "dev": true }, "@types/node": { - "version": "14.14.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", - "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==" + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz", + "integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/pug": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz", + "integrity": "sha1-h3L80EGOPNLMFxVV1zAHQVBR9LI=", + "dev": true }, "@types/qs": { "version": "6.9.6", @@ -274,6 +309,15 @@ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", "dev": true }, + "@types/sass": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.16.0.tgz", + "integrity": "sha512-2XZovu4NwcqmtZtsBR5XYLw18T8cBCnU2USFHTnYLLHz9fkhnoEMoDsqShJIOFsFhn5aJHjweiUUdTrDGujegA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/serve-static": { "version": "1.13.9", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", @@ -816,6 +860,54 @@ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dev": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + }, + "dependencies": { + "util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + } + } + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -849,12 +941,24 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", + "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==", + "dev": true + }, "axios": { "version": "0.21.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", @@ -962,6 +1066,12 @@ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", + "dev": true + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -1042,6 +1152,93 @@ "fill-range": "^7.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, "browserslist": { "version": "4.16.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", @@ -1076,6 +1273,18 @@ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", "dev": true }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -1217,6 +1426,16 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -1412,6 +1631,18 @@ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -1459,6 +1690,64 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -1486,6 +1775,25 @@ } } }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, "css-loader": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.4.tgz", @@ -1568,6 +1876,12 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", @@ -1648,12 +1962,28 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "dev": true }, + "detect-indent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", + "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "dev": true + }, "detect-node": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz", @@ -1666,6 +1996,25 @@ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1736,6 +2085,12 @@ } } }, + "domain-browser": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.19.0.tgz", + "integrity": "sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==", + "dev": true + }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", @@ -1791,6 +2146,35 @@ "integrity": "sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg==", "dev": true }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1916,12 +2300,74 @@ "prr": "~1.0.1" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.2.tgz", + "integrity": "sha512-byRiNIQXE6HWNySaU6JohoNXzYgbBjztwFnBLUTiJmWXjaU9bSq3urQLUlNLQ292tc+gc07zYZXNZjaOoAX3sw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "dependencies": { + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + } + } + }, "es-module-lexer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", "dev": true }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2175,6 +2621,16 @@ "original": "^1.0.0" } }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -2477,6 +2933,12 @@ "to-regex-range": "^5.0.1" } }, + "filter-obj": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-2.0.2.tgz", + "integrity": "sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg==", + "dev": true + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -2556,6 +3018,52 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.2.10", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.2.10.tgz", + "integrity": "sha512-HveFCHWSH2WlYU1tU3PkrupvW8lNFMTfH3Jk0TfC2mtktE9ibHGcifhCsCFvj+kqlDfNIlwmNLiNqR9jnSA7OQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + } + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -2577,6 +3085,24 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2734,6 +3260,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", @@ -2810,12 +3342,52 @@ } } }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -3075,6 +3647,12 @@ } } }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -3221,6 +3799,18 @@ "call-bind": "^1.0.0" } }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3230,12 +3820,27 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, "is-core-module": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", @@ -3307,6 +3912,12 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "is-generator-function": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.9.tgz", + "integrity": "sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A==", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -3316,12 +3927,34 @@ "is-extglob": "^2.1.1" } }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -3376,6 +4009,34 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", + "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -3471,6 +4132,12 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3498,6 +4165,16 @@ "minimist": "^1.2.5" } }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -3526,6 +4203,12 @@ "type-check": "~0.4.0" } }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, "linked-list-typescript": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/linked-list-typescript/-/linked-list-typescript-1.0.15.tgz", @@ -3640,12 +4323,32 @@ "object-visit": "^1.0.0" } }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, + "memfs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.2.tgz", + "integrity": "sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==", + "dev": true, + "requires": { + "fs-monkey": "1.0.3" + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -3680,6 +4383,24 @@ "picomatch": "^2.2.3" } }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -3707,6 +4428,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "mini-css-extract-plugin": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.0.tgz", @@ -3724,6 +4451,12 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3863,6 +4596,54 @@ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "dev": true }, + "node-polyfill-webpack-plugin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-1.1.2.tgz", + "integrity": "sha512-ubwf7M73V13RDlKaDmMh1+giB/D8KL75umXEGabGtxSt/WRCirl01urhK1qsr6Cdt77escQ9SNb5OoTR8IwEHg==", + "dev": true, + "requires": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.19.0", + "events": "^3.3.0", + "filter-obj": "^2.0.2", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^2.1.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "^0.0.1", + "url": "^0.11.0", + "util": "^0.12.3", + "vm-browserify": "^1.1.2" + }, + "dependencies": { + "util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + } + } + }, "node-releases": { "version": "1.1.72", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", @@ -3930,6 +4711,12 @@ } } }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true + }, "object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", @@ -3953,6 +4740,18 @@ "isobject": "^3.0.0" } }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -4033,6 +4832,12 @@ "url-parse": "^1.4.3" } }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -4078,6 +4883,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "papaparse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.0.tgz", @@ -4115,6 +4926,31 @@ "callsites": "^3.0.0" } }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "parseqs": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", @@ -4164,6 +5000,12 @@ "util": "^0.10.3" } }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -4212,6 +5054,19 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "phaser": { "version": "3.55.2", "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.55.2.tgz", @@ -4414,6 +5269,28 @@ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4442,6 +5319,12 @@ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", "dev": true }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -4499,6 +5382,16 @@ "safe-buffer": "^5.1.0" } }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4722,6 +5615,16 @@ "glob": "^7.1.3" } }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4959,12 +5862,28 @@ } } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -5390,6 +6309,44 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, "string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", @@ -5412,6 +6369,26 @@ } } }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5437,6 +6414,12 @@ } } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -5449,6 +6432,15 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5464,6 +6456,47 @@ "has-flag": "^3.0.0" } }, + "svelte": { + "version": "3.38.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.38.2.tgz", + "integrity": "sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg==", + "dev": true + }, + "svelte-dev-helper": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/svelte-dev-helper/-/svelte-dev-helper-1.1.9.tgz", + "integrity": "sha1-fRh9tcbNu9ZNdaMvkbiZi94yc8M=", + "dev": true + }, + "svelte-hmr": { + "version": "0.12.9", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.12.9.tgz", + "integrity": "sha512-SGE7Odznj4dqZtUVIWcoPCvZ9gHImxVIIjrz+O3DDSi0j4OaSLim6MRF4UdhlBKeW3glSRc+tXNSKYvM5x+Dyw==", + "dev": true + }, + "svelte-loader": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-3.1.1.tgz", + "integrity": "sha512-JU7qo1yBdDeJ3Aw23WoGKXrVaSn3KeWkM9KMl43HuMVFrsPNHIzZHTsf1ARJX/Abm3jeqNjigaO35RVbixhmWg==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "svelte-dev-helper": "^1.1.9", + "svelte-hmr": "^0.12.3" + } + }, + "svelte-preprocess": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.7.3.tgz", + "integrity": "sha512-Zx1/xLeGOIBlZMGPRCaXtlMe4ZA0faato5Dc3CosEqwu75MIEPuOstdkH6cy+RYTUYynoxzNaDxkPX4DbrPwRA==", + "dev": true, + "requires": { + "@types/pug": "^2.0.4", + "@types/sass": "^1.16.0", + "detect-indent": "^6.0.0", + "strip-indent": "^3.0.0" + } + }, "table": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", @@ -5594,6 +6627,15 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", @@ -5672,6 +6714,29 @@ "yn": "3.1.1" } }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5686,6 +6751,12 @@ "tslib": "^1.8.1" } }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5717,6 +6788,18 @@ "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -5729,6 +6812,12 @@ "set-value": "^2.0.1" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -5879,6 +6968,12 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, "watchpack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", @@ -6578,12 +7673,40 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, "wildcard": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", @@ -6648,6 +7771,12 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, "y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", @@ -6660,6 +7789,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, "yargs": { "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", diff --git a/front/src/Api/iframe/CoWebsite.ts b/front/src/Api/iframe/CoWebsite.ts new file mode 100644 index 00000000..346c1589 --- /dev/null +++ b/front/src/Api/iframe/CoWebsite.ts @@ -0,0 +1,29 @@ +import type { OpenCoWebSiteEvent } from '../Events/OpenCoWebSiteEvent'; +import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; + +class WorkadventureCoWebsiteCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "cowebsite" + + readonly addMethodsAtRoot = true + callbacks = [] + + openCoWebSite(url: string): void { + sendToWorkadventure({ + "type": 'openCoWebSite', + "data": { + url + } as OpenCoWebSiteEvent + }); + } + + closeCoWebSite(): void { + sendToWorkadventure({ + "type": 'closeCoWebSite', + data: null + }); + } +} + + +export default new WorkadventureCoWebsiteCommands(); \ No newline at end of file diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts index ee2ecff5..25e1cde0 100644 --- a/front/src/Api/iframe/IframeApiContribution.ts +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -1,8 +1,7 @@ -import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; import type * as tg from "generic-type-guard"; +import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; -export type PossibleSubobjects = "zone" | "chat" | "ui" export function sendToWorkadventure(content: IframeEvent) { window.parent.postMessage(content, "*") @@ -21,7 +20,7 @@ export interface IframeCallbackContribution, callback: (payloadData: T) => void } - +export type PossibleSubobjects = "zone" | "chat" | "ui" | "nav" | "sound" | "cowebsite" | "player" /** * !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly * diff --git a/front/src/Api/iframe/Navigation.ts b/front/src/Api/iframe/Navigation.ts new file mode 100644 index 00000000..fe3fed8e --- /dev/null +++ b/front/src/Api/iframe/Navigation.ts @@ -0,0 +1,35 @@ +import type { GoToPageEvent } from '../Events/GoToPageEvent'; +import type { OpenTabEvent } from '../Events/OpenTabEvent'; +import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; + + + +class WorkadventureNavigationCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "nav" + + readonly addMethodsAtRoot = true + callbacks = [] + + + openTab(url: string): void { + sendToWorkadventure({ + "type": 'openTab', + "data": { + url + } as OpenTabEvent + }); + } + + goToPage(url: string): void { + sendToWorkadventure({ + "type": 'goToPage', + "data": { + url + } as GoToPageEvent + }); + } +} + + +export default new WorkadventureNavigationCommands(); \ No newline at end of file diff --git a/front/src/Api/iframe/Player.ts b/front/src/Api/iframe/Player.ts new file mode 100644 index 00000000..3ce50938 --- /dev/null +++ b/front/src/Api/iframe/Player.ts @@ -0,0 +1,22 @@ +import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; + +class WorkadventureNavigationCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "player" + + readonly addMethodsAtRoot = true + callbacks = [] + + disablePlayerControls(): void { + sendToWorkadventure({ 'type': 'disablePlayerControls', data: null }); + } + + restorePlayerControls(): void { + sendToWorkadventure({ 'type': 'restorePlayerControls', data: null }); + } + + +} + + +export default new WorkadventureNavigationCommands(); \ No newline at end of file diff --git a/front/src/Api/iframe/Sound.ts b/front/src/Api/iframe/Sound.ts new file mode 100644 index 00000000..194f937b --- /dev/null +++ b/front/src/Api/iframe/Sound.ts @@ -0,0 +1,59 @@ +import type { LoadSoundEvent } from '../Events/LoadSoundEvent'; +import type { PlaySoundEvent } from '../Events/PlaySoundEvent'; +import type { StopSoundEvent } from '../Events/StopSoundEvent'; +import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; +import SoundConfig = Phaser.Types.Sound.SoundConfig; + +export class Sound { + constructor(private url: string) { + sendToWorkadventure({ + "type": 'loadSound', + "data": { + url: this.url, + } as LoadSoundEvent + + }); + } + + public play(config: SoundConfig) { + sendToWorkadventure({ + "type": 'playSound', + "data": { + url: this.url, + config + } as PlaySoundEvent + + }); + return this.url; + } + public stop() { + sendToWorkadventure({ + "type": 'stopSound', + "data": { + url: this.url, + } as StopSoundEvent + + }); + return this.url; + } + +} + + + +class WorkadventureSoundCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "sound" + + readonly addMethodsAtRoot = true + callbacks = [] + + + loadSound(url: string): Sound { + return new Sound(url); + } + +} + + +export default new WorkadventureSoundCommands(); \ No newline at end of file diff --git a/front/src/Api/iframe/zone-events.ts b/front/src/Api/iframe/zone-events.ts index 8f66b45a..c7d66c16 100644 --- a/front/src/Api/iframe/zone-events.ts +++ b/front/src/Api/iframe/zone-events.ts @@ -1,6 +1,6 @@ -import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent' -import { apiCallback as apiCallback, IframeApiContribution } from './IframeApiContribution' import { Subject } from "rxjs"; +import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent'; +import { apiCallback as apiCallback, IframeApiContribution } from './IframeApiContribution'; const enterStreams: Map> = new Map>(); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index a927cf75..395c9d01 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,13 +1,5 @@ -import { Subject } from "rxjs"; -import type { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import { IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; -import type { LoadSoundEvent } from "./Api/Events/LoadSoundEvent"; -import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; -import type { PlaySoundEvent } from "./Api/Events/PlaySoundEvent"; -import type { StopSoundEvent } from "./Api/Events/StopSoundEvent"; -import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; -import SoundConfig = Phaser.Types.Sound.SoundConfig; + export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: { typeChecker: Function callback: Function @@ -16,9 +8,13 @@ export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: { const importType = Promise.all([ import("./Api/iframe/popup"), import("./Api/iframe/chatmessage"), - import("./Api/iframe/zone-events") + import("./Api/iframe/Sound"), + import("./Api/iframe/zone-events"), + import("./Api/iframe/Navigation"), + import("./Api/iframe/CoWebsite") ]) + type PromiseReturnType

= P extends Promise ? T : P type WorkadventureCommandClasses = PromiseReturnType[number]["default"]; @@ -50,20 +46,12 @@ type WorkAdventureApiFiles = { } & SubObjectTypes export interface WorkAdventureApi extends WorkAdventureApiFiles { - openTab(url: string): void; - goToPage(url: string): void; - openCoWebSite(url: string): void; - closeCoWebSite(): void; disablePlayerControls(): void; restorePlayerControls(): void; displayBubble(): void; removeBubble(): void; - loadSound(url: string): Sound; } - - - declare global { interface Window { @@ -72,55 +60,9 @@ declare global { let WA: WorkAdventureApi } -const userInputChatStream: Subject = new Subject(); - - - - - -export class Sound { - constructor(private url: string) { - window.parent.postMessage({ - "type": 'loadSound', - "data": { - url: this.url, - } as LoadSoundEvent - - }, '*'); - } - - public play(config: SoundConfig) { - window.parent.postMessage({ - "type": 'playSound', - "data": { - url: this.url, - config - } as PlaySoundEvent - - }, '*'); - return this.url; - } - public stop() { - window.parent.postMessage({ - "type": 'stopSound', - "data": { - url: this.url, - } as StopSoundEvent - - }, '*'); - return this.url; - } - -} window.WA = { - disablePlayerControls(): void { - window.parent.postMessage({ 'type': 'disablePlayerControls' }, '*'); - }, - - restorePlayerControls(): void { - window.parent.postMessage({ 'type': 'restorePlayerControls' }, '*'); - }, + displayBubble(): void { window.parent.postMessage({ 'type': 'displayBubble' }, '*'); @@ -130,42 +72,7 @@ window.WA = { window.parent.postMessage({ 'type': 'removeBubble' }, '*'); }, - openTab(url: string): void { - window.parent.postMessage({ - "type": 'openTab', - "data": { - url - } as OpenTabEvent - }, '*'); - }, - loadSound(url: string): Sound { - return new Sound(url); - }, - - goToPage(url: string): void { - window.parent.postMessage({ - "type": 'goToPage', - "data": { - url - } as GoToPageEvent - }, '*'); - }, - - openCoWebSite(url: string): void { - window.parent.postMessage({ - "type": 'openCoWebSite', - "data": { - url - } as OpenCoWebSiteEvent - }, '*'); - }, - - closeCoWebSite(): void { - window.parent.postMessage({ - "type": 'closeCoWebSite' - }, '*'); - }, ...({} as WorkAdventureApiFiles), } @@ -173,18 +80,16 @@ window.addEventListener('message', message => { if (message.source !== window.parent) { return; // Skip message in this event listener } - const payload = message.data; - console.debug(payload); if (isIframeResponseEventWrapper(payload)) { const payloadData = payload.data; - if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) { - userInputChatStream.next(payloadData); + if (registeredCallbacks[payload.type] && registeredCallbacks[payload.type]?.typeChecker(payloadData)) { + registeredCallbacks[payload.type]?.callback(payloadData) + return } - } // ... From fd5b598b63baa90547add8001819ce5654bd6c86 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:18:00 +0200 Subject: [PATCH 052/189] Bubble [WIP] (still need to do the javascript part) --- front/src/Api/iframe/Bubble.ts | 20 +++++++++++++++++++ front/src/Api/iframe/IframeApiContribution.ts | 2 +- front/src/iframe_api.ts | 20 ++++--------------- 3 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 front/src/Api/iframe/Bubble.ts diff --git a/front/src/Api/iframe/Bubble.ts b/front/src/Api/iframe/Bubble.ts new file mode 100644 index 00000000..b0f070cb --- /dev/null +++ b/front/src/Api/iframe/Bubble.ts @@ -0,0 +1,20 @@ +import { IframeApiContribution } from './IframeApiContribution'; + +class WorkadventureNavigationCommands extends IframeApiContribution { + + readonly subObjectIdentifier = "bubble" + + readonly addMethodsAtRoot = true + callbacks = [] + displayBubble(): void { + window.parent.postMessage({ 'type': 'displayBubble' }, '*'); + } + + removeBubble(): void { + window.parent.postMessage({ 'type': 'removeBubble' }, '*'); + } + +} + + +export default new WorkadventureNavigationCommands(); \ No newline at end of file diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts index 25e1cde0..f1fb3cd5 100644 --- a/front/src/Api/iframe/IframeApiContribution.ts +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -20,7 +20,7 @@ export interface IframeCallbackContribution, callback: (payloadData: T) => void } -export type PossibleSubobjects = "zone" | "chat" | "ui" | "nav" | "sound" | "cowebsite" | "player" +export type PossibleSubobjects = "zone" | "chat" | "ui" | "nav" | "sound" | "cowebsite" | "player" | "bubble" /** * !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly * diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 395c9d01..42cc34e1 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -11,7 +11,9 @@ const importType = Promise.all([ import("./Api/iframe/Sound"), import("./Api/iframe/zone-events"), import("./Api/iframe/Navigation"), - import("./Api/iframe/CoWebsite") + import("./Api/iframe/CoWebsite"), + import("./Api/iframe/Player"), + import("./Api/iframe/Bubble") ]) @@ -46,10 +48,7 @@ type WorkAdventureApiFiles = { } & SubObjectTypes export interface WorkAdventureApi extends WorkAdventureApiFiles { - disablePlayerControls(): void; - restorePlayerControls(): void; - displayBubble(): void; - removeBubble(): void; + } declare global { @@ -62,17 +61,6 @@ declare global { window.WA = { - - - displayBubble(): void { - window.parent.postMessage({ 'type': 'displayBubble' }, '*'); - }, - - removeBubble(): void { - window.parent.postMessage({ 'type': 'removeBubble' }, '*'); - }, - - ...({} as WorkAdventureApiFiles), } From 9e6fb755d9352d56080acee47dd7cc2793254255 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:44:38 +0200 Subject: [PATCH 053/189] added javascript for setting commands --- front/src/iframe_api.ts | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 42cc34e1..0da0099f 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -43,13 +43,10 @@ type SubObjectTypes = { [importCl in WorkadventureCommandClasses as importCl["subObjectIdentifier"]]: JustMethods; }; -type WorkAdventureApiFiles = { +type WorkAdventureApi = { [Key in WorkadventureFunctionsFilteredByRoot]: ShouldAddAttribute } & SubObjectTypes -export interface WorkAdventureApi extends WorkAdventureApiFiles { - -} declare global { @@ -59,11 +56,31 @@ declare global { let WA: WorkAdventureApi } +async function populateWa(): Promise { + const wa: Partial = {} + for (const apiImport of await importType) { + const classInstance = apiImport.default + const commandPrototype = Object.getPrototypeOf(classInstance); + const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor"); + const importObject: Partial = {} + for (const prop of commandClassPropertyNames) { + const apiImportKey = prop as keyof typeof classInstance; + if (typeof classInstance[apiImportKey] === "function") { + importObject[apiImportKey as keyof WorkAdventureApi] = commandPrototype[apiImportKey] as never + } + } + wa[classInstance.subObjectIdentifier] = importObject as never + if (classInstance.addMethodsAtRoot) { + Object.assign(wa, importObject) + } + } -window.WA = { - ...({} as WorkAdventureApiFiles), + window.WA = Object.assign({}, wa) as WorkAdventureApi } + +populateWa() + window.addEventListener('message', message => { if (message.source !== window.parent) { return; // Skip message in this event listener From ab631c5dc48a4194d0505a6048b8877b24d8a890 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:46:08 +0200 Subject: [PATCH 054/189] register callbacks should be done now --- front/src/Api/iframe/IframeApiContribution.ts | 6 ++++- front/src/Api/iframe/iframe-registration.ts | 27 ------------------- 2 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 front/src/Api/iframe/iframe-registration.ts diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts index f1fb3cd5..dc261762 100644 --- a/front/src/Api/iframe/IframeApiContribution.ts +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -1,4 +1,5 @@ import type * as tg from "generic-type-guard"; +import { registeredCallbacks } from '../../iframe_api'; import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent'; @@ -9,7 +10,10 @@ export function sendToWorkadventure(content: IframeEvent) type GuardedType> = Guard extends tg.TypeGuard ? T : never export function apiCallback>(callbackData: IframeCallbackContribution) { - + registeredCallbacks[callbackData.type] = { + typeChecker: callbackData.typeChecker, + callback: callbackData.callback + } return callbackData } diff --git a/front/src/Api/iframe/iframe-registration.ts b/front/src/Api/iframe/iframe-registration.ts deleted file mode 100644 index 41fb7ce6..00000000 --- a/front/src/Api/iframe/iframe-registration.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { registeredCallbacks } from "../../iframe_api"; -import type { IframeResponseEventMap } from '../Events/IframeEvent'; -/*export function registerWorkadventureCommand(commnds: T): T { - const commandPrototype = Object.getPrototypeOf(commnds); - const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor"); - for (const key of commandClassPropertyNames) { - window.WA[key as keyof WorkAdventureApi] = commandPrototype[key] as never - } - return commnds -} -*/ - -export function registerWorkadvntureCallback(callbacks: Array<{ - type: keyof IframeResponseEventMap, - typeChecker: Function, - callback: T -}>) { - for (const callback of callbacks) { - registeredCallbacks[callback.type] = { - typeChecker: callback.typeChecker, - callback: callback.callback - } - } - return callbacks -} - - From 5fd82c1188d0e4f556f03c5aab8d6f6dcaf3ca69 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:50:58 +0200 Subject: [PATCH 055/189] minor cleanup --- front/src/Api/iframe/chatmessage.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/front/src/Api/iframe/chatmessage.ts b/front/src/Api/iframe/chatmessage.ts index 19694c1c..80b549dd 100644 --- a/front/src/Api/iframe/chatmessage.ts +++ b/front/src/Api/iframe/chatmessage.ts @@ -1,6 +1,5 @@ import type { ChatEvent } from '../Events/ChatEvent' import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent' -import { } from "./iframe-registration" import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution' From dbb35d102f748d9abc436fd98980be0da86efc8e Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 01:59:43 +0200 Subject: [PATCH 056/189] extracted giant typing block --- front/src/iframe_api.d.ts | 25 +++++++++++++++++++++++++ front/src/iframe_api.ts | 33 ++------------------------------- 2 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 front/src/iframe_api.d.ts diff --git a/front/src/iframe_api.d.ts b/front/src/iframe_api.d.ts new file mode 100644 index 00000000..953c92d2 --- /dev/null +++ b/front/src/iframe_api.d.ts @@ -0,0 +1,25 @@ +import type { WorkadventureImport } from './iframe_api'; + +type PromiseReturnType

= P extends Promise ? T : P; +type WorkadventureCommandClasses = PromiseReturnType[number]["default"]; +type KeysOfUnion = T extends T ? keyof T : never; +type ObjectWithKeyOfUnion = O extends O ? (Key extends keyof O ? O[Key] : never) : never; +type ApiKeys = KeysOfUnion; +type ObjectOfKey = O extends O ? (Key extends keyof O ? O : never) : never; +type ShouldAddAttribute = ObjectWithKeyOfUnion; +type WorkadventureFunctions = { + [K in ApiKeys]: ObjectWithKeyOfUnion extends Function ? K : never; +}[ApiKeys]; +type WorkadventureFunctionsFilteredByRoot = { + [K in WorkadventureFunctions]: ObjectOfKey["addMethodsAtRoot"] extends true ? K : never; +}[WorkadventureFunctions]; +type JustMethodKeys = ({ + [P in keyof T]: T[P] extends Function ? P : never; +})[keyof T]; +type JustMethods = Pick>; +type SubObjectTypes = { + [importCl in WorkadventureCommandClasses as importCl["subObjectIdentifier"]]: JustMethods; +}; +export type WorkAdventureApi = { + [Key in WorkadventureFunctionsFilteredByRoot]: ShouldAddAttribute; +} & SubObjectTypes; diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 0da0099f..136edb8e 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,4 +1,5 @@ import { IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; +import type { WorkAdventureApi } from './iframe_api.d'; export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: { typeChecker: Function @@ -16,37 +17,7 @@ const importType = Promise.all([ import("./Api/iframe/Bubble") ]) - -type PromiseReturnType

@@ -66,6 +69,7 @@ --> {#if $gameOverlayVisibilityStore}
+
diff --git a/front/src/Components/EnableCamera/HorizontalSoundMeterWidget.svelte b/front/src/Components/EnableCamera/HorizontalSoundMeterWidget.svelte index a22da2fa..79ad1810 100644 --- a/front/src/Components/EnableCamera/HorizontalSoundMeterWidget.svelte +++ b/front/src/Components/EnableCamera/HorizontalSoundMeterWidget.svelte @@ -58,7 +58,7 @@
- {#each [...Array(NB_BARS).keys()] as i} + {#each [...Array(NB_BARS).keys()] as i (i)}
{/each}
diff --git a/front/src/Components/SoundMeterWidget.svelte b/front/src/Components/SoundMeterWidget.svelte index 30650e3f..94e0cdd2 100644 --- a/front/src/Components/SoundMeterWidget.svelte +++ b/front/src/Components/SoundMeterWidget.svelte @@ -23,7 +23,7 @@ timeout = setInterval(() => { try{ - volume = parseInt((soundMeter.getVolume() / 100 * NB_BARS).toFixed(0)); + volume = soundMeter.getVolume(); //console.log(volume); }catch(err){ @@ -45,9 +45,9 @@
- 1}> - 2}> - 3}> - 4}> 5}> + 10}> + 15}> + 40}> + 70}>
diff --git a/front/src/Components/Video/LocalStreamMedia.svelte b/front/src/Components/Video/LocalStreamMedia.svelte new file mode 100644 index 00000000..43b1d117 --- /dev/null +++ b/front/src/Components/Video/LocalStreamMedia.svelte @@ -0,0 +1,20 @@ + + + +
+ +
diff --git a/front/src/Components/Video/Peer.svelte b/front/src/Components/Video/Peer.svelte new file mode 100644 index 00000000..c73d620e --- /dev/null +++ b/front/src/Components/Video/Peer.svelte @@ -0,0 +1,20 @@ + + +
+ {#if peer instanceof VideoPeer} + + {:else if peer instanceof ScreenSharingPeer} + + {:else} + + {/if} +
diff --git a/front/src/Components/Video/ScreenSharingMedia.svelte b/front/src/Components/Video/ScreenSharingMedia.svelte new file mode 100644 index 00000000..e16fac58 --- /dev/null +++ b/front/src/Components/Video/ScreenSharingMedia.svelte @@ -0,0 +1,57 @@ + + +
+ {#if $statusStore === 'connecting'} +
+ {/if} + {#if $statusStore === 'error'} +
+ {/if} + {#if $streamStore === null} + {name} + {/if} + +
+ + diff --git a/front/src/Components/Video/VideoMedia.svelte b/front/src/Components/Video/VideoMedia.svelte new file mode 100644 index 00000000..fbc5c6f7 --- /dev/null +++ b/front/src/Components/Video/VideoMedia.svelte @@ -0,0 +1,75 @@ + + +
+ {#if $statusStore === 'connecting'} +
+ {/if} + {#if $statusStore === 'error'} +
+ {/if} + {#if !$constraintStore || $constraintStore.video === false} + {name} + {/if} + {#if $constraintStore && $constraintStore.audio === false} + Muted + {/if} + + + + {#if $constraintStore && $constraintStore.audio !== false} + + {/if} +
+ + diff --git a/front/src/Components/Video/VideoOverlay.svelte b/front/src/Components/Video/VideoOverlay.svelte new file mode 100644 index 00000000..5ba7fbc7 --- /dev/null +++ b/front/src/Components/Video/VideoOverlay.svelte @@ -0,0 +1,32 @@ + + +
+
+ {#each [...$layoutStore.get(DivImportance.Important).values()] as peer (peer.uniqueId)} + + {/each} +
+ + + + +
+ + diff --git a/front/src/Components/Video/images/blockSign.svg b/front/src/Components/Video/images/blockSign.svg new file mode 100644 index 00000000..c64ba294 --- /dev/null +++ b/front/src/Components/Video/images/blockSign.svg @@ -0,0 +1,22 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/front/src/Components/Video/images/report.svg b/front/src/Components/Video/images/report.svg new file mode 100644 index 00000000..14753256 --- /dev/null +++ b/front/src/Components/Video/images/report.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index b5876d5a..1bec39fc 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -30,7 +30,7 @@ import {PlayerMovement} from "./PlayerMovement"; import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator"; import {RemotePlayer} from "../Entity/RemotePlayer"; import {Queue} from 'queue-typescript'; -import {SimplePeer, UserSimplePeerInterface} from "../../WebRtc/SimplePeer"; +import {SimplePeer} from "../../WebRtc/SimplePeer"; import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene"; import {lazyLoadPlayerCharacterTextures, loadCustomTexture} from "../Entity/PlayerTexturesLoadingManager"; import { @@ -93,7 +93,7 @@ import {PinchManager} from "../UserInput/PinchManager"; import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick"; import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes"; import {waScaleManager} from "../Services/WaScaleManager"; -import {peerStore} from "../../Stores/PeerStore"; +import {peerStore, screenSharingPeerStore} from "../../Stores/PeerStore"; import {EmoteManager} from "./EmoteManager"; export interface GameSceneInitInterface { @@ -646,12 +646,13 @@ export class GameScene extends DirtyScene implements CenterListener { // When connection is performed, let's connect SimplePeer this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName); peerStore.connectToSimplePeer(this.simplePeer); + screenSharingPeerStore.connectToSimplePeer(this.simplePeer); this.GlobalMessageManager = new GlobalMessageManager(this.connection); userMessageManager.setReceiveBanListener(this.bannedUser.bind(this)); const self = this; this.simplePeer.registerPeerConnectionListener({ - onConnect(user: UserSimplePeerInterface) { + onConnect(peer) { self.presentationModeSprite.setVisible(true); self.chatModeSprite.setVisible(true); self.openChatIcon.setVisible(true); diff --git a/front/src/Stores/GameOverlayStoreVisibility.ts b/front/src/Stores/GameOverlayStoreVisibility.ts new file mode 100644 index 00000000..c58c929d --- /dev/null +++ b/front/src/Stores/GameOverlayStoreVisibility.ts @@ -0,0 +1,17 @@ +import {writable} from "svelte/store"; + +/** + * A store that contains whether the game overlay is shown or not. + * Typically, the overlay is hidden when entering Jitsi meet. + */ +function createGameOverlayVisibilityStore() { + const { subscribe, set, update } = writable(false); + + return { + subscribe, + showGameOverlay: () => set(true), + hideGameOverlay: () => set(false), + }; +} + +export const gameOverlayVisibilityStore = createGameOverlayVisibilityStore(); diff --git a/front/src/Stores/LayoutStore.ts b/front/src/Stores/LayoutStore.ts new file mode 100644 index 00000000..45e6f604 --- /dev/null +++ b/front/src/Stores/LayoutStore.ts @@ -0,0 +1,58 @@ +import {derived, get} from "svelte/store"; +import {ScreenSharingLocalMedia, screenSharingLocalMedia} from "./ScreenSharingStore"; +import {DivImportance} from "../WebRtc/LayoutManager"; +import { peerStore, screenSharingStreamStore} from "./PeerStore"; +import type {RemotePeer} from "../WebRtc/SimplePeer"; + +export type DisplayableMedia = RemotePeer | ScreenSharingLocalMedia; + +/** + * A store that contains the layout of the streams + */ +function createLayoutStore() { + + let unsubscribes: (()=>void)[] = []; + + return derived([ + screenSharingStreamStore, + peerStore, + screenSharingLocalMedia, + ], ([ + $screenSharingStreamStore, + $peerStore, + $screenSharingLocalMedia, + ], set) => { + for (const unsubscribe of unsubscribes) { + unsubscribe(); + } + unsubscribes = []; + + const peers = new Map>(); + peers.set(DivImportance.Normal, new Map()); + peers.set(DivImportance.Important, new Map()); + + const addPeer = (peer: DisplayableMedia) => { + const importance = get(peer.importanceStore); + + peers.get(importance)?.set(peer.uniqueId, peer); + + unsubscribes.push(peer.importanceStore.subscribe((importance) => { + peers.forEach((category) => { + category.delete(peer.uniqueId); + }); + peers.get(importance)?.set(peer.uniqueId, peer); + set(peers); + })); + }; + + $screenSharingStreamStore.forEach(addPeer); + $peerStore.forEach(addPeer); + if ($screenSharingLocalMedia?.stream) { + addPeer($screenSharingLocalMedia); + } + + set(peers); + }); +} + +export const layoutStore = createLayoutStore(); diff --git a/front/src/Stores/MediaStore.ts b/front/src/Stores/MediaStore.ts index d622511e..b2cd9f42 100644 --- a/front/src/Stores/MediaStore.ts +++ b/front/src/Stores/MediaStore.ts @@ -1,13 +1,13 @@ import {derived, get, Readable, readable, writable, Writable} from "svelte/store"; import {peerStore} from "./PeerStore"; import {localUserStore} from "../Connexion/LocalUserStore"; -import {ITiledMapGroupLayer, ITiledMapObjectLayer, ITiledMapTileLayer} from "../Phaser/Map/ITiledMap"; import {userMovingStore} from "./GameStore"; import {HtmlUtils} from "../WebRtc/HtmlUtils"; import {BrowserTooOldError} from "./Errors/BrowserTooOldError"; import {errorStore} from "./ErrorStore"; import {isIOS} from "../WebRtc/DeviceUtils"; import {WebviewOnOldIOS} from "./Errors/WebviewOnOldIOS"; +import {gameOverlayVisibilityStore} from "./GameOverlayStoreVisibility"; /** * A store that contains the camera state requested by the user (on or off). @@ -50,20 +50,6 @@ export const visibilityStore = readable(document.visibilityState === 'visible', }; }); -/** - * A store that contains whether the game overlay is shown or not. - * Typically, the overlay is hidden when entering Jitsi meet. - */ -function createGameOverlayVisibilityStore() { - const { subscribe, set, update } = writable(false); - - return { - subscribe, - showGameOverlay: () => set(true), - hideGameOverlay: () => set(false), - }; -} - /** * A store that contains whether the EnableCameraScene is shown or not. */ @@ -79,7 +65,6 @@ function createEnableCameraSceneVisibilityStore() { export const requestedCameraState = createRequestedCameraState(); export const requestedMicrophoneState = createRequestedMicrophoneState(); -export const gameOverlayVisibilityStore = createGameOverlayVisibilityStore(); export const enableCameraSceneVisibilityStore = createEnableCameraSceneVisibilityStore(); /** diff --git a/front/src/Stores/PeerStore.ts b/front/src/Stores/PeerStore.ts index a582e692..df8b17ce 100644 --- a/front/src/Stores/PeerStore.ts +++ b/front/src/Stores/PeerStore.ts @@ -1,26 +1,64 @@ -import { derived, writable, Writable } from "svelte/store"; -import type {UserSimplePeerInterface} from "../WebRtc/SimplePeer"; -import type {SimplePeer} from "../WebRtc/SimplePeer"; +import {derived, get, readable, writable} from "svelte/store"; +import type {RemotePeer, SimplePeer} from "../WebRtc/SimplePeer"; +import {VideoPeer} from "../WebRtc/VideoPeer"; +import {ScreenSharingPeer} from "../WebRtc/ScreenSharingPeer"; /** - * A store that contains the camera state requested by the user (on or off). + * A store that contains the list of (video) peers we are connected to. */ function createPeerStore() { - let users = new Map(); + let peers = new Map(); - const { subscribe, set, update } = writable(users); + const { subscribe, set, update } = writable(peers); return { subscribe, connectToSimplePeer: (simplePeer: SimplePeer) => { - users = new Map(); - set(users); + peers = new Map(); + set(peers); simplePeer.registerPeerConnectionListener({ - onConnect(user: UserSimplePeerInterface) { + onConnect(peer: RemotePeer) { + if (peer instanceof VideoPeer) { + update(users => { + users.set(peer.userId, peer); + return users; + }); + } + console.log('CONNECT VIDEO', peers); + }, + onDisconnect(userId: number) { update(users => { - users.set(user.userId, user); + users.delete(userId); return users; }); + console.log('DISCONNECT VIDEO', peers); + } + }) + } + }; +} + +/** + * A store that contains the list of screen sharing peers we are connected to. + */ +function createScreenSharingPeerStore() { + let peers = new Map(); + + const { subscribe, set, update } = writable(peers); + + return { + subscribe, + connectToSimplePeer: (simplePeer: SimplePeer) => { + peers = new Map(); + set(peers); + simplePeer.registerPeerConnectionListener({ + onConnect(peer: RemotePeer) { + if (peer instanceof ScreenSharingPeer) { + update(users => { + users.set(peer.userId, peer); + return users; + }); + } }, onDisconnect(userId: number) { update(users => { @@ -34,3 +72,56 @@ function createPeerStore() { } export const peerStore = createPeerStore(); +export const screenSharingPeerStore = createScreenSharingPeerStore(); + +/** + * A store that contains ScreenSharingPeer, ONLY if those ScreenSharingPeer are emitting a stream towards us! + */ +function createScreenSharingStreamStore() { + let peers = new Map(); + + return readable>(peers, function start(set) { + + let unsubscribes: (()=>void)[] = []; + + const unsubscribe = screenSharingPeerStore.subscribe((screenSharingPeers) => { + for (const unsubscribe of unsubscribes) { + unsubscribe(); + } + unsubscribes = []; + + peers = new Map(); + + screenSharingPeers.forEach((screenSharingPeer: ScreenSharingPeer, key: number) => { + + if (screenSharingPeer.isReceivingScreenSharingStream()) { + peers.set(key, screenSharingPeer); + } + + unsubscribes.push(screenSharingPeer.streamStore.subscribe((stream) => { + if (stream) { + peers.set(key, screenSharingPeer); + } else { + peers.delete(key); + } + set(peers); + })); + + }); + + set(peers); + + }); + + return function stop() { + unsubscribe(); + for (const unsubscribe of unsubscribes) { + unsubscribe(); + } + }; + }) +} + +export const screenSharingStreamStore = createScreenSharingStreamStore(); + + diff --git a/front/src/Stores/ScreenSharingStore.ts b/front/src/Stores/ScreenSharingStore.ts index ec5aa46f..41d450c2 100644 --- a/front/src/Stores/ScreenSharingStore.ts +++ b/front/src/Stores/ScreenSharingStore.ts @@ -1,16 +1,10 @@ import {derived, get, Readable, readable, writable, Writable} from "svelte/store"; import {peerStore} from "./PeerStore"; -import {localUserStore} from "../Connexion/LocalUserStore"; -import {ITiledMapGroupLayer, ITiledMapObjectLayer, ITiledMapTileLayer} from "../Phaser/Map/ITiledMap"; -import {userMovingStore} from "./GameStore"; -import {HtmlUtils} from "../WebRtc/HtmlUtils"; -import { - audioConstraintStore, cameraEnergySavingStore, - enableCameraSceneVisibilityStore, - gameOverlayVisibilityStore, LocalStreamStoreValue, privacyShutdownStore, - requestedCameraState, - requestedMicrophoneState, videoConstraintStore +import type { + LocalStreamStoreValue, } from "./MediaStore"; +import {DivImportance} from "../WebRtc/LayoutManager"; +import {gameOverlayVisibilityStore} from "./GameOverlayStoreVisibility"; declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any @@ -191,3 +185,35 @@ export const screenSharingAvailableStore = derived(peerStore, ($peerStore, set) set($peerStore.size !== 0); }); + +export interface ScreenSharingLocalMedia { + uniqueId: string; + importanceStore: Writable; + stream: MediaStream|null; + //subscribe(this: void, run: Subscriber, invalidate?: (value?: ScreenSharingLocalMedia) => void): Unsubscriber; +} + +/** + * The representation of the screen sharing stream. + */ +export const screenSharingLocalMedia = readable(null, function start(set) { + + const localMedia: ScreenSharingLocalMedia = { + uniqueId: "localScreenSharingStream", + importanceStore: writable(DivImportance.Normal), + stream: null + } + + const unsubscribe = screenSharingLocalStreamStore.subscribe((screenSharingLocalStream) => { + if (screenSharingLocalStream.type === "success") { + localMedia.stream = screenSharingLocalStream.stream; + } else { + localMedia.stream = null; + } + set(localMedia); + }); + + return function stop() { + unsubscribe(); + }; +}) diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index efc9660a..a71618e0 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -7,7 +7,7 @@ import type {UserSimplePeerInterface} from "./SimplePeer"; import {SoundMeter} from "../Phaser/Components/SoundMeter"; import {DISABLE_NOTIFICATIONS} from "../Enum/EnvironmentVariable"; import { - gameOverlayVisibilityStore, localStreamStore, + localStreamStore, } from "../Stores/MediaStore"; import { screenSharingLocalStreamStore @@ -22,6 +22,7 @@ export type ShowReportCallBack = (userId: string, userName: string|undefined) => export type HelpCameraSettingsCallBack = () => void; import {cowebsiteCloseButtonId} from "./CoWebsiteManager"; +import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility"; export class MediaManager { private remoteVideo: Map = new Map(); @@ -65,7 +66,7 @@ export class MediaManager { } }); - let isScreenSharing = false; + //let isScreenSharing = false; screenSharingLocalStreamStore.subscribe((result) => { if (result.type === 'error') { console.error(result.error); @@ -75,7 +76,7 @@ export class MediaManager { return; } - if (result.stream !== null) { + /*if (result.stream !== null) { isScreenSharing = true; this.addScreenSharingActiveVideo('me', DivImportance.Normal); HtmlUtils.getElementByIdOrFail('screen-sharing-me').srcObject = result.stream; @@ -84,7 +85,7 @@ export class MediaManager { isScreenSharing = false; this.removeActiveScreenSharingVideo('me'); } - } + }*/ }); @@ -134,7 +135,7 @@ export class MediaManager { gameOverlayVisibilityStore.hideGameOverlay(); } - addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){ + /*addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){ const userId = ''+user.userId userName = userName.toUpperCase(); @@ -194,7 +195,7 @@ export class MediaManager { layoutManager.add(divImportance, userId, html); this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail(userId)); - } + }*/ private getScreenSharingId(userId: string): string { return `screen-sharing-${userId}`; @@ -242,19 +243,12 @@ export class MediaManager { const blockLogoElement = HtmlUtils.getElementByIdOrFail('blocking-'+userId); show ? blockLogoElement.classList.add('active') : blockLogoElement.classList.remove('active'); } - addStreamRemoteVideo(userId: string, stream : MediaStream): void { + /*addStreamRemoteVideo(userId: string, stream : MediaStream): void { const remoteVideo = this.remoteVideo.get(userId); if (remoteVideo === undefined) { throw `Unable to find video for ${userId}`; } remoteVideo.srcObject = stream; - - //FIX ME SOUNDMETER: check stalability of sound meter calculation - //sound metter - /*const soundMeter = new SoundMeter(); - soundMeter.connectToSource(stream, new AudioContext()); - this.soundMeters.set(userId, soundMeter); - this.soundMeterElements.set(userId, HtmlUtils.getElementByIdOrFail('soundMeter-'+userId));*/ } addStreamRemoteScreenSharing(userId: string, stream : MediaStream){ // In the case of screen sharing (going both ways), we may need to create the HTML element if it does not exist yet @@ -264,23 +258,18 @@ export class MediaManager { } this.addStreamRemoteVideo(this.getScreenSharingId(userId), stream); - } + }*/ removeActiveVideo(userId: string){ - layoutManager.remove(userId); - this.remoteVideo.delete(userId); - - //FIX ME SOUNDMETER: check stalability of sound meter calculation - /*this.soundMeters.get(userId)?.stop(); - this.soundMeters.delete(userId); - this.soundMeterElements.delete(userId);*/ + //layoutManager.remove(userId); + //this.remoteVideo.delete(userId); //permit to remove user in discussion part this.removeParticipant(userId); } - removeActiveScreenSharingVideo(userId: string) { + /*removeActiveScreenSharingVideo(userId: string) { this.removeActiveVideo(this.getScreenSharingId(userId)) - } + }*/ isConnecting(userId: string): void { const connectingSpinnerDiv = this.getSpinner(userId); diff --git a/front/src/WebRtc/ScreenSharingPeer.ts b/front/src/WebRtc/ScreenSharingPeer.ts index d797f59b..49026971 100644 --- a/front/src/WebRtc/ScreenSharingPeer.ts +++ b/front/src/WebRtc/ScreenSharingPeer.ts @@ -1,9 +1,11 @@ import type * as SimplePeerNamespace from "simple-peer"; import {mediaManager} from "./MediaManager"; -import {STUN_SERVER, TURN_SERVER, TURN_USER, TURN_PASSWORD} from "../Enum/EnvironmentVariable"; +import {STUN_SERVER, TURN_PASSWORD, TURN_SERVER, TURN_USER} from "../Enum/EnvironmentVariable"; import type {RoomConnection} from "../Connexion/RoomConnection"; import {MESSAGE_TYPE_CONSTRAINT} from "./VideoPeer"; import type {UserSimplePeerInterface} from "./SimplePeer"; +import {Readable, readable, writable, Writable} from "svelte/store"; +import {DivImportance} from "./LayoutManager"; const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer'); @@ -17,9 +19,13 @@ export class ScreenSharingPeer extends Peer { private isReceivingStream:boolean = false; public toClose: boolean = false; public _connected: boolean = false; - private userId: number; + public readonly userId: number; + public readonly uniqueId: string; + public readonly streamStore: Readable; + public readonly importanceStore: Writable; + public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">; - constructor(user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection, stream: MediaStream | null) { + constructor(user: UserSimplePeerInterface, initiator: boolean, public readonly userName: string, private connection: RoomConnection, stream: MediaStream | null) { super({ initiator: initiator ? initiator : false, //reconnectTimer: 10000, @@ -38,6 +44,56 @@ export class ScreenSharingPeer extends Peer { }); this.userId = user.userId; + this.uniqueId = 'screensharing_'+this.userId; + + this.streamStore = readable(null, (set) => { + const onStream = (stream: MediaStream|null) => { + set(stream); + }; + const onData = (chunk: Buffer) => { + // We unfortunately need to rely on an event to let the other party know a stream has stopped. + // It seems there is no native way to detect that. + // TODO: we might rely on the "ended" event: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended_event + const message = JSON.parse(chunk.toString('utf8')); + if (message.streamEnded !== true) { + console.error('Unexpected message on screen sharing peer connection'); + return; + } + set(null); + } + + this.on('stream', onStream); + this.on('data', onData); + + return () => { + this.off('stream', onStream); + this.off('data', onData); + }; + }); + + this.importanceStore = writable(DivImportance.Important); + + this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => { + const onConnect = () => { + set('connected'); + }; + const onError = () => { + set('error'); + }; + const onClose = () => { + set('closed'); + }; + + this.on('connect', onConnect); + this.on('error', onError); + this.on('close', onClose); + + return () => { + this.off('connect', onConnect); + this.off('error', onError); + this.off('close', onClose); + }; + }); //start listen signal for the peer connection this.on('signal', (data: unknown) => { @@ -54,16 +110,17 @@ export class ScreenSharingPeer extends Peer { this.destroy(); }); - this.on('data', (chunk: Buffer) => { + /*this.on('data', (chunk: Buffer) => { // We unfortunately need to rely on an event to let the other party know a stream has stopped. // It seems there is no native way to detect that. + // TODO: we might rely on the "ended" event: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended_event const message = JSON.parse(chunk.toString('utf8')); if (message.streamEnded !== true) { console.error('Unexpected message on screen sharing peer connection'); return; } mediaManager.removeActiveScreenSharingVideo("" + this.userId); - }); + });*/ // eslint-disable-next-line @typescript-eslint/no-explicit-any this.on('error', (err: any) => { @@ -103,10 +160,10 @@ export class ScreenSharingPeer extends Peer { //console.log(`ScreenSharingPeer::stream => ${this.userId}`, stream); //console.log(`stream => ${this.userId} => `, stream); if(!stream){ - mediaManager.removeActiveScreenSharingVideo("" + this.userId); + //mediaManager.removeActiveScreenSharingVideo("" + this.userId); this.isReceivingStream = false; } else { - mediaManager.addStreamRemoteScreenSharing("" + this.userId, stream); + //mediaManager.addStreamRemoteScreenSharing("" + this.userId, stream); this.isReceivingStream = true; } } @@ -121,7 +178,7 @@ export class ScreenSharingPeer extends Peer { if(!this.toClose){ return; } - mediaManager.removeActiveScreenSharingVideo("" + this.userId); + //mediaManager.removeActiveScreenSharingVideo("" + this.userId); // FIXME: I don't understand why "Closing connection with" message is displayed TWICE before "Nb users in peerConnectionArray" // I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel. //console.log('Closing connection with '+userId); diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts index 2a502bab..7c6264a9 100644 --- a/front/src/WebRtc/SimplePeer.ts +++ b/front/src/WebRtc/SimplePeer.ts @@ -28,8 +28,10 @@ export interface UserSimplePeerInterface{ webRtcPassword?: string|undefined; } +export type RemotePeer = VideoPeer | ScreenSharingPeer; + export interface PeerConnectionListener { - onConnect(user: UserSimplePeerInterface): void; + onConnect(user: RemotePeer): void; onDisconnect(userId: number): void; } @@ -159,20 +161,17 @@ export class SimplePeer { let name = user.name; if (!name) { - const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === user.userId); - if (userSearch) { - name = userSearch.name; - } + name = this.getName(user.userId); } mediaManager.removeActiveVideo("" + user.userId); - mediaManager.addActiveVideo(user, name); + //mediaManager.addActiveVideo(user, name); this.lastWebrtcUserName = user.webRtcUser; this.lastWebrtcPassword = user.webRtcPassword; - const peer = new VideoPeer(user, user.initiator ? user.initiator : false, this.Connection, localStream); + const peer = new VideoPeer(user, user.initiator ? user.initiator : false, name, this.Connection, localStream); //permit to send message mediaManager.addSendMessageCallback(user.userId,(message: string) => { @@ -196,11 +195,20 @@ export class SimplePeer { this.PeerConnectionArray.set(user.userId, peer); for (const peerConnectionListener of this.peerConnectionListeners) { - peerConnectionListener.onConnect(user); + peerConnectionListener.onConnect(peer); } return peer; } + private getName(userId: number): string { + const userSearch = this.Users.find((userSearch: UserSimplePeerInterface) => userSearch.userId === userId); + if (userSearch) { + return userSearch.name || ''; + } else { + return ''; + } + } + /** * create peer connection to bind users */ @@ -222,10 +230,10 @@ export class SimplePeer { } // We should display the screen sharing ONLY if we are not initiator - if (!user.initiator) { +/* if (!user.initiator) { mediaManager.removeActiveScreenSharingVideo("" + user.userId); mediaManager.addScreenSharingActiveVideo("" + user.userId); - } + }*/ // Enrich the user with last known credentials (if they are not set in the user object, which happens when a user triggers the screen sharing) if (user.webRtcUser === undefined) { @@ -233,11 +241,13 @@ export class SimplePeer { user.webRtcPassword = this.lastWebrtcPassword; } - const peer = new ScreenSharingPeer(user, user.initiator ? user.initiator : false, this.Connection, stream); + const name = this.getName(user.userId); + + const peer = new ScreenSharingPeer(user, user.initiator ? user.initiator : false, name, this.Connection, stream); this.PeerScreenSharingConnectionArray.set(user.userId, peer); for (const peerConnectionListener of this.peerConnectionListeners) { - peerConnectionListener.onConnect(user); + peerConnectionListener.onConnect(peer); } return peer; } @@ -288,7 +298,7 @@ export class SimplePeer { */ private closeScreenSharingConnection(userId : number) { try { - mediaManager.removeActiveScreenSharingVideo("" + userId); + //mediaManager.removeActiveScreenSharingVideo("" + userId); const peer = this.PeerScreenSharingConnectionArray.get(userId); if (peer === undefined) { console.warn("closeScreenSharingConnection => Tried to close connection for user "+userId+" but could not find user") diff --git a/front/src/WebRtc/VideoPeer.ts b/front/src/WebRtc/VideoPeer.ts index 5ca8952c..c69bc4cd 100644 --- a/front/src/WebRtc/VideoPeer.ts +++ b/front/src/WebRtc/VideoPeer.ts @@ -5,8 +5,9 @@ import type {RoomConnection} from "../Connexion/RoomConnection"; import {blackListManager} from "./BlackListManager"; import type {Subscription} from "rxjs"; import type {UserSimplePeerInterface} from "./SimplePeer"; -import {get} from "svelte/store"; +import {get, readable, Readable, writable, Writable} from "svelte/store"; import {obtainedMediaConstraintStore} from "../Stores/MediaStore"; +import {DivImportance} from "./LayoutManager"; const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer'); @@ -22,12 +23,16 @@ export class VideoPeer extends Peer { public _connected: boolean = false; private remoteStream!: MediaStream; private blocked: boolean = false; - private userId: number; - private userName: string; + public readonly userId: number; + public readonly uniqueId: string; private onBlockSubscribe: Subscription; private onUnBlockSubscribe: Subscription; + public readonly streamStore: Readable; + public readonly importanceStore: Writable; + public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">; + public readonly constraintsStore: Readable; - constructor(public user: UserSimplePeerInterface, initiator: boolean, private connection: RoomConnection, localStream: MediaStream | null) { + constructor(public user: UserSimplePeerInterface, initiator: boolean, public readonly userName: string, private connection: RoomConnection, localStream: MediaStream | null) { super({ initiator: initiator ? initiator : false, //reconnectTimer: 10000, @@ -46,7 +51,70 @@ export class VideoPeer extends Peer { }); this.userId = user.userId; - this.userName = user.name || ''; + this.uniqueId = 'video_'+this.userId; + + this.streamStore = readable(null, (set) => { + const onStream = (stream: MediaStream|null) => { + set(stream); + }; + const onData = (chunk: Buffer) => { + this.on('data', (chunk: Buffer) => { + const message = JSON.parse(chunk.toString('utf8')); + if (message.type === MESSAGE_TYPE_CONSTRAINT) { + if (!message.video) { + set(null); + } + } + }); + } + + this.on('stream', onStream); + this.on('data', onData); + + return () => { + this.off('stream', onStream); + this.off('data', onData); + }; + }); + + this.constraintsStore = readable(null, (set) => { + const onData = (chunk: Buffer) => { + const message = JSON.parse(chunk.toString('utf8')); + if(message.type === MESSAGE_TYPE_CONSTRAINT) { + set(message); + } + } + + this.on('data', onData); + + return () => { + this.off('data', onData); + }; + }); + + this.importanceStore = writable(DivImportance.Normal); + + this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => { + const onConnect = () => { + set('connected'); + }; + const onError = () => { + set('error'); + }; + const onClose = () => { + set('closed'); + }; + + this.on('connect', onConnect); + this.on('error', onError); + this.on('close', onClose); + + return () => { + this.off('connect', onConnect); + this.off('error', onError); + this.off('close', onClose); + }; + }); //start listen signal for the peer connection this.on('signal', (data: unknown) => { @@ -152,7 +220,7 @@ export class VideoPeer extends Peer { if (blackListManager.isBlackListed(this.userId) || this.blocked) { this.toggleRemoteStream(false); } - mediaManager.addStreamRemoteVideo("" + this.userId, stream); + //mediaManager.addStreamRemoteVideo("" + this.userId, stream); }catch (err){ console.error(err); } From ac7fa164b6e39052bd8354e8c917418949abbf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 14 Jun 2021 17:59:50 +0200 Subject: [PATCH 069/189] Adding importance handling --- .../Components/Video/LocalStreamMedia.svelte | 7 +++-- front/src/Components/Video/Peer.svelte | 2 +- .../Video/ScreenSharingMedia.svelte | 2 +- front/src/Components/Video/VideoMedia.svelte | 5 +++- front/src/Stores/ImportanceStore.ts | 26 +++++++++++++++++++ front/src/Stores/ScreenSharingStore.ts | 5 ++-- front/src/WebRtc/ScreenSharingPeer.ts | 6 +++-- front/src/WebRtc/VideoPeer.ts | 6 +++-- 8 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 front/src/Stores/ImportanceStore.ts diff --git a/front/src/Components/Video/LocalStreamMedia.svelte b/front/src/Components/Video/LocalStreamMedia.svelte index 43b1d117..375612a6 100644 --- a/front/src/Components/Video/LocalStreamMedia.svelte +++ b/front/src/Components/Video/LocalStreamMedia.svelte @@ -1,4 +1,6 @@
- +
diff --git a/front/src/Components/Video/Peer.svelte b/front/src/Components/Video/Peer.svelte index c73d620e..8d5637f6 100644 --- a/front/src/Components/Video/Peer.svelte +++ b/front/src/Components/Video/Peer.svelte @@ -15,6 +15,6 @@ {:else if peer instanceof ScreenSharingPeer} {:else} - + {/if}
diff --git a/front/src/Components/Video/ScreenSharingMedia.svelte b/front/src/Components/Video/ScreenSharingMedia.svelte index e16fac58..0dbc3c16 100644 --- a/front/src/Components/Video/ScreenSharingMedia.svelte +++ b/front/src/Components/Video/ScreenSharingMedia.svelte @@ -45,7 +45,7 @@ {#if $streamStore === null} {name} {/if} - + diff --git a/front/src/Components/Video/VideoOverlay.svelte b/front/src/Components/Video/VideoOverlay.svelte index 5ba7fbc7..88c1cd42 100644 --- a/front/src/Components/Video/VideoOverlay.svelte +++ b/front/src/Components/Video/VideoOverlay.svelte @@ -3,18 +3,23 @@ import {DivImportance} from "../../WebRtc/LayoutManager"; import Peer from "./Peer.svelte"; import {layoutStore} from "../../Stores/LayoutStore"; + import {videoFocusStore} from "../../Stores/VideoFocusStore";
- {#each [...$layoutStore.get(DivImportance.Important).values()] as peer (peer.uniqueId)} - + {#each [...$layoutStore.values()] as peer (peer.uniqueId)} + {#if $videoFocusStore && peer === $videoFocusStore } + + {/if} {/each}

= P extends Promise ? T : P - -type WorkadventureCommandClasses = PromiseReturnType[number]["default"]; - -type KeysOfUnion = T extends T ? keyof T : never - -type ObjectWithKeyOfUnion = O extends O ? (Key extends keyof O ? O[Key] : never) : never - -type ApiKeys = KeysOfUnion; - -type ObjectOfKey = O extends O ? (Key extends keyof O ? O : never) : never - -type ShouldAddAttribute = ObjectWithKeyOfUnion; - -type WorkadventureFunctions = { [K in ApiKeys]: ObjectWithKeyOfUnion extends Function ? K : never }[ApiKeys] - -type WorkadventureFunctionsFilteredByRoot = { [K in WorkadventureFunctions]: ObjectOfKey["addMethodsAtRoot"] extends true ? K : never }[WorkadventureFunctions] - - -type JustMethodKeys = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T]; -type JustMethods = Pick>; - -type SubObjectTypes = { - [importCl in WorkadventureCommandClasses as importCl["subObjectIdentifier"]]: JustMethods; -}; - -type WorkAdventureApi = { - [Key in WorkadventureFunctionsFilteredByRoot]: ShouldAddAttribute -} & SubObjectTypes - +export type WorkadventureImport = typeof importType declare global { From 8a1376e966f49afaace294ba0e5e7b51964e9972 Mon Sep 17 00:00:00 2001 From: jonny Date: Fri, 28 May 2021 02:28:11 +0200 Subject: [PATCH 057/189] refactored to key based types --- front/src/Api/iframe/IframeApiContribution.ts | 23 +++++++++++-------- front/src/iframe_api.ts | 17 +++++++------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts index dc261762..77739f7e 100644 --- a/front/src/Api/iframe/IframeApiContribution.ts +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -9,21 +9,28 @@ export function sendToWorkadventure(content: IframeEvent) } type GuardedType> = Guard extends tg.TypeGuard ? T : never -export function apiCallback>(callbackData: IframeCallbackContribution) { - registeredCallbacks[callbackData.type] = { +export function apiCallback(callbackData: IframeCallbackContribution): IframeCallbackContribution { + const iframeCallback = { typeChecker: callbackData.typeChecker, callback: callbackData.callback - } - return callbackData + } as IframeCallback; + + const newCallback = { [callbackData.type]: iframeCallback }; + Object.assign(registeredCallbacks, newCallback) + return callbackData as unknown as IframeCallbackContribution; } -export interface IframeCallbackContribution, T = GuardedType> { +export interface IframeCallback> { - type: keyof IframeResponseEventMap, typeChecker: Guard, callback: (payloadData: T) => void } +export interface IframeCallbackContribution extends IframeCallback { + + type: Key +} + export type PossibleSubobjects = "zone" | "chat" | "ui" | "nav" | "sound" | "cowebsite" | "player" | "bubble" /** * !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly @@ -32,9 +39,7 @@ export type PossibleSubobjects = "zone" | "chat" | "ui" | "nav" | "sound" | "cow */ export abstract class IframeApiContribution>>, + callbacks: Array>, readonly subObjectIdentifier: PossibleSubobjects, readonly addMethodsAtRoot: boolean | undefined }> { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 136edb8e..60080303 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,10 +1,9 @@ -import { IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; +import { IframeResponseEvent, IframeResponseEventMap, isIframeResponseEventWrapper, TypedMessageEvent } from "./Api/Events/IframeEvent"; +import type { IframeCallback } from './Api/iframe/IframeApiContribution'; import type { WorkAdventureApi } from './iframe_api.d'; -export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: { - typeChecker: Function - callback: Function -} } = {} + +export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: IframeCallback } = {} const importType = Promise.all([ import("./Api/iframe/popup"), @@ -52,7 +51,7 @@ async function populateWa(): Promise { populateWa() -window.addEventListener('message', message => { +window.addEventListener('message', (message: TypedMessageEvent>) => { if (message.source !== window.parent) { return; // Skip message in this event listener } @@ -62,9 +61,9 @@ window.addEventListener('message', message => { if (isIframeResponseEventWrapper(payload)) { const payloadData = payload.data; - if (registeredCallbacks[payload.type] && registeredCallbacks[payload.type]?.typeChecker(payloadData)) { - registeredCallbacks[payload.type]?.callback(payloadData) - return + const callback = registeredCallbacks[payload.type] as IframeCallback | undefined + if (callback?.typeChecker(payloadData)) { + callback?.callback(payloadData) } } From 858a513569026d4566857919731dbc21d44d221d Mon Sep 17 00:00:00 2001 From: GRL Date: Fri, 28 May 2021 12:13:10 +0200 Subject: [PATCH 058/189] correction of adding custom menu correction of setProperty updating CHANGELOG updating api-reference --- CHANGELOG.md | 7 +++++ docs/maps/api-reference.md | 2 +- front/src/Api/Events/IframeEvent.ts | 5 ++- front/src/Api/IframeListener.ts | 20 ++++++++---- front/src/Phaser/Game/GameMap.ts | 8 ++--- front/src/Phaser/Game/GameScene.ts | 7 ----- front/src/Phaser/Menu/MenuScene.ts | 7 +++++ front/src/iframe_api.ts | 25 +++------------ maps/tests/index.html | 48 +++++++++++++++++++++++++++++ 9 files changed, 87 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dec14540..68a7016f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,13 @@ - Improved virtual joystick size (adapts to the zoom level) - New scripting API features: - Use `WA.loadSound(): Sound` to load / play / stop a sound + - Use `WA.showLayer(): void` to show a layer + - Use `WA.hideLayer(): void` to hide a layer + - Use `WA.setProperty() : void` to add or change existing property of a layer + - Use `WA.onPlayerMove(): void` to track the movement of the current player + - Use `WA.getCurrentUser(): Promise` to get the ID, name and tags of the current player + - Use `WA.getCurrentRoom(): Promise` to get the ID, JSON map file, url of the map of the current room and the layer where the current player started + - Use `WA.registerMenuCommand(): void` to add a custom menu ### Bug Fixes diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 6a4dd7ab..d4316772 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -323,7 +323,7 @@ WA.getCurrentRoom((room) => { ### Add a custom menu ``` -registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) +registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void ``` Add a custom menu item containing the text `commandDescriptor`. A click on the menu will trigger the `callback`. diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index bb15528d..e5b1c30b 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -15,8 +15,8 @@ import type { UserInputChatEvent } from './UserInputChatEvent'; import type { DataLayerEvent } from "./DataLayerEvent"; import type { LayerEvent } from './LayerEvent'; import type { SetPropertyEvent } from "./setPropertyEvent"; -import type {LoadSoundEvent} from "./LoadSoundEvent"; -import type {PlaySoundEvent} from "./PlaySoundEvent"; +import type { LoadSoundEvent } from "./LoadSoundEvent"; +import type { PlaySoundEvent } from "./PlaySoundEvent"; export interface TypedMessageEvent extends MessageEvent { @@ -42,7 +42,6 @@ export type IframeEventMap = { hideLayer: LayerEvent setProperty: SetPropertyEvent getDataLayer: undefined - //tilsetEvent: TilesetEvent loadSound: LoadSoundEvent playSound: PlaySoundEvent stopSound: null diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index ceeea1c4..d05b416f 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -20,7 +20,6 @@ import { Math } from 'phaser'; import type { DataLayerEvent } from "./Events/DataLayerEvent"; import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; import type { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; -//import { isTilesetEvent, TilesetEvent } from "./Events/TilesetEvent"; import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent"; import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent"; import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent"; @@ -81,8 +80,8 @@ class IframeListener { private readonly _registerMenuCommandStream: Subject = new Subject(); public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); -/* private readonly _tilesetLoaderStream: Subject = new Subject(); - public readonly tilesetLoaderStream = this._tilesetLoaderStream.asObservable();*/ + private readonly _unregisterMenuCommandStream: Subject = new Subject(); + public readonly unregisterMenuCommandStream = this._unregisterMenuCommandStream.asObservable(); private readonly _playSoundStream: Subject = new Subject(); public readonly playSoundStream = this._playSoundStream.asObservable(); @@ -94,6 +93,7 @@ class IframeListener { public readonly loadSoundStream = this._loadSoundStream.asObservable(); private readonly iframes = new Set(); + private readonly iframeCloseCallbacks = new Map void)[]>(); private readonly scripts = new Map(); private sendPlayerMove: boolean = false; @@ -103,7 +103,8 @@ class IframeListener { // Let's only accept messages from the iframe that are allowed. // Note: maybe we could restrict on the domain too for additional security (in case the iframe goes to another domain). let foundSrc: string | null = null; - for (const iframe of this.iframes) { + let iframe: HTMLIFrameElement; + for (iframe of this.iframes) { if (iframe.contentWindow === message.source) { foundSrc = iframe.src; break; @@ -171,9 +172,12 @@ class IframeListener { } else if (payload.type == "getDataLayer") { this._dataLayerChangeStream.next(); } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { + const data = payload.data.menutItem; + // @ts-ignore + this.iframeCloseCallbacks.get(iframe).push(() => { + this._unregisterMenuCommandStream.next(data); + }) this._registerMenuCommandStream.next(payload.data.menutItem) -/* } else if (payload.type == "tilsetEvent" && isTilesetEvent(payload.data)) { - this._tilesetLoaderStream.next(payload.data);*/ } } }, false); @@ -200,9 +204,13 @@ class IframeListener { */ registerIframe(iframe: HTMLIFrameElement): void { this.iframes.add(iframe); + this.iframeCloseCallbacks.set(iframe, []); } unregisterIframe(iframe: HTMLIFrameElement): void { + this.iframeCloseCallbacks.get(iframe)?.forEach(callback => { + callback(); + }); this.iframes.delete(iframe); } diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 34f55d0b..873b6062 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -1,7 +1,7 @@ -import type {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap"; +import type { ITiledMap, ITiledMapLayer } from "../Map/ITiledMap"; import { flattenGroupLayersMap } from "../Map/LayersFlattener"; import TilemapLayer = Phaser.Tilemaps.TilemapLayer; -import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes"; +import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes"; export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map) => void; @@ -118,11 +118,11 @@ export class GameMap { } public findLayer(layerName: string): ITiledMapLayer | undefined { - return this.flatLayers.find((layer) => layer.name = layerName); + return this.flatLayers.find((layer) => layer.name === layerName); } public findPhaserLayer(layerName: string): TilemapLayer | undefined { - return this.phaserLayers.find((layer) => layer.layer.name = layerName); + return this.phaserLayers.find((layer) => layer.layer.name === layerName); } public addTerrain(terrain : Phaser.Tilemaps.Tileset): void { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 1e4c55f5..cb2ec0a0 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -927,13 +927,6 @@ ${escapedMessage} }) })); -/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => { - //this.load.tilemapTiledJSON('logo', tileset.imgUrl); - this.load.image('logo', tileset.imgUrl); - this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing)); - this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]); - }))*/ - } private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void { diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 8957bbce..8a01c259 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -49,7 +49,10 @@ export class MenuScene extends Phaser.Scene { this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => { this.addMenuOption(menuCommand); + })) + this.subscriptions.add(iframeListener.unregisterMenuCommandStream.subscribe(menuCommand => { + this.destroyMenu(menuCommand); })) } @@ -386,6 +389,10 @@ export class MenuScene extends Phaser.Scene { } } + public destroyMenu(menu: string) { + this.menuElement.getChildByID(menu).remove(); + } + public isDirty(): boolean { return false; } diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index f76c4218..61a3c890 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -17,9 +17,9 @@ import { DataLayerEvent, isDataLayerEvent } from "./Api/Events/DataLayerEvent"; import type { ITiledMap } from "./Phaser/Map/ITiledMap"; import type { MenuItemRegisterEvent } from "./Api/Events/MenuItemRegisterEvent"; import { isMenuItemClickedEvent } from "./Api/Events/MenuItemClickedEvent"; -import type {PlaySoundEvent} from "./Api/Events/PlaySoundEvent"; -import type {StopSoundEvent} from "./Api/Events/StopSoundEvent"; -import type {LoadSoundEvent} from "./Api/Events/LoadSoundEvent"; +import type { PlaySoundEvent } from "./Api/Events/PlaySoundEvent"; +import type { StopSoundEvent } from "./Api/Events/StopSoundEvent"; +import type { LoadSoundEvent } from "./Api/Events/LoadSoundEvent"; import SoundConfig = Phaser.Types.Sound.SoundConfig; interface WorkAdventureApi { @@ -47,8 +47,6 @@ interface WorkAdventureApi { registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void getCurrentUser(): Promise getCurrentRoom(): Promise - //loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void; - onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void } @@ -176,7 +174,6 @@ const gameStateResolver: Array<(event: GameStateEvent) => void> = [] const dataLayerResolver: Array<(event: DataLayerEvent) => void> = [] let immutableData: GameStateEvent; -//const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {} const callbackPlayerMoved: Array<(event: HasPlayerMovedEvent) => void> = [] function postToParent(content: IframeEvent) { @@ -193,20 +190,6 @@ window.WA = { }) }, -/* loadTileset(name: string, imgUrl : string, tilewidth : number, tileheight : number, margin : number, spacing : number): void { - postToParent({ - type: "tilsetEvent", - data: { - name: name, - imgUrl: imgUrl, - tilewidth: tilewidth, - tileheight: tileheight, - margin: margin, - spacing: spacing - } as TilesetEvent - }) - },*/ - getCurrentUser(): Promise { return getGameState().then((gameState) => { return {id: gameState.uuid, nickName: gameState.nickname, tags: gameState.tags}; @@ -353,7 +336,7 @@ window.WA = { return popup; }, - registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void { menuCallbacks.set(commandDescriptor, callback); window.parent.postMessage({ 'type': 'registerMenuCommand', diff --git a/maps/tests/index.html b/maps/tests/index.html index a17a3b5d..527b435f 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -82,6 +82,54 @@ Test energy consumption + + + Success Failure Pending + + + Testing add a custom menu by scripting API + + + + + Success Failure Pending + + + Testing return current room attributes by Scripting API (Need to test from current user) + + + + + Success Failure Pending + + + Testing return current user attributes by Scripting API + + + + + Success Failure Pending + + + Test listening player movement by Scripting API + + + + + Success Failure Pending + + + Testing set a property on a layer by Scripting API + + + + + Success Failure Pending + + + Testing show or hide a layer by Scripting API + + From dab3f1f844659723fac3872fbcf7a1c7e5b334db Mon Sep 17 00:00:00 2001 From: jonny Date: Thu, 3 Jun 2021 22:01:42 +0200 Subject: [PATCH 061/189] removed zoned popups --- front/src/Api/iframe/popup.ts | 42 ----------------------------------- 1 file changed, 42 deletions(-) diff --git a/front/src/Api/iframe/popup.ts b/front/src/Api/iframe/popup.ts index f45be74c..248f06a4 100644 --- a/front/src/Api/iframe/popup.ts +++ b/front/src/Api/iframe/popup.ts @@ -1,7 +1,6 @@ import { isButtonClickedEvent } from '../Events/ButtonClickedEvent'; import type { ClosePopupEvent } from '../Events/ClosePopupEvent'; import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; -import zoneCommands from "./zone-events"; class Popup { constructor(private id: number) { } @@ -102,47 +101,6 @@ class PopupApiContribution extends IframeApiContribution { popups.set(popupId, popup) return popup; } - - - - popupInZone(options: ZonedPopupOptions) { - const objectLayerName = options.objectLayerName || options.zone - - let lastOpened = 0; - - let popup: Popup | undefined; - zoneCommands.onEnterZone(options.zone, () => { - if (options.delay) { - if (lastOpened + options.delay > Date.now()) { - return; - } - } - lastOpened = Date.now(); - popup = this.openPopup(objectLayerName, options.popupText, options.popupOptions.map(option => { - const callback = option.callback; - const popupOptions = { - ...option, - className: option.className || 'normal', - callback: () => { - if (callback && popup) { - callback(popup); - } - popup?.close(); - popup = undefined; - } - }; - - return popupOptions; - })); - }); - zoneCommands.onLeaveZone(options.zone, () => { - if (popup) { - popup.close(); - popup = undefined; - } - }); - } - } export default new PopupApiContribution() \ No newline at end of file From 7712bd685b6257c31bdb146776f5342e72b4abdc Mon Sep 17 00:00:00 2001 From: jonny Date: Tue, 15 Jun 2021 15:19:45 +0200 Subject: [PATCH 062/189] fixed merge errors --- front/src/Phaser/Game/GameScene.ts | 4 ++-- front/src/iframe_api.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index b09f5a1e..b5876d5a 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1102,10 +1102,10 @@ ${escapedMessage} } //todo: push that into the gameManager - private loadNextGame(exitSceneIdentifier: string): void { + private loadNextGame(exitSceneIdentifier: string): Promise { const {roomId, hash} = Room.getIdFromIdentifier(exitSceneIdentifier, this.MapUrlFile, this.instance); const room = new Room(roomId); - gameManager.loadMap(room, this.scene).catch(() => {}); + return gameManager.loadMap(room, this.scene).catch(() => {}); } private startUser(layer: ITiledMapTileLayer): PositionInterface { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index ea987f21..d4146fd1 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,11 +9,11 @@ import type { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; import type { OpenTabEvent } from "./Api/Events/OpenTabEvent"; import type { GoToPageEvent } from "./Api/Events/GoToPageEvent"; import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; -import type {PlaySoundEvent} from "./Api/Events/PlaySoundEvent"; -import type {StopSoundEvent} from "./Api/Events/StopSoundEvent"; -import type {LoadSoundEvent} from "./Api/Events/LoadSoundEvent"; +import type { PlaySoundEvent } from "./Api/Events/PlaySoundEvent"; +import type { StopSoundEvent } from "./Api/Events/StopSoundEvent"; +import type { LoadSoundEvent } from "./Api/Events/LoadSoundEvent"; import SoundConfig = Phaser.Types.Sound.SoundConfig; -import { LoadPageEvent } from './Api/Events/LoadPageEvent'; +import type { LoadPageEvent } from './Api/Events/LoadPageEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; From 085a4d41fdfe08aa3fb957a10e7716bbb8ad4a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 15 Jun 2021 18:08:16 +0200 Subject: [PATCH 063/189] Adding svelte-check to the build process Type checking in Svelte was not enabled (because we were not running svelte-check). This PR adds: - run svelte-check in watch mode in development - run svelte-check in CI --- .github/workflows/continuous_integration.yml | 4 + front/package.json | 9 +- front/yarn.lock | 199 ++++++++++++++++++- 3 files changed, 201 insertions(+), 11 deletions(-) diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index 06c1c58e..2036e4e6 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -52,6 +52,10 @@ jobs: PUSHER_URL: "//localhost:8080" working-directory: "front" + - name: "Svelte check" + run: yarn run svelte-check + working-directory: "front" + - name: "Lint" run: yarn run lint working-directory: "front" diff --git a/front/package.json b/front/package.json index 1c938195..05d3e29c 100644 --- a/front/package.json +++ b/front/package.json @@ -20,9 +20,11 @@ "jasmine": "^3.5.0", "mini-css-extract-plugin": "^1.6.0", "node-polyfill-webpack-plugin": "^1.1.2", + "npm-run-all": "^4.1.5", "sass": "^1.32.12", "sass-loader": "^11.1.0", "svelte": "^3.38.2", + "svelte-check": "^2.1.0", "svelte-loader": "^3.1.1", "svelte-preprocess": "^4.7.3", "ts-loader": "^9.1.2", @@ -50,10 +52,13 @@ "standardized-audio-context": "^25.2.4" }, "scripts": { - "start": "TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open", + "start": "run-p serve svelte-check-watch", + "serve": "TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open", "build": "TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack", "test": "TS_NODE_PROJECT=\"tsconfig-for-jasmine.json\" ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json", "lint": "node_modules/.bin/eslint src/ . --ext .ts", - "fix": "node_modules/.bin/eslint --fix src/ . --ext .ts" + "fix": "node_modules/.bin/eslint --fix src/ . --ext .ts", + "svelte-check-watch": "svelte-check --fail-on-warnings --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\" --watch", + "svelte-check": "svelte-check --fail-on-warnings --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\"" } } diff --git a/front/yarn.lock b/front/yarn.lock index dc43f559..e64a76c1 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -651,7 +651,7 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@~3.1.1: +anymatch@~3.1.1, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -1112,7 +1112,7 @@ caniuse-lite@^1.0.30001219: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== -chalk@^2.0.0: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1163,6 +1163,21 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" +chokidar@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -1402,7 +1417,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2365,7 +2380,7 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@~2.3.1: +fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -2429,7 +2444,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -2606,6 +2621,11 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -3177,7 +3197,7 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -3282,6 +3302,16 @@ linked-list-typescript@^1.0.11: resolved "https://registry.yarnpkg.com/linked-list-typescript/-/linked-list-typescript-1.0.15.tgz#faeed93cf9203f102e2158c29edcddda320abe82" integrity sha512-RIyUu9lnJIyIaMe63O7/aFv/T2v3KsMFuXMBbUQCHX+cgtGro86ETDj5ed0a8gQL2+DFjzYYsgVG4I36/cUwgw== +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" @@ -3396,6 +3426,11 @@ memory-fs@^0.4.1: errno "^0.1.3" readable-stream "^2.0.1" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -3529,6 +3564,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.5: dependencies: minimist "^1.2.5" +mri@^1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6" + integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3657,6 +3697,16 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -3669,6 +3719,21 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -3899,6 +3964,14 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -3987,6 +4060,13 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -4034,11 +4114,21 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -4288,6 +4378,15 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + readable-stream@^2.0.1, readable-stream@^2.0.2: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" @@ -4326,6 +4425,13 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + rechoir@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca" @@ -4444,7 +4550,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.9.0: +resolve@^1.10.0, resolve@^1.9.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -4503,6 +4609,13 @@ rxjs@^6.6.3: dependencies: tslib "^1.9.0" +sade@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691" + integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA== + dependencies: + mri "^1.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -4579,7 +4692,7 @@ selfsigned@^1.10.8: dependencies: node-forge "^0.10.0" -semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -4714,6 +4827,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + signal-exit@^3.0.0, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -4867,6 +4985,32 @@ source-map@^0.7.3, source-map@~0.7.2: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" + integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -4960,6 +5104,15 @@ string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string.prototype.padend@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" + integrity sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" @@ -5059,6 +5212,21 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +svelte-check@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-2.1.0.tgz#3ee8ad86068256346ebca862bbee8417a757fc53" + integrity sha512-kKLXkFt0XZTn+O1fnilGTQ1SFLsOFF+lXp1YjPfeN9nX+Y3ZpELtZSQCkbuK6HMkWugFvsOM17FCOSa1mfrEFA== + dependencies: + chalk "^4.0.0" + chokidar "^3.4.1" + glob "^7.1.6" + import-fresh "^3.2.1" + minimist "^1.2.5" + sade "^1.7.4" + source-map "^0.7.3" + svelte-preprocess "^4.0.0" + typescript "*" + svelte-dev-helper@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/svelte-dev-helper/-/svelte-dev-helper-1.1.9.tgz#7d187db5c6cdbbd64d75a32f91b8998bde3273c3" @@ -5078,7 +5246,7 @@ svelte-loader@^3.1.1: svelte-dev-helper "^1.1.9" svelte-hmr "^0.12.3" -svelte-preprocess@^4.7.3: +svelte-preprocess@^4.0.0, svelte-preprocess@^4.7.3: version "4.7.3" resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-4.7.3.tgz#454fa059c2400b15e7a3caeca18993cff9df0e96" integrity sha512-Zx1/xLeGOIBlZMGPRCaXtlMe4ZA0faato5Dc3CosEqwu75MIEPuOstdkH6cy+RYTUYynoxzNaDxkPX4DbrPwRA== @@ -5283,6 +5451,11 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typescript@*: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== + typescript@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" @@ -5408,6 +5581,14 @@ v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" From 0afdbf704091a901b3bf36af9545d860bd45b679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 15 Jun 2021 18:34:11 +0200 Subject: [PATCH 064/189] Fixing Svelte-check errors --- front/package.json | 4 +- front/src/Components/App.svelte | 6 +-- .../CustomCharacterScene.svelte | 8 ++-- .../EnableCamera/EnableCameraScene.svelte | 16 ++++---- .../HorizontalSoundMeterWidget.svelte | 2 +- front/src/Components/Login/LoginScene.svelte | 7 ++-- front/src/Components/MyCamera.svelte | 8 ++-- .../SelectCompanionScene.svelte | 6 +-- front/src/Components/SoundMeterWidget.svelte | 2 +- front/src/Components/UI/AudioPlaying.svelte | 2 +- .../src/Components/VisitCard/VisitCard.svelte | 2 +- .../SelectCharacterScene.svelte | 8 ++-- front/src/Phaser/Login/CustomizeScene.ts | 4 +- .../src/Phaser/Login/SelectCharacterScene.ts | 10 ++--- front/src/ambient.d.ts | 38 +++++++++++++++++++ 15 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 front/src/ambient.d.ts diff --git a/front/package.json b/front/package.json index 05d3e29c..f6b99bcb 100644 --- a/front/package.json +++ b/front/package.json @@ -58,7 +58,7 @@ "test": "TS_NODE_PROJECT=\"tsconfig-for-jasmine.json\" ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json", "lint": "node_modules/.bin/eslint src/ . --ext .ts", "fix": "node_modules/.bin/eslint --fix src/ . --ext .ts", - "svelte-check-watch": "svelte-check --fail-on-warnings --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\" --watch", - "svelte-check": "svelte-check --fail-on-warnings --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\"" + "svelte-check-watch": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\" --watch", + "svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore\"" } } diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte index a39f2dc7..c973a6c2 100644 --- a/front/src/Components/App.svelte +++ b/front/src/Components/App.svelte @@ -1,6 +1,4 @@ + + ``` + */ +declare module "*.gif" { + const value: string; + export = value; +} + +declare module "*.jpg" { + const value: string; + export = value; +} + +declare module "*.jpeg" { + const value: string; + export = value; +} + +declare module "*.png" { + const value: string; + export = value; +} + +declare module "*.svg" { + const value: string; + export = value; +} + +declare module "*.webp" { + const value: string; + export = value; +} From c1e202b7b113bbd06411d0dee8fbd57a59afed97 Mon Sep 17 00:00:00 2001 From: jonny Date: Wed, 16 Jun 2021 17:16:00 +0200 Subject: [PATCH 065/189] renamed to goToRoom --- front/src/iframe_api.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index d4146fd1..89279a64 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -21,10 +21,10 @@ interface WorkAdventureApi { onEnterZone(name: string, callback: () => void): void; onLeaveZone(name: string, callback: () => void): void; openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; - openTab(url : string): void; - goToPage(url : string): void; - exitSceneTo(url : string): void; - openCoWebSite(url : string): void; + openTab(url: string): void; + goToPage(url: string): void; + goToRoom(url: string): void; + openCoWebSite(url: string): void; closeCoWebSite(): void; disablePlayerControls(): void; restorePlayerControls(): void; @@ -168,7 +168,7 @@ window.WA = { }, '*'); }, - exitSceneTo(url : string) : void{ + goToRoom(url: string): void { window.parent.postMessage({ "type" : 'loadPage', "data" : { From 1147a21ddeaf4e32147c6e0de15c4a5653ae32f9 Mon Sep 17 00:00:00 2001 From: jonny Date: Wed, 16 Jun 2021 17:34:00 +0200 Subject: [PATCH 066/189] fixed documentation --- docs/maps/api-reference.md | 19 +++++++++++++++++++ maps/tests/goToPageScript.js | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 9891a88a..80d57ea9 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -187,6 +187,25 @@ Example: WA.goToPage('https://www.wikipedia.org/'); ``` +### Going to a different map from the script + +``` + +goToRoom(url: string): void +``` + +Load the map at url without unloading workadventure + +relative urls: "../subFolder/map.json[#start-layer-name]" +global urls: "/_/global/domain/path/map.json[#start-layer-name]" + +Example: + +```javascript +WA.goToRoom('../otherMap/map.json'); +WA.goToRoom("/_/global/.json#start-layer-2") +``` + ### Opening/closing a web page in an iFrame ``` diff --git a/maps/tests/goToPageScript.js b/maps/tests/goToPageScript.js index af5b7f9f..bccbc5d2 100644 --- a/maps/tests/goToPageScript.js +++ b/maps/tests/goToPageScript.js @@ -39,7 +39,7 @@ WA.onEnterZone(zoneName, () => { label: "load grouped map", className: "popUpElement", callback: (popup => { - WA.exitSceneTo(urlRelativeMap); + WA.goToRoom(urlRelativeMap); popup.close(); }) From 8d2baa8d1a8e03a08063ffc06e3b3a4f2069c3f2 Mon Sep 17 00:00:00 2001 From: jonny Date: Wed, 16 Jun 2021 17:36:52 +0200 Subject: [PATCH 067/189] added workadventure specific url --- docs/maps/api-reference.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/maps/api-reference.md b/docs/maps/api-reference.md index 80d57ea9..b9525d3c 100644 --- a/docs/maps/api-reference.md +++ b/docs/maps/api-reference.md @@ -202,6 +202,7 @@ global urls: "/_/global/domain/path/map.json[#start-layer-name]" Example: ```javascript +WA.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls WA.goToRoom('../otherMap/map.json'); WA.goToRoom("/_/global/.json#start-layer-2") ``` From e7b0f859a567f21dffe9e88a831206b399dbeb31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Fri, 11 Jun 2021 11:29:36 +0200 Subject: [PATCH 068/189] Migrating the video overlay in Svelte (WIP) --- front/src/Components/App.svelte | 6 +- .../HorizontalSoundMeterWidget.svelte | 2 +- front/src/Components/SoundMeterWidget.svelte | 10 +- .../Components/Video/LocalStreamMedia.svelte | 20 ++++ front/src/Components/Video/Peer.svelte | 20 ++++ .../Video/ScreenSharingMedia.svelte | 57 +++++++++ front/src/Components/Video/VideoMedia.svelte | 75 ++++++++++++ .../src/Components/Video/VideoOverlay.svelte | 32 +++++ .../src/Components/Video/images/blockSign.svg | 22 ++++ front/src/Components/Video/images/report.svg | 1 + front/src/Phaser/Game/GameScene.ts | 7 +- .../src/Stores/GameOverlayStoreVisibility.ts | 17 +++ front/src/Stores/LayoutStore.ts | 58 +++++++++ front/src/Stores/MediaStore.ts | 17 +-- front/src/Stores/PeerStore.ts | 111 ++++++++++++++++-- front/src/Stores/ScreenSharingStore.ts | 46 ++++++-- front/src/WebRtc/MediaManager.ts | 37 ++---- front/src/WebRtc/ScreenSharingPeer.ts | 73 ++++++++++-- front/src/WebRtc/SimplePeer.ts | 36 ++++-- front/src/WebRtc/VideoPeer.ts | 80 ++++++++++++- 20 files changed, 630 insertions(+), 97 deletions(-) create mode 100644 front/src/Components/Video/LocalStreamMedia.svelte create mode 100644 front/src/Components/Video/Peer.svelte create mode 100644 front/src/Components/Video/ScreenSharingMedia.svelte create mode 100644 front/src/Components/Video/VideoMedia.svelte create mode 100644 front/src/Components/Video/VideoOverlay.svelte create mode 100644 front/src/Components/Video/images/blockSign.svg create mode 100644 front/src/Components/Video/images/report.svg create mode 100644 front/src/Stores/GameOverlayStoreVisibility.ts create mode 100644 front/src/Stores/LayoutStore.ts diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte index c973a6c2..1d492ab7 100644 --- a/front/src/Components/App.svelte +++ b/front/src/Components/App.svelte @@ -1,5 +1,5 @@