From 87546938930b8d7f30cc3f5a686d019a77ff809f Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 14 Mar 2022 15:12:47 +0900 Subject: [PATCH 01/16] [Service] Debugging condole.log with ServiceMessage There is no way to get the console message with commercial products because Tizen SDK cannot get the 'dlog' actually. - 'dlog' is disabled on release firmware. Thus, this way provides a new way to catch the console message of service application by UI application's message port - local message port 'wrt.message.port' - message format : {'service-log' : message } Change-Id: Ia42dbecb9daa492ffe58b4b5550d804569190232 Signed-off-by: DongHyun Song --- wrt_app/common/service_message.ts | 31 +++++++++++++++++++++++++++++-- wrt_app/service/service_runner.ts | 13 +++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/wrt_app/common/service_message.ts b/wrt_app/common/service_message.ts index 4080701..33ceb3b 100644 --- a/wrt_app/common/service_message.ts +++ b/wrt_app/common/service_message.ts @@ -1,7 +1,9 @@ import { wrt } from '../browser/wrt'; +let funcConsoleLog: any = null; let foregroundAppMessagePort: any = null; let lastForegroundApp: string = ''; +const wrtCommonPort = 'wrt.message.port'; export function notifyServiceMessage(type: string, message: string) { let foregroundApp = wrt.tv?.getForegroundApp(); @@ -11,10 +13,35 @@ export function notifyServiceMessage(type: string, message: string) { try { if (!foregroundAppMessagePort || lastForegroundApp != foregroundApp) { foregroundAppMessagePort = - global.tizen.messageport.requestRemoteMessagePort(foregroundApp, 'wrt.message.port'); + global.tizen.messageport.requestRemoteMessagePort(foregroundApp, wrtCommonPort); lastForegroundApp = foregroundApp; } if (foregroundAppMessagePort) - foregroundAppMessagePort.sendMessage([{key: type, value: ['', message]}]); + foregroundAppMessagePort.sendMessage([{ key: type, value: ['', message] }]); } catch { } } + +export function initConsoleMessageNotification(id: string) { + try { + let mainAppId = wrt.getMainAppId(id); + if (!mainAppId) + return; + + let mainAppMessagePort = global.tizen.messageport.requestRemoteMessagePort( + mainAppId, wrtCommonPort); + if (!mainAppMessagePort) + return; + + Object.defineProperty(global, 'mainAppMessagePort', + { value: mainAppMessagePort, writable: false }); + + funcConsoleLog = console.log; + console.log = (log: any) => { + funcConsoleLog(log); + if (global.mainAppMessagePort) { + let value = [id, log.toString()]; + global.mainAppMessagePort.sendMessage([{ key: 'service-log', value }]); + } + } + } catch { } +} \ No newline at end of file diff --git a/wrt_app/service/service_runner.ts b/wrt_app/service/service_runner.ts index c7e40d2..405c9e9 100644 --- a/wrt_app/service/service_runner.ts +++ b/wrt_app/service/service_runner.ts @@ -3,11 +3,7 @@ import * as XWalkExtension from '../common/wrt_xwalk_extension'; import { DeviceAPIRouter } from './device_api_router'; import { isMainThread, parentPort, workerData } from 'worker_threads'; import { wrt } from '../browser/wrt'; - -Object.defineProperty(global, 'serviceType', { - value: wrt.getServiceModel(), - writable: false -}); +import * as ServiceMessage from '../common/service_message'; function isServiceApplication() { return global['serviceType'] !== 'UI'; @@ -90,6 +86,7 @@ export function start(id: string, filename: string) { console.debug(`serviceType : ${global['serviceType']}`) new DeviceAPIRouter(id, isGlobalService()); printAppControlData(id); + ServiceMessage.initConsoleMessageNotification(id); // This is for awaking up uv loop. if (isGlobalService()) { @@ -146,9 +143,9 @@ function run() { process.exit(); } - Object.defineProperty(global, 'internalId', { - value: id, - writable: false + Object.defineProperties(global, { + 'internalId': { value: id, writable: false }, + 'serviceType': { value: wrt.getServiceModel(), writable: false } }); let filename = workerData.filename; -- 2.7.4 From 3f3746a295456a15adf97f49ce18fa4e5ef1eb2b Mon Sep 17 00:00:00 2001 From: "yman.son" Date: Fri, 25 Mar 2022 16:51:11 +0900 Subject: [PATCH 02/16] [VD] resolve metadata-profile.xml parsing error if use the metadata sample used for config.xml, need add xmlns information to the profile. Change-Id: Ic935970691f3ca5b4148521e868858255c33c816 Signed-off-by: yman.son --- packaging/metadata-profile.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/metadata-profile.xml b/packaging/metadata-profile.xml index 8eb87d7..bb68518 100755 --- a/packaging/metadata-profile.xml +++ b/packaging/metadata-profile.xml @@ -1,5 +1,5 @@ - + Y -- 2.7.4 From 124042b9cc4c28c514d218a1b92e5feb239baf1d Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 23 Mar 2022 09:46:07 +0900 Subject: [PATCH 03/16] [Service] Unset post callbacks Unexpectedly, post callbacks can be fired from webapi worker thread after its wrt::api::XwalkExtension instance was destroyed. Thus, this will unset the post callbacks on unloadInstance API. Related chromium-efl patch: https://review.tizen.org/gerrit/272695/ Change-Id: I82e5bdfc48bed4b4d208ca6dd485bdffd1c31a0d Signed-off-by: DongHyun Song --- wrt_app/common/wrt_xwalk_extension.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrt_app/common/wrt_xwalk_extension.ts b/wrt_app/common/wrt_xwalk_extension.ts index 4e32394..c0c9971 100644 --- a/wrt_app/common/wrt_xwalk_extension.ts +++ b/wrt_app/common/wrt_xwalk_extension.ts @@ -230,6 +230,9 @@ export const setRuntimeMessageHandler = (handler: (type: string, data?: string, } export let cleanup = () => { + for (const name in extensions_) { + extensions_[name].unloadInstance(); + } delete global.tizen; instance = undefined; } -- 2.7.4 From dab685448500e096a504ba992755513502307b8e Mon Sep 17 00:00:00 2001 From: liwei Date: Wed, 13 Apr 2022 17:22:11 +0800 Subject: [PATCH 04/16] [VD] Send appcontrol data to app in 'ResumeWithAppControl' Send appcontrol data to app side when appcontrol data 'ResumeWithAppControl =Yes',then app can use the key/value flexibility. Change-Id: Id3101bf03c1fc35885e08871c582ea7d4bd7dea8 Signed-off-by: liwei --- wrt_app/src/tv/web_application_tv.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrt_app/src/tv/web_application_tv.ts b/wrt_app/src/tv/web_application_tv.ts index 65e7499..d3668fc 100644 --- a/wrt_app/src/tv/web_application_tv.ts +++ b/wrt_app/src/tv/web_application_tv.ts @@ -219,6 +219,7 @@ Then you can get profile log from the initial loading.`; handleAppControlEvent(appControl: any) { this.launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); this.preloadStatus = 'none'; + let resumeWithAppControl = appControl.getData('ResumeWithAppControl'); if (this.launchMode === 'runningAsBackground') { this.webApplication.suspended = false; @@ -226,7 +227,7 @@ Then you can get profile log from the initial loading.`; this.webApplication.windowList[this.webApplication.windowList.length - 1].hide(); this.webApplication.sendAppControlEvent(); return false; - } else if (this.launchMode === 'runningAsForeground') { + } else if ((this.launchMode === 'runningAsForeground') || (resumeWithAppControl === 'Yes')) { this.webApplication.resume(); this.webApplication.sendAppControlEvent(); return false; -- 2.7.4 From 13666a518c90d576902f50a63755cb5b348de839 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 20 Apr 2022 16:16:45 +0900 Subject: [PATCH 05/16] [DeviceHome][VD] Disable to build DeviceHome DeviceHome will be managed by TV app store as a downloadable app. TV store ID : 3202204027208 TV profile don't need to build and install DeviceHome on wrtjs side. Change-Id: I1c13524849b8bb08a2986171769ec414c7639dff Signed-off-by: DongHyun Song --- packaging/wrtjs.spec | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packaging/wrtjs.spec b/packaging/wrtjs.spec index e605fba..95842fe 100644 --- a/packaging/wrtjs.spec +++ b/packaging/wrtjs.spec @@ -194,18 +194,11 @@ cp -r %{app_dir}/* %{buildroot}%{_resourcedir}/ echo "No TPK generation" %endif -%if 0%{?_use_d2d} -%if "%{?tizen_profile_name}" == "tv" - %define _d2d_app_file_name device_home.tmg - %define _d2d_app_extension tmg - %define _d2d_install_path %{TZ_SYS_DATA}/device_home - install -m 0644 packaging/config_tv.xml.in device_home/config.xml -%else +%if "%{?tizen_profile_name}" != "tv" && 0%{?_use_d2d} %define _d2d_app_file_name device_home.wgt %define _d2d_app_extension wgt %define _d2d_install_path %{_appdir}/.preload-rw-wgt install -m 0644 packaging/config.xml.in device_home/config.xml -%endif %if 0%{?_use_d2d_offload} install -m 0644 key.pem device_home/signaling_server/gen/ install -m 0644 cert.pem device_home/signaling_server/gen/ @@ -261,12 +254,10 @@ else fi %post -%if "%{?_local_build}" == "1" -%if 0%{?_use_d2d} +%if "%{?_local_build}" == "1" && "%{?tizen_profile_name}" != "tv" && 0%{?_use_d2d} pkgcmd -un 9z6IujVul3 pkgcmd -i -t wgt -p %{_d2d_install_path}/%{_d2d_app_file_name} %endif -%endif %postun @@ -276,10 +267,10 @@ rm -fr %{buildroot} %files %manifest packaging/wrtjs.manifest %license LICENSE +%if "%{?tizen_profile_name}" != "tv" %if 0%{?_use_d2d} %{_d2d_install_path}/%{_d2d_app_file_name} %endif -%if "%{?tizen_profile_name}" != "tv" %caps(cap_setgid,cap_sys_admin=ei) %{_bindir}/wrt-loader %else %{_bindir}/wrt-loader -- 2.7.4 From ae6a06f318887167255a3d599a5d23b5a200d525 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 20 Apr 2022 16:07:51 +0900 Subject: [PATCH 06/16] [DeviceHome][VD] Fix setting the 'wsa' path The start page includes 'wsa' path, then replace the base path as /res/wsa/client/ for tmg app. Change-Id: Iaed061140e26ee04a78402fb1879bc861f7cb4a4 Signed-off-by: DongHyun Song --- device_home/service/service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device_home/service/service.js b/device_home/service/service.js index 138dd23..4cf8593 100755 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -357,7 +357,7 @@ var HTTPserverStart = function() { if (is_tv) { platform_app_path = '/opt/usr/apps'; - if (!fs.existsSync(path.join(__dirname, platform_client_res_path))) { + if (__dirname.indexOf('/wsa/') > -1) { platform_client_res_path = '/res/wsa/client'; } console.log(`${TAG} TV Profile`); -- 2.7.4 From 6f6889b08c4c0048400137df04854573f8f798d5 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Mon, 18 Apr 2022 17:00:45 +0900 Subject: [PATCH 07/16] [DeviceHome] Seperate TV service with service_tv.js 1. Add new file service_tv.js for TV product features 2. Remove unnecessary service.js symlink 3. Support webapis.getProfile() Change-Id: Ied35583ff74d0b8b864e65c091a8791ffe0f31f9 Signed-off-by: DongHyun Song --- device_home/service.js | 15 ------ device_home/service/service.js | 7 ++- device_home/service/tv/service_tv.js | 102 +++++++++++++++++++++++++++++++++++ packaging/config.xml.in | 2 +- packaging/config_tv.xml.in | 2 +- wrt_app/service/device_api_router.ts | 6 +++ 6 files changed, 116 insertions(+), 18 deletions(-) delete mode 100644 device_home/service.js create mode 100644 device_home/service/tv/service_tv.js diff --git a/device_home/service.js b/device_home/service.js deleted file mode 100644 index 17cd727..0000000 --- a/device_home/service.js +++ /dev/null @@ -1,15 +0,0 @@ -const deviceHome = require('./service/service'); - -module.exports.onStart = async function() { - deviceHome.onStart(); - // Temporarily remove the signaling server - // require('./signaling_server/gen/app'); -}; - -module.exports.onStop = function() { - deviceHome.onStop(); -}; - -module.exports.onRequest = function() { - deviceHome.onRequest(); -} diff --git a/device_home/service/service.js b/device_home/service/service.js index 138dd23..221a2ee 100755 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -26,7 +26,7 @@ const TAG = '[DeviceHome][service.js]' const TIZEN_WEB_APP_SHARED_RESOURCES = 'shared/res/'; const WEBCLIP_DIRECTORY = 'webclip'; const WEBCLIP_MANIFEST = 'manifest.json'; -const is_tv = webapis.cachedProperty !== undefined; +const is_tv = webapis.getProfile() === 'TV'; const local_ip = '127.0.0.1'; const non_ip_list = [ '1', @@ -529,6 +529,11 @@ var HTTPserverStart = function() { webapis.mde.launchBrowserFromUrl(req.body.url); }); + if (is_tv) { + const tvService = require('./tv/service_tv'); + tvService.initialize(app); + } + httpserver = http.createServer(app); httpserver.listen(g.port, function() { console.log(`Device home is running on port ${g.port}`); diff --git a/device_home/service/tv/service_tv.js b/device_home/service/tv/service_tv.js new file mode 100644 index 0000000..cc0156c --- /dev/null +++ b/device_home/service/tv/service_tv.js @@ -0,0 +1,102 @@ +const express = require('express'); + +let virtualKeyGeneratorInitialized = false; +let virtualMouseInitialized = false; +const keyMap = { + 'Ambient': 530, + 'ArrowLeft': 113, + 'ArrowRight': 114, + 'ArrowUp': 111, + 'ArrowDown': 116, + 'Back': 9, + 'ChannelDown': 95, + 'ChannelUp': 96, + 'HomeUI': 71, + 'OK': 36, + 'VolumeDown': 75, + 'VolumeUp': 76, + 'WebBrowser': 158, +}; + +let webapis = global.webapis; + +function initializeVirtualKeyGenerator() { + if (!virtualKeyGeneratorInitialized) { + virtualKeyGeneratorInitialized = true; + webapis.mde.initVirtualEventGenerator(0); + } + return virtualKeyGeneratorInitialized; +} + +function initializeVirtualMouse() { + if (!virtualMouseInitialized) { + virtualMouseInitialized = true; + webapis.mde.initVirtualEventGenerator(1); + } + return virtualMouseInitialized; +} + +module.exports.initialize = (app) => { + app.post('/sendKey', express.json(), (req, res) => { + if (!initializeVirtualKeyGenerator()) { + res.send({ + result: 'mde API is not enabled' + }); + return; + } + + var keyName = req.body.keyName; + let keyCode = keyMap[keyName]; + console.log(`keyName : ${keyName}, keyCode : ${keyCode}`); + webapis.mde.generateVirtualKeyEvent(keyCode, 2); + res.send({ + result: 'ok' + }); + }); + + app.post('/sendString', express.json(), (req, res) => { + var inputString = req.body.inputString; + console.log(`inputString : ${inputString}`); + webapis.mde.updateRemoteInput(inputString); + res.send({ + result: 'ok' + }); + }); + + app.post('/selectString', express.json(), (req, res) => { + webapis.mde.selectRemoteInput(); + res.send({ + result: 'ok' + }); + }); + + app.post('/mouseMove', express.json(), (req, res) => { + if (!initializeVirtualMouse()) { + res.send({ + result: 'mde API is not enabled' + }); + return; + } + var dx = req.body.dx; + var dy = req.body.dy; + console.log(`dx : ${dx}, dy : ${dy}`); + webapis.mde.generateVirtualMouseMoveEvent(dx, dy, 3); + res.send({ + result: 'ok' + }); + }); + + app.post('/previewData', express.json(), (req, res) => { + let pkgId = req.body.pkgId; + let previewData = '{ sections: [] }'; + if (webapis && webapis.getPreviewData) { + previewData = webapis.getPreviewData(pkgId); + } else { + console.error('webapis.getPreviewData is unsupported.'); + } + res.send({ + result: JSON.parse(previewData) + }); + }); + +} \ No newline at end of file diff --git a/packaging/config.xml.in b/packaging/config.xml.in index 2b80c64..e2a99de 100644 --- a/packaging/config.xml.in +++ b/packaging/config.xml.in @@ -14,7 +14,7 @@ - + DeviceHomeService DeviceHomeService diff --git a/packaging/config_tv.xml.in b/packaging/config_tv.xml.in index cf869c3..af85a01 100644 --- a/packaging/config_tv.xml.in +++ b/packaging/config_tv.xml.in @@ -14,7 +14,7 @@ - + DeviceHomeService DeviceHomeService diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index eed2979..40c33d7 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -68,12 +68,18 @@ export class DeviceAPIRouter { return { images: 'no' }; } } + global.webapis.getProfile = () => { + if (wrt.tv) return 'TV'; + else if (wrt.da) return 'DA'; + else return 'common'; + } Object.defineProperties(global.webapis, { getCallerAppId: { writable: false, enumerable: true }, getPackageId: { writable: false, enumerable: true }, getServiceId: { writable: false, enumerable: true }, postPlainNotification: { writable: false, enumerable: true }, getPreviewData: { writable: false, enumerable: true }, + getProfile: { writable: false, enumerable: true }, }); this.initMDEWebapis(); this.initEdgeWebapis(); -- 2.7.4 From b83469e0acda7d1d9e3f11f84f2a403e4b8b9a89 Mon Sep 17 00:00:00 2001 From: Surya Kumar Date: Mon, 25 Apr 2022 20:16:36 +0530 Subject: [PATCH 08/16] [DeviceHome] Fix crash due to empty appid Platform team has reported crashes on wrt calling webapis with empty appid, which happens on installation of resource packages without app. This change safeguards such instances. Change-Id: Ied8e3f6f7253aa1bc38421e296842c8c09d54e6c Signed-off-by: Surya Kumar --- device_home/service/service.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/device_home/service/service.js b/device_home/service/service.js index 7cd039d..1bedb6f 100755 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -200,6 +200,10 @@ function getWebclipsManifest() { function setPackageInfoEventListener() { const packageEventCallback = { oninstalled: async function(packageInfo) { + if (typeof(packageInfo.name) !== 'string' || !packageInfo.name.length) { + console.debug(`${TAG} Package with no appid is installed`); + return; + } console.log(`${TAG} The package ${packageInfo.name} is installed`); const app = addD2Ddata(packageInfo.id, packageInfo.appIds[0], packageInfo.name, packageInfo.iconPath); if (app.path !== undefined) { @@ -216,9 +220,17 @@ function setPackageInfoEventListener() { } }, onupdated: function(packageInfo) { + if (typeof(packageInfo.name) !== 'string' || !packageInfo.name.length) { + console.debug(`${TAG} Package with no appid is updated`); + return; + } console.log(`${TAG} The package ${packageInfo.name} is updated`); }, onuninstalled: function(packageId) { + if (typeof(packageId) !== 'string' || !packageId.length) { + console.debug(`${TAG} Package with no appid is uninstalled`); + return; + } console.log(`${TAG} The package ${packageId} is uninstalled`); removeD2Ddata(packageId); evtEmit.emit('updateapplist', 'message', dataApps); -- 2.7.4 From 88beccdf6e56f7c26b7ccd5be4679fbb7cbb0db0 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 21 Apr 2022 20:06:18 +0900 Subject: [PATCH 09/16] [DeviceHome][VD] Add 'action' parameter for deeplink If there is 'action' parameter, then, it will be a 'PAYLOAD' data for deeplink. Change-Id: Ic7f3414364945f0a46b2e74274924cfcdc8a9b31 Signed-off-by: DongHyun Song --- device_home/client/js/actions.js | 25 ++++++++----------------- device_home/service/app_proxy.js | 40 +++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 30 deletions(-) mode change 100755 => 100644 device_home/client/js/actions.js mode change 100755 => 100644 device_home/service/app_proxy.js diff --git a/device_home/client/js/actions.js b/device_home/client/js/actions.js old mode 100755 new mode 100644 index fdcb1c5..1ff3f9a --- a/device_home/client/js/actions.js +++ b/device_home/client/js/actions.js @@ -11,18 +11,13 @@ class Actions { * @returns {Function} */ - launchAppOnTV(pkgId, appId, callback) { - const xhr = new XMLHttpRequest(); - - var self = this; - var retFunc = function() { - var data = { - pkgId: pkgId, - appId: appId - }; - self.sendDataToApp(pkgId, appId, data, callback); + launchAppOnTV(pkgId, appId, action, callback) { + var data = { + pkgId, + appId, + action }; - return retFunc; + return this.sendDataToApp('app', data, callback); }; /** @@ -32,12 +27,8 @@ class Actions { * @param {Object} data * @param {Function} callback */ - sendDataToApp(pkgId, appId, data, callback) { + sendDataToApp(api, data, callback) { const xhr = new XMLHttpRequest(); - // add tv app id - data.appId = appId; - data.pkgId = pkgId; - xhr.onreadystatechange = function() { if (xhr.readyState === xhr.DONE) { if (xhr.status === 200 || xhr.status === 201) { @@ -50,7 +41,7 @@ class Actions { } } } - xhr.open('POST', serverURL + ':' + serverPort + '/app'); + xhr.open('POST', `${serverURL}:${serverPort}/${api}`); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.send(JSON.stringify(data)); }; diff --git a/device_home/service/app_proxy.js b/device_home/service/app_proxy.js old mode 100755 new mode 100644 index 1cd814c..d71fca1 --- a/device_home/service/app_proxy.js +++ b/device_home/service/app_proxy.js @@ -6,7 +6,7 @@ var appRouters = []; var path = null; var currentD2DAppId = null; -function runApp(appId, port, callback) { +function runApp(appId, port, action, callback) { function onRunningAppsContext(contexts) { var isRunning = false; for (var i = 0; i < contexts.length; i++) { @@ -16,22 +16,35 @@ function runApp(appId, port, callback) { } } - if (isRunning && currentD2DAppId === appId) { + if (isRunning && currentD2DAppId === appId && !action) { callback(); } else { const urlParam = require('./service').getUrlParam(); const urlObj = url.parse(urlParam, true).query; urlObj.target = is_tv ? 'tv' : 'fhub'; - const appControl = new tizen.ApplicationControl( - "http://tizen.org/appcontrol/operation/default", null, null, null, - [new tizen.ApplicationControlData( - "http://tizen.org/appcontrol/data/launch_port", [port] - ), - new tizen.ApplicationControlData( - "http://tizen.org/appcontrol/data/url_parameter", [JSON.stringify(urlObj)] - )] - ); - + var appControl; + if (action) { + console.log('action : ' + JSON.stringify(action)); + appControl = new tizen.ApplicationControl( + "http://tizen.org/appcontrol/operation/eden_resume", null, null, null, + [new tizen.ApplicationControlData( + "PAYLOAD", [JSON.stringify({ values: action }) ] + ), + new tizen.ApplicationControlData( + "SkipReload", ['No'] + )] + ); + } else { + appControl = new tizen.ApplicationControl( + "http://tizen.org/appcontrol/operation/default", null, null, null, + [new tizen.ApplicationControlData( + "http://tizen.org/appcontrol/data/launch_port", [port] + ), + new tizen.ApplicationControlData( + "http://tizen.org/appcontrol/data/url_parameter", [JSON.stringify(urlObj)] + )] + ); + } currentD2DAppId = appId; tizen.application.launchAppControl(appControl, appId, callback); } @@ -56,6 +69,7 @@ module.exports = function (app, port) { path = req.body.pkgId ? req.body.pkgId : path; var appId = req.body.appId; var pkgId = req.body.pkgId; + var action = req.body.action; var name = appId.split(".")[1]; var appRouter = appRouters.filter(function (router) { return router.path === path; @@ -71,7 +85,7 @@ module.exports = function (app, port) { } console.log('[GlobalWebServer] appProxy.post ', path, action); // run app - runApp(appId, port, function () { + runApp(appId, port, action, function () { res.send({ port: port }); }); } -- 2.7.4 From f32af3b76102b15639668917138605f037698a7f Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 21 Apr 2022 20:10:38 +0900 Subject: [PATCH 10/16] [DeviceHome][VD] Support preview display on client When there are d2dservice apps having preview data, - 'click' event is for listing preview data - 'dblclick' event is for opening the UI offloading page For the deeplink, when the preview icon is clicked on client side, then it will request appcontrol with 'action' parameter as 'PAYLAOAD' Parent patch: https://review.tizen.org/gerrit/274112/ Change-Id: I8c367802aed101644f6d086a9e30ae9dcc6f7eae Signed-off-by: DongHyun Song --- device_home/client/client.html | 5 ++ device_home/client/css/style.css | 13 ++++++ device_home/client/js/myApps.js | 98 ++++++++++++++++++++++++++++++++-------- 3 files changed, 96 insertions(+), 20 deletions(-) mode change 100755 => 100644 device_home/client/client.html mode change 100755 => 100644 device_home/client/css/style.css mode change 100755 => 100644 device_home/client/js/myApps.js diff --git a/device_home/client/client.html b/device_home/client/client.html old mode 100755 new mode 100644 index 025676a..e6c5461 --- a/device_home/client/client.html +++ b/device_home/client/client.html @@ -53,6 +53,11 @@
+
+
+
+
+
My Device App
diff --git a/device_home/client/css/style.css b/device_home/client/css/style.css old mode 100755 new mode 100644 index 3e7b5eb..56afa8b --- a/device_home/client/css/style.css +++ b/device_home/client/css/style.css @@ -50,6 +50,7 @@ box-sizing: border-box; width: 100%; } + .app-dummy-payment input.ui-inline { width: auto; display: inline; @@ -74,3 +75,15 @@ body { .app-display-none { display: none; } + +.app-preview-img { + width: 100px; +} + +#preview-section { + display: none; +} + +#preview-list { + display: none; +} \ No newline at end of file diff --git a/device_home/client/js/myApps.js b/device_home/client/js/myApps.js old mode 100755 new mode 100644 index 167feb9..869db93 --- a/device_home/client/js/myApps.js +++ b/device_home/client/js/myApps.js @@ -24,7 +24,6 @@ const NEW_WINDOW_TIMEOUT = 1000; const myappsmodule = {}; (function () { - var xhr; function emptyElement(elm) { while (elm.firstChild) { elm.removeChild(elm.firstChild); @@ -45,6 +44,26 @@ const myappsmodule = {}; }, NEW_WINDOW_TIMEOUT); }; + function request(method, json, api, body) { + return new Promise( + (resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function () { + if (xhr.readyState === xhr.DONE) { + if (xhr.status === 200 || xhr.status === 201) { + resolve(xhr.responseText); + } else { + reject(xhr.responseText); + } + } + }; + xhr.open(method, `${serverURL}:${serverPort}/${api}`); + if (json) + xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8'); + body ? xhr.send(body) : xhr.send(); + }); + } + function showListView(dataArray) { var formResult = document.getElementById("d2dApps"), imgResult = document.getElementById("d2dAppList"), @@ -71,24 +90,37 @@ const myappsmodule = {}; d2dApp = dataArray[i]['d2dApp']; if (d2dApp.hasOwnProperty("appName")) { if (d2dApp.iconPath) { - icon = d2dApp.iconPath.substring(d2dApp.iconPath.indexOf('/',10)+1); + icon = d2dApp.iconPath.substring(d2dApp.iconPath.indexOf('/', 10) + 1); imgObj.src = `/d2dIcon/${icon}`; } else { imgObj.src = `./images/icon.png`; } imgObj.className = "app-icon-img"; imgObj.alt = d2dApp.appName; + imgObj.setAttribute('pkgId', d2dApp.pkgId); + imgObj.setAttribute('appId', d2dApp.appId); textObj.style.display = "block"; textObj.style.margin = "0 auto"; textObj.style.fontSize = "14px"; textObj.innerHTML = d2dApp.appName; } - imgObj.addEventListener("click", actions.launchAppOnTV( - d2dApp.pkgId, - d2dApp.appId, - function (response) { - openAppWindow(response); - })); + imgObj.addEventListener("click", function () { + var pkgId = this.getAttribute('pkgId'); + var appId = this.getAttribute('appId'); + showPreview(pkgId, appId); + }, false); + imgObj.addEventListener("dblclick", function () { + var pkgId = this.getAttribute('pkgId'); + var appId = this.getAttribute('appId'); + actions.launchAppOnTV( + pkgId, + appId, + '', + function (response) { + // TODO: should check if the app provides client page or not + openAppWindow(response); + }) + }, false); formObj.appendChild(imgObj); formObj.appendChild(textObj); @@ -103,19 +135,45 @@ const myappsmodule = {}; } } + function showPreview(pkgId, appId) { + const reqBody = JSON.stringify({ pkgId, appId }); + request('POST', true, 'previewData', reqBody).then((body) => { + const preview = JSON.parse(body); + if (!preview.result.sections || !preview.result.sections.length) + return; + const previewSection = document.getElementById('preview-section'); + previewSection.style.display = 'block'; + previewSection.innerHTML = 'Preview'; + const previewList = document.getElementById('preview-list'); + previewList.style.display = 'grid'; + previewList.innerHTML = ''; + preview.result.sections.forEach(section => { + if (!section.tiles) + return; + section.tiles.forEach(tile => { + if (!tile.image_url) + return; + const img = document.createElement('img'); + img.src = tile.image_url; + img.border = 0; + img.className = 'app-preview-img'; + img.onclick = function () { + actions.launchAppOnTV( + pkgId, + appId, + tile.action_play_url, + function () { console.log('preview resumed') }); + } + previewList.appendChild(img); + }); + }); + }); + } + function showList() { - xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function () { - if (xhr.readyState === xhr.DONE) { - if (xhr.status === 200 || xhr.status === 201) { - showListView(JSON.parse(xhr.responseText)); - } else { - console.error(xhr.responseText); - } - } - }; - xhr.open('GET', serverURL + ':' + serverPort + '/appList'); - xhr.send(); + request('GET', false, 'appList').then((body) => { + showListView(JSON.parse(body)); + }) } function init() { -- 2.7.4 From c044daf366a7a6d55afe7ffea3d9fb13bc75122e Mon Sep 17 00:00:00 2001 From: Hunseop Jeong Date: Tue, 26 Apr 2022 16:50:50 +0900 Subject: [PATCH 11/16] [SignalingServer] Enable the d2d_offload flag Update the signaling server code and define the service type for the signaling server to run the service independently. Change-Id: Ib69f48392b00734231a8f0f2c35f0feb87f75c12 Signed-off-by: Hunseop Jeong --- device_home/signaling_server/gen/app.js | 377 +-------------------- device_home/signaling_server/gen/edge.js | 6 +- device_home/signaling_server/gen/service.js | 409 +++++++++++++++++++++++ device_home/signaling_server/gen/socket-tizen.js | 2 +- device_home/signaling_server/gen/util.js | 4 +- packaging/config.xml.in | 5 + packaging/wrtjs.spec | 1 + 7 files changed, 423 insertions(+), 381 deletions(-) create mode 100644 device_home/signaling_server/gen/service.js diff --git a/device_home/signaling_server/gen/app.js b/device_home/signaling_server/gen/app.js index 44998f0..8b0a0a8 100644 --- a/device_home/signaling_server/gen/app.js +++ b/device_home/signaling_server/gen/app.js @@ -1,376 +1,3 @@ -const path = require('path'); -const fs = require('fs'); -const express = require('express'); -const QRCode = require('qrcode'); -const Edge = require('./edge'); -const SocketTizen = require('./socket-tizen'); -const { getMyAddress } = require('./util'); +const { onStart } = require('./service'); -const TAG = 'app.js'; - -const app = express(); - -const options = { - key: fs.readFileSync(path.resolve(__dirname, 'key.pem')), - cert: fs.readFileSync(path.resolve(__dirname, 'cert.pem')) -}; - -console.log(TAG, `platform : ${process.platform}`); - -const httpPort = process.env.HTTP_PORT || 9559; -const httpsPort = process.env.PORT || process.env.HTTPS_PORT || 5443; -const httpsServer = require('https').createServer(options, app); -const httpServer = require('http').createServer(app); -const io = require('socket.io')(); -const isTizen = process.platform === 'tizen'; -const supportMessagePort = isTizen; -// Implementation for edge orchestration -const supportEdgeOrchestration = - typeof webapis !== 'undefined' && webapis.hasOwnProperty('edge'); -console.log(TAG, `supportEdgeOrchestration : ${supportEdgeOrchestration}`); - -io.attach(httpServer); -io.attach(httpsServer); - -const clients = new Set(); -const workers = new Map(); -const sockets = new Map(); -let edgeForCastanets = null; -let forceQuitTimer = null; -let isMeerkatStarted = false; - -app.set('host', '0.0.0.0'); - -if (isTizen) { - app.use(express.static(path.join(__dirname, './public'))); -} else { - app.use( - '/offload.html', - express.static(path.join(__dirname, '../../sample/offload.html')) - ); - // Host offload-worker - app.use( - '/offload-worker', - express.static(path.join(__dirname, '../../offload-worker/src/')) - ); - app.use( - '/offload-worker/offload-worker.js', - express.static(path.join(__dirname, '../../build/offload-worker.js')) - ); - const serveIndex = require('serve-index'); - app.use( - '/', - express.static(path.join(__dirname, '../../build')), - express.static(path.join(__dirname, '../../sample')), - serveIndex(path.join(__dirname, '../../sample')) - ); - app.use( - '/test', - express.static(path.join(__dirname, '../../test')), - serveIndex(path.join(__dirname, '../../test')) - ); -} - -function onConnection(socket) { - if (isTizen && !isMeerkatStarted) { - try { - console.log(TAG, `Try to start Meerkat client.`); - tizen.application.launch( - 'org.tizen.meerkat.client', - () => { - console.log(TAG, `Meerkat client is started.`); - isMeerkatStarted = true; - }, - err => console.error(TAG, 'Failed to launch Meerkat client. ' + err) - ); - } catch (err) { - console.error(TAG, 'Failed to launch Meerkat client. ' + err); - } - } - console.log(TAG, `connection from '${socket.id}.`); - sockets.set(socket.id, socket); - - // client creates a session. - socket.on('create', async function () { - if (forceQuitTimer !== null) { - clearTimeout(forceQuitTimer); - } - - if (clients.has(socket.id)) { - console.log(TAG, `already created by ${socket.id}.`); - return; - } - clients.add(socket.id); - - let qr = null; - const myAddress = getMyAddress(); - if (myAddress) { - try { - qr = await QRCode.toDataURL( - 'https://' + myAddress + ':5443/offload-worker.html' - ); - } catch (err) { - console.error(TAG, 'unabled to generate QR: ' + error); - } - } - - socket.emit('greeting', { - qrCode: qr, - workers: Array.from(workers) - }); - - console.log( - TAG, - `[client] session created by ${socket.id}. workers.size : ${workers.size}` - ); - - if (supportEdgeOrchestration) { - socket.emit( - 'capabilities', - Array.from(edgeForCastanets.getCapabilities()) - ); - } - }); - - socket.on('getcapabilities', function () { - console.log(TAG, `getcapabilities`); - if (supportEdgeOrchestration) { - socket.emit( - 'capabilities', - Array.from(edgeForCastanets.getCapabilities()) - ); - } else { - socket.emit('capabilities', []); - } - }); - - socket.on('requestService', function (workerId) { - if (supportEdgeOrchestration) { - edgeForCastanets.requestService(workerId); - } - }); - - // new worker has been joined. - socket.on('join', function (worker) { - if (supportEdgeOrchestration) { - let deviceIp = socket.request.connection.remoteAddress; - if (deviceIp.indexOf('::ffff:') !== -1) { - deviceIp = deviceIp.substr(7, deviceIp.length); - } - - if (deviceIp) { - edgeForCastanets.joinDevice(deviceIp); - } - } - - workers.set(worker.id, { - socketId: socket.id, - name: worker.name, - features: worker.features, - mediaDeviceInfos: worker.mediaDeviceInfos, - compute_tasks: 0 - }); - console.log( - TAG, - `worker[${workers.size}] join: '${worker.id}' - '${socket.id}', '${worker.name}'`, - worker.features - ); - - for (const client of clients) { - const clientSocket = sockets.get(client); - clientSocket.emit('worker', { - event: 'join', - workerId: worker.id, - socketId: socket.id, - name: worker.name, - features: worker.features, - mediaDeviceInfos: worker.mediaDeviceInfos - }); - } - }); - - // route message between clients. - socket.on('message', function (data) { - console.log(TAG, `message ${JSON.stringify(data)}`); - let socketId = null; - if (workers.has(data.to)) { - socketId = workers.get(data.to).socketId; - } else if (clients.has(data.to)) { - socketId = data.to; - } - - if (socketId) { - const socket = sockets.get(socketId); - socket.emit('message', data); - } - }); - - socket.on('disconnect', function (reason) { - const socketId = socket.id; - sockets.delete(socketId); - if (clients.has(socketId)) { - console.log(TAG, `[client] session terminated by client: ${socketId}`); - - // broadcast to offload-worker - for (const socket of sockets.values()) { - socket.emit('client', { - event: 'bye', - socketId: socketId - }); - } - clients.delete(socketId); - - if (clients.size === 0) { - if (supportMessagePort) { - closeServer(); - } - forceQuitTimer = setTimeout(function () { - console.log( - TAG, - `All clients are destroyed. Broadcast 'forceQuit' to workers` - ); - for (const socket of sockets.values()) { - socket.emit('client', { - event: 'forceQuit', - socketId: socketId - }); - } - }, 5000); - } - } else { - if (supportEdgeOrchestration) { - let deviceIp = socket.request.connection.remoteAddress; - if (deviceIp.indexOf('::ffff:') !== -1) { - deviceIp = deviceIp.substr(7, deviceIp.length); - } - - if (deviceIp) { - edgeForCastanets.disconnectDevice(deviceIp); - } - } - - let workerId = null; - workers.forEach(function (value, key, map) { - if (value.socketId === socket.id) { - workerId = key; - } - }); - - if (workerId) { - for (const client of clients) { - const socket = sockets.get(client); - socket.emit('worker', { - event: 'bye', - workerId: workerId, - socketId: socket.id - }); - } - workers.delete(workerId); - console.log(TAG, `worker[${workers.size}] bye: '${workerId}'`); - } - } - }); -} - -io.of('/offload-js').on('connection', onConnection); - -if (supportEdgeOrchestration) { - edgeForCastanets = new Edge( - 'castanets', - 'android', - 'com.samsung.android.castanets' - ); -} - -function startServer() { - console.log(TAG, 'starting server...'); - - if (!httpsServer.listening) { - httpsServer.listen(httpsPort, function () { - console.log(TAG, `server is listening on https ${httpsPort} port.`); - }); - } - - if (!httpServer.listening) { - httpServer.listen(httpPort, function () { - console.log(TAG, `server is listening on http ${httpPort} port.`); - }); - } -} - -function closeServer() { - console.log(TAG, 'closing server...'); - - if (httpsServer.listening) { - httpsServer.close(err => { - if (err) { - console.error(`failed to close the https server:`, err); - } - }); - } - - if (httpServer.listening) { - httpServer.close(err => { - if (err) { - console.error(`failed to close the http server:`, err); - } - }); - } -} - -if (supportMessagePort) { - console.log(TAG, 'listening tizen messageport...'); - const localPort = tizen.messageport.requestLocalMessagePort('offload'); - localPort.addMessagePortListener(messages => { - if (messages.length === 0) { - console.error(TAG, 'Not found message'); - return; - } - - const message = messages[0]; - const event = message.key; - const value = JSON.parse(message.value); - const id = value.id; - - if (event === 'connect') { - // FIXME: The message port does not guarantee that the connection has - // been disconnected when the page is reloaded. Therefore, if a new - // connection occurs with the same id, the existing connection is - // disconnected. - if (sockets.has(id)) { - console.log(TAG, `Disconnect already connected socket: ${id}`); - const socket = sockets.get(id); - socket.handleEvents('disconnect'); - } - - const socket = new SocketTizen(id, localPort); - socket.on('connection', onConnection); - socket.connect(); - sockets.set(id, socket); - startServer(); - } else { - const socket = sockets.get(id); - socket.handleEvents(event, value.data); - } - }); - - // Check the client status - function checkConnectionStatus() { - for (const client of clients) { - const socket = sockets.get(client); - if (socket.constructor === SocketTizen) { - try { - socket.emit('status'); - } catch (e) { - console.error(TAG, `Failed to check ${client} status`); - socket.handleEvents('disconnect'); - } - } - } - } - - // Prevent to terminate the process - setInterval(checkConnectionStatus, 1000); -} else { - startServer(); -} +onStart(); diff --git a/device_home/signaling_server/gen/edge.js b/device_home/signaling_server/gen/edge.js index 8573ef2..4751384 100644 --- a/device_home/signaling_server/gen/edge.js +++ b/device_home/signaling_server/gen/edge.js @@ -43,7 +43,7 @@ class Edge { ); if (deviceList === null || deviceList.ipaddrs.length === 0) { - console.log(TAG, `deviceList is null`); + console.log(TAG, 'deviceList is null'); return this._capabilities; } @@ -57,8 +57,8 @@ class Edge { console.log(TAG, `ReadCapability : ${ipaddr}, ${features.capability}`); try { let jsonCapability = JSON.parse(features.capability); - if (jsonCapability.hasOwnProperty('offloadjs')) { - jsonCapability = jsonCapability['offloadjs']; + if (Object.hasOwnProperty.call(jsonCapability, 'offloadjs')) { + jsonCapability = jsonCapability.offloadjs; } this._capabilities.set(jsonCapability.id, { ipaddr: ipaddr, diff --git a/device_home/signaling_server/gen/service.js b/device_home/signaling_server/gen/service.js new file mode 100644 index 0000000..86d51bb --- /dev/null +++ b/device_home/signaling_server/gen/service.js @@ -0,0 +1,409 @@ +const path = require('path'); +const fs = require('fs'); +const express = require('express'); +const QRCode = require('qrcode'); +const Edge = require('./edge'); +const SocketTizen = require('./socket-tizen'); +const { getMyAddress } = require('./util'); + +const TAG = 'service.js'; + +const app = express(); + +const options = { + key: fs.readFileSync(path.resolve(__dirname, 'key.pem')), + cert: fs.readFileSync(path.resolve(__dirname, 'cert.pem')) +}; + +console.log(TAG, `platform : ${process.platform}`); + +const httpPort = process.env.HTTP_PORT || 9559; +const httpsPort = process.env.PORT || process.env.HTTPS_PORT || 5443; +const httpsServer = require('https').createServer(options, app); +const httpServer = require('http').createServer(app); +const io = require('socket.io')(); +const isTizen = process.platform === 'tizen'; +const supportMessagePort = isTizen; +// Implementation for edge orchestration +const supportEdgeOrchestration = + typeof webapis !== 'undefined' && Object.hasOwnProperty.call(webapis, 'edge'); +console.log(TAG, `supportEdgeOrchestration : ${supportEdgeOrchestration}`); + +io.attach(httpServer); +io.attach(httpsServer); + +const clients = new Set(); +const workers = new Map(); +const sockets = new Map(); +let edgeForCastanets = null; +let forceQuitTimer = null; +let isMeerkatStarted = false; +let statusIntervalId = null; +let localPort = null; + +app.set('host', '0.0.0.0'); + +if (isTizen) { + app.use(express.static(path.join(__dirname, './public'))); + app.use(express.static(path.join(__dirname, '../../shared/res'))); +} else { + app.use( + '/offload.html', + express.static(path.join(__dirname, '../../offload/apps/web/offload.html')) + ); + // Host offload-worker + app.use( + '/offload-worker', + express.static(path.join(__dirname, '../../offload-worker/apps/web/')) + ); + app.use( + '/offload-worker/offload-worker.js', + express.static(path.join(__dirname, '../../dist/offload-worker.js')) + ); + app.use( + '/face.webm', + express.static(path.join(__dirname, '../../offload-worker/apps/web/face.webm')) + ); + const serveIndex = require('serve-index'); + app.use( + '/', + express.static(path.join(__dirname, '../../dist')), + express.static(path.join(__dirname, '../../offload/sample')), + serveIndex(path.join(__dirname, '../../offload/sample')) + ); + app.use( + '/test', + express.static(path.join(__dirname, '../../test')), + serveIndex(path.join(__dirname, '../../test')) + ); +} + +function onConnection(socket) { + if (isTizen && !isMeerkatStarted) { + try { + console.log(TAG, 'Try to start Meerkat client.'); + tizen.application.launch( + 'org.tizen.meerkat.client', + () => { + console.log(TAG, 'Meerkat client is started.'); + isMeerkatStarted = true; + }, + err => console.error(TAG, 'Failed to launch Meerkat client. ' + err) + ); + } catch (err) { + console.error(TAG, 'Failed to launch Meerkat client. ' + err); + } + } + console.log(TAG, `connection from '${socket.id}.`); + sockets.set(socket.id, socket); + + // client creates a session. + socket.on('create', async function () { + if (forceQuitTimer !== null) { + clearTimeout(forceQuitTimer); + } + + if (clients.has(socket.id)) { + console.log(TAG, `already created by ${socket.id}.`); + return; + } + clients.add(socket.id); + + let qr = null; + const myAddress = getMyAddress(); + if (myAddress) { + try { + qr = await QRCode.toDataURL( + 'https://' + myAddress + ':5443/offload-worker.html' + ); + } catch (err) { + console.error(TAG, 'unabled to generate QR: ' + err); + } + } + + socket.emit('greeting', { + qrCode: qr, + workers: Array.from(workers) + }); + + console.log( + TAG, + `[client] session created by ${socket.id}. workers.size : ${workers.size}` + ); + + if (supportEdgeOrchestration) { + socket.emit( + 'capabilities', + Array.from(edgeForCastanets.getCapabilities()) + ); + } + }); + + socket.on('getcapabilities', function () { + console.log(TAG, 'getcapabilities'); + if (supportEdgeOrchestration) { + socket.emit( + 'capabilities', + Array.from(edgeForCastanets.getCapabilities()) + ); + } else { + socket.emit('capabilities', []); + } + }); + + socket.on('requestService', function (workerId) { + if (supportEdgeOrchestration) { + edgeForCastanets.requestService(workerId); + } + }); + + // new worker has been joined. + socket.on('join', function (worker) { + if (supportEdgeOrchestration) { + let deviceIp = socket.request.connection.remoteAddress; + if (deviceIp.indexOf('::ffff:') !== -1) { + deviceIp = deviceIp.substr(7, deviceIp.length); + } + + if (deviceIp) { + edgeForCastanets.joinDevice(deviceIp); + } + } + + workers.set(worker.id, { + socketId: socket.id, + name: worker.name, + features: worker.features, + mediaDeviceInfos: worker.mediaDeviceInfos, + compute_tasks: 0 + }); + console.log( + TAG, + `worker[${workers.size}] join: '${worker.id}' - '${socket.id}', '${worker.name}'`, + worker.features + ); + + for (const client of clients) { + const clientSocket = sockets.get(client); + clientSocket.emit('worker', { + event: 'join', + workerId: worker.id, + socketId: socket.id, + name: worker.name, + features: worker.features, + mediaDeviceInfos: worker.mediaDeviceInfos + }); + } + }); + + // route message between clients. + socket.on('message', function (data) { + console.log(TAG, `message ${JSON.stringify(data)}`); + let socketId = null; + if (workers.has(data.to)) { + socketId = workers.get(data.to).socketId; + } else if (clients.has(data.to)) { + socketId = data.to; + } + + if (socketId) { + const socket = sockets.get(socketId); + socket.emit('message', data); + } + }); + + socket.on('disconnect', function (reason) { + const socketId = socket.id; + sockets.delete(socketId); + if (clients.has(socketId)) { + console.log(TAG, `[client] session terminated by client: ${socketId}`); + clients.delete(socketId); + + // broadcast to offload-worker + for (const socket of sockets.values()) { + socket.emit('client', { + event: 'bye', + socketId: socketId + }); + } + + if (clients.size === 0) { + if (supportMessagePort) { + closeServer(); + } + forceQuitTimer = setTimeout(function () { + console.log( + TAG, + 'All clients are destroyed. Broadcast \'forceQuit\' to workers' + ); + for (const socket of sockets.values()) { + socket.emit('client', { + event: 'forceQuit', + socketId: socketId + }); + } + }, 5000); + } + } else { + if (supportEdgeOrchestration) { + let deviceIp = socket.request.connection.remoteAddress; + if (deviceIp.indexOf('::ffff:') !== -1) { + deviceIp = deviceIp.substr(7, deviceIp.length); + } + + if (deviceIp) { + edgeForCastanets.disconnectDevice(deviceIp); + } + } + + let workerId = null; + workers.forEach(function (value, key, map) { + if (value.socketId === socket.id) { + workerId = key; + } + }); + + if (workerId) { + for (const client of clients) { + const socket = sockets.get(client); + socket.emit('worker', { + event: 'bye', + workerId: workerId, + socketId: socket.id + }); + } + workers.delete(workerId); + console.log(TAG, `worker[${workers.size}] bye: '${workerId}'`); + } + } + }); +} + +io.of('/offload-js').on('connection', onConnection); + +if (supportEdgeOrchestration) { + edgeForCastanets = new Edge( + 'castanets', + 'android', + 'com.samsung.android.castanets' + ); +} + +function startServer() { + console.log(TAG, 'starting server...'); + + if (!httpsServer.listening) { + httpsServer.listen(httpsPort, function () { + console.log(TAG, `server is listening on https ${httpsPort} port.`); + }); + } + + if (!httpServer.listening) { + httpServer.listen(httpPort, function () { + console.log(TAG, `server is listening on http ${httpPort} port.`); + }); + } +} + +function closeServer() { + console.log(TAG, 'closing server...'); + + if (httpsServer.listening) { + httpsServer.close(err => { + if (err) { + console.error('failed to close the https server:', err); + } + }); + } + + if (httpServer.listening) { + httpServer.close(err => { + if (err) { + console.error('failed to close the http server:', err); + } + }); + } +} + +// Check the client status +function checkConnectionStatus() { + for (const client of clients) { + const socket = sockets.get(client); + if (socket.constructor === SocketTizen) { + try { + socket.emit('status'); + } catch (e) { + console.error(TAG, `Failed to check ${client} status`); + socket.handleEvents('disconnect'); + } + } + } +} + +function handleMessagePort(messages) { + if (messages.length === 0) { + console.error(TAG, 'Not found message'); + return; + } + + const message = messages[0]; + const event = message.key; + const value = JSON.parse(message.value); + const id = value.id; + + if (event === 'connect') { + // FIXME: The message port does not guarantee that the connection has + // been disconnected when the page is reloaded. Therefore, if a new + // connection occurs with the same id, the existing connection is + // disconnected. + if (sockets.has(id)) { + console.log(TAG, `Disconnect already connected socket: ${id}`); + const socket = sockets.get(id); + socket.handleEvents('disconnect'); + } + + const socket = new SocketTizen(id, localPort); + socket.on('connection', onConnection); + socket.connect(); + sockets.set(id, socket); + startServer(); + } else { + const socket = sockets.get(id); + socket.handleEvents(event, value.data); + } +} + +module.exports.onStart = () => { + console.log(`${TAG} onStart is called`); + if (supportMessagePort) { + console.log(TAG, 'listening tizen messageport...'); + localPort = tizen.messageport.requestLocalMessagePort('offload'); + localPort.addMessagePortListener(handleMessagePort); + + // Prevent to terminate the process + statusIntervalId = setInterval(checkConnectionStatus, 1000); + } else { + startServer(); + } +}; + +module.exports.onStop = () => { + console.log(`${TAG} onStop is called`); + if (supportMessagePort) { + for (const socket of sockets.values()) { + socket.close(); + } + if (localPort !== null) { + localPort.removeMessagePortListener(handleMessagePort); + } + if (statusIntervalId !== null) { + clearInterval(statusIntervalId); + } + } + + closeServer(); +}; + +module.exports.onRequest = () => { + console.log(`${TAG} onRequest is called`); +}; diff --git a/device_home/signaling_server/gen/socket-tizen.js b/device_home/signaling_server/gen/socket-tizen.js index bb1f726..a94ede6 100644 --- a/device_home/signaling_server/gen/socket-tizen.js +++ b/device_home/signaling_server/gen/socket-tizen.js @@ -58,7 +58,7 @@ class SocketTizen { this.handleEvents('connection', this); this.emit('connect'); } catch (error) { - console.error(TAG, `Messageport connection failed: ` + error); + console.error(TAG, 'Messageport connection failed: ' + error); } } diff --git a/device_home/signaling_server/gen/util.js b/device_home/signaling_server/gen/util.js index 38a0e8e..4c79773 100644 --- a/device_home/signaling_server/gen/util.js +++ b/device_home/signaling_server/gen/util.js @@ -4,9 +4,9 @@ function getMyAddress() { const interfaces = os.networkInterfaces(); const addresses = {}; for (const intf in interfaces) { - if (interfaces.hasOwnProperty(intf)) { + if (Object.hasOwnProperty.call(interfaces, intf)) { for (const addr in interfaces[intf]) { - if (interfaces[intf].hasOwnProperty(addr)) { + if (Object.hasOwnProperty.call(interfaces[intf], addr)) { const address = interfaces[intf][addr]; if (address.family === 'IPv4' && !address.internal) { addresses[intf] = address.address; diff --git a/packaging/config.xml.in b/packaging/config.xml.in index e2a99de..9485b1d 100644 --- a/packaging/config.xml.in +++ b/packaging/config.xml.in @@ -18,4 +18,9 @@ DeviceHomeService DeviceHomeService + + + SignalingServer + SignalingServer + diff --git a/packaging/wrtjs.spec b/packaging/wrtjs.spec index e605fba..1e27eb1 100644 --- a/packaging/wrtjs.spec +++ b/packaging/wrtjs.spec @@ -26,6 +26,7 @@ Source: %{name}-%{version}.tar.gz %define _use_nmt 0 %endif %define _use_category 0 + %define _use_d2d_offload 1 %endif BuildRequires: pkgconfig(chromium-efl) -- 2.7.4 From a31ba581183ca1ee6bd8143cfb5a517d43f59dfd Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 21 Apr 2022 20:21:51 +0900 Subject: [PATCH 12/16] [DeviceHome] Refactors EventSource handler Refactors EventSource handlers for multiple purpose. - updateapp-list: update app list when install/uninstall - redirect-url: request to open the URL - remote-message: 'remotemessage' CustomEvent - ime-event: handle for remote input Change-Id: I637bcdc17ed8fd3ed7b69b93d50a5c431a385d35 Signed-off-by: DongHyun Song --- device_home/client/js/myApps.js | 29 +++++++++++++++++++++++++---- device_home/service/service.js | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 10 deletions(-) mode change 100755 => 100644 device_home/service/service.js diff --git a/device_home/client/js/myApps.js b/device_home/client/js/myApps.js index 869db93..8eebe74 100644 --- a/device_home/client/js/myApps.js +++ b/device_home/client/js/myApps.js @@ -176,11 +176,28 @@ const myappsmodule = {}; }) } - function init() { - var eventSource = new EventSource(serverURL + ':' + serverPort + '/updateAppList'); + function initEventSource() { + const eventSource = new EventSource(serverURL + ':' + serverPort + '/listenMessage'); eventSource.addEventListener('message', evt => { - showListView(JSON.parse(evt.data)); - UpdateWebClip(JSON.parse(evt.data)); + console.log(`evt.data : ${evt.data}`); + const message = JSON.parse(evt.data); + switch (message.type) { + case 'updateapp-list': + showListView(message.body); + UpdateWebClip(message.body); + break; + case 'redirect-url': + const body = JSON.parse(message.body); + window.open(body.url, '_blank'); + break; + case 'remote-message': + document.dispatchEvent(new CustomEvent('remotemessage', message.body)); + break; + case 'ime-event': + break; + default: + console.log(`no matched case : ${message.type}`); + } }, false); eventSource.addEventListener('open', evt => { console.log("Connected to..."); @@ -192,6 +209,10 @@ const myappsmodule = {}; console.log('Connecting to...'); } }, false); + } + + function init() { + initEventSource(); showList(); } window.onload = init; diff --git a/device_home/service/service.js b/device_home/service/service.js old mode 100755 new mode 100644 index 1bedb6f..d73de5a --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -19,7 +19,8 @@ const sessionMiddleware = session({ cookie: { httpOnly: true, secure: false, -}}); + } +}); const PUBLIC_DOMAIN = 'https://devicehome.net'; const TAG = '[DeviceHome][service.js]' @@ -213,10 +214,10 @@ function setPackageInfoEventListener() { }); console.log(`${TAG} Emit app list`); // for both companion and webclip - evtEmit.emit('updateapplist', 'message', dataApps); + evtEmit.emit('updateapp-list', 'message', dataApps); relayServer(httpserver, dataApps, sessionMiddleware, clientPublicKeys, packageInfo.id); } else { - evtEmit.emit('updateapplist', 'message', dataApps); + evtEmit.emit('updateapp-list', 'message', dataApps); } }, onupdated: function(packageInfo) { @@ -233,12 +234,24 @@ function setPackageInfoEventListener() { } console.log(`${TAG} The package ${packageId} is uninstalled`); removeD2Ddata(packageId); - evtEmit.emit('updateapplist', 'message', dataApps); + evtEmit.emit('updateapp-list', 'message', dataApps); } }; tizen.package.setPackageInfoEventListener(packageEventCallback); } +function registerWrtMessagePort() { + let localPort = tizen.messageport.requestLocalMessagePort('wrt.message.port'); + localPort.addMessagePortListener((data, remotePort) => { + try { + evtEmit.emit(data[0]['key'], 'message', data[0]['value']); + } catch (e) { + console.log('wrt.message.port has exception' + e); + } + }); +} +} + function unsetPackageInfoEventListener() { tizen.package.unsetPackageInfoEventListener(); } @@ -485,11 +498,25 @@ var HTTPserverStart = function() { 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); - evtEmit.on('updateapplist', (event, data) => { + evtEmit.on('updateapp-list', (event, data) => { res.write('event: ' + String(event) + '\n' + 'data: ' + JSON.stringify(data) + '\n\n'); }); }); + app.get('/listenMessage', (req, res) => { + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + }); + const eventTypes = ['updateapp-list', 'redirect-url', 'remote-message', 'ime-event']; + for (const type of eventTypes) { + evtEmit.on(type, (event, data) => { + res.write(`event: ${event}\ndata: { "type": "${type}", "body": ${JSON.stringify(data)}}\n\n`); + }); + } + }); + app.get('/pincode/publicKey', async (req, res) => { tryCount = 0; await displayPincode(req); @@ -581,7 +608,7 @@ module.exports.onStop = function() { console.log(`${TAG} Server Terminated`); } unsetPackageInfoEventListener(); - evtEmit.off('updateapplist'); + evtEmit.off('updateapp-list'); console.log(`${TAG} onStop is called in DNS Resolver`); }; -- 2.7.4 From c7c5c4f65d06a8f78e4ca6c249b1b3b92312f7a5 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 28 Apr 2022 13:49:53 +0900 Subject: [PATCH 13/16] [Service] Support webapis.getAppIdsByMetadata() This new API will be used to find proper apps quickly more than tizen.application.getAppsInfo() Related patch: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/274342/ Change-Id: Ibe8c2a279943cc85570f057e38721aa5d4b95729 Signed-off-by: DongHyun Song --- wrt_app/service/device_api_router.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrt_app/service/device_api_router.ts b/wrt_app/service/device_api_router.ts index 40c33d7..cde4134 100644 --- a/wrt_app/service/device_api_router.ts +++ b/wrt_app/service/device_api_router.ts @@ -73,7 +73,11 @@ export class DeviceAPIRouter { else if (wrt.da) return 'DA'; else return 'common'; } + global.webapis.getAppIdsByMetadata = (metadata: string) => { + return wrt.getAppIdsByMetadata(metadata); + } Object.defineProperties(global.webapis, { + getAppIdsByMetadata: { writable: false, enumerable: true }, getCallerAppId: { writable: false, enumerable: true }, getPackageId: { writable: false, enumerable: true }, getServiceId: { writable: false, enumerable: true }, -- 2.7.4 From eb94d74c1e4cd899cbfd0d625e64e12d6f76689c Mon Sep 17 00:00:00 2001 From: Hunseop Jeong Date: Thu, 28 Apr 2022 17:15:41 +0900 Subject: [PATCH 14/16] [SignalingServer] Move the offload.js to the shared space Move the offload.js to the shared/res/ to access the offload.js from the xwalk extension. Change-Id: If4b802c99e40de23a198cee173c9f5969a371599 Signed-off-by: Hunseop Jeong --- device_home/{signaling_server/gen/public => shared/res}/offload.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename device_home/{signaling_server/gen/public => shared/res}/offload.js (100%) diff --git a/device_home/signaling_server/gen/public/offload.js b/device_home/shared/res/offload.js similarity index 100% rename from device_home/signaling_server/gen/public/offload.js rename to device_home/shared/res/offload.js -- 2.7.4 From 2d7081e69763c9cb1edc311eb321574e0a3865b5 Mon Sep 17 00:00:00 2001 From: Hunseop Jeong Date: Mon, 9 May 2022 13:52:39 +0900 Subject: [PATCH 15/16] [DeviceHome] Remove the wrong parentheses to fix the script Change-Id: I2f73e84ebaa225a3b0404b5118114ea774d08cfd Signed-off-by: Hunseop Jeong --- device_home/service/service.js | 1 - 1 file changed, 1 deletion(-) diff --git a/device_home/service/service.js b/device_home/service/service.js index d73de5a..2c9611e 100644 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -250,7 +250,6 @@ function registerWrtMessagePort() { } }); } -} function unsetPackageInfoEventListener() { tizen.package.unsetPackageInfoEventListener(); -- 2.7.4 From 70b8e23de039890184654c292fdb162855fb162e Mon Sep 17 00:00:00 2001 From: Insoon Kim Date: Wed, 11 May 2022 12:55:20 +0900 Subject: [PATCH 16/16] [SignalingServer] Update latest offload.js Disable the wildcard certificate and domain name by default for public Change-Id: Ie8eec92688736c421f32a1f8b092d6c98833df4e Signed-off-by: Insoon Kim --- device_home/shared/res/offload.js | 10 +- device_home/signaling_server/gen/config.js | 48 + device_home/signaling_server/gen/config.json | 4 + device_home/signaling_server/gen/edge.js | 2 +- .../signaling_server/gen/public/offload-worker.js | 20 - .../index.html} | 0 .../gen/public/{ => offload-worker}/js/log.js | 50 +- .../gen/public/{ => offload-worker}/js/main.js | 4 + .../gen/public/offload-worker/offload-worker.js | 9134 ++++++++++++++++++++ device_home/signaling_server/gen/service.js | 202 +- device_home/signaling_server/gen/socket-tizen.js | 142 +- device_home/signaling_server/gen/util.js | 42 +- 12 files changed, 9455 insertions(+), 203 deletions(-) create mode 100644 device_home/signaling_server/gen/config.js create mode 100644 device_home/signaling_server/gen/config.json delete mode 100644 device_home/signaling_server/gen/public/offload-worker.js rename device_home/signaling_server/gen/public/{offload-worker.html => offload-worker/index.html} (100%) rename device_home/signaling_server/gen/public/{ => offload-worker}/js/log.js (50%) rename device_home/signaling_server/gen/public/{ => offload-worker}/js/main.js (97%) create mode 100644 device_home/signaling_server/gen/public/offload-worker/offload-worker.js diff --git a/device_home/shared/res/offload.js b/device_home/shared/res/offload.js index 66a50a5..4a367a3 100644 --- a/device_home/shared/res/offload.js +++ b/device_home/shared/res/offload.js @@ -1,4 +1,4 @@ -window.offload=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=65)}([function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r,o=(r=n(28))&&r.__esModule?r:{default:r};var i=["debug","error","info","log","warn","time","timeEnd","table"];t.default=function e(t){var n=this;if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),!t)throw new Error("Need a prefix when creating Logger class");i.forEach((function(e){e.indexOf("time")>-1?n[e]=(0,o.default)("".concat("offload",":TIME:")):n[e]=(0,o.default)("".concat("offload",":").concat(e.toUpperCase(),":").concat(t)),n[e].log=function(){for(var e=arguments.length,t=new Array(e),n=0;n1?{type:p[o],data:e.substring(1)}:{type:p[o]}:d}o=new Uint8Array(e)[0];var i=s(e,1);return g&&"blob"===n&&(i=new g([i])),{type:p[o],data:i}},t.decodeBase64Packet=function(e,t){var n=p[e.charAt(0)];if(!r)return{type:n,data:{base64:!0,data:e.substr(1)}};var o=r.decode(e.substr(1));return"blob"===t&&g&&(o=new g([o])),{type:n,data:o}},t.encodePayload=function(e,n,r){"function"==typeof n&&(r=n,n=null);var o=i(e);if(n&&o)return g&&!f?t.encodePayloadAsBlob(e,r):t.encodePayloadAsArrayBuffer(e,r);if(!e.length)return r("0:");y(e,(function(e,r){t.encodePacket(e,!!o&&n,!1,(function(e){r(null,function(e){return e.length+":"+e}(e))}))}),(function(e,t){return r(t.join(""))}))},t.decodePayload=function(e,n,r){if("string"!=typeof e)return t.decodePayloadAsBinary(e,n,r);var o;if("function"==typeof n&&(r=n,n=null),""===e)return r(d,0,1);for(var i,s,a="",c=0,u=e.length;c0;){for(var a=new Uint8Array(o),c=0===a[0],u="",l=1;255!==a[l];l++){if(u.length>310)return r(d,0,1);u+=a[l]}o=s(o,2+u.length),u=parseInt(u);var f=s(o,0,u);if(c)try{f=String.fromCharCode.apply(null,new Uint8Array(f))}catch(e){var h=new Uint8Array(f);f="";for(l=0;l1)for(var n=1;n=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(o())}).call(this,n(3))},function(e,t){t.encode=function(e){var t="";for(var n in e)e.hasOwnProperty(n)&&(t.length&&(t+="&"),t+=encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return t},t.decode=function(e){for(var t={},n=e.split("&"),r=0,o=n.length;r=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(o())}).call(this,n(3))},function(e,t,n){var r=n(35)("socket.io-parser"),o=n(9),i=n(15),s=n(42),a=n(16),c=n(17);function u(){}function l(e){var n=""+e.type;return t.BINARY_EVENT!==e.type&&t.BINARY_ACK!==e.type||(n+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(n+=e.nsp+","),null!=e.id&&(n+=e.id),null!=e.data&&(n+=JSON.stringify(e.data)),r("encoded %j as %s",e,n),n}function f(){this.reconstructor=null}function h(e){this.reconPack=e,this.buffers=[]}function p(e){return{type:t.ERROR,data:"parser error: "+e}}t.protocol=4,t.types=["CONNECT","DISCONNECT","EVENT","ACK","ERROR","BINARY_EVENT","BINARY_ACK"],t.CONNECT=0,t.DISCONNECT=1,t.EVENT=2,t.ACK=3,t.ERROR=4,t.BINARY_EVENT=5,t.BINARY_ACK=6,t.Encoder=u,t.Decoder=f,u.prototype.encode=function(e,n){(e.type!==t.EVENT&&e.type!==t.ACK||!i(e.data)||(e.type=e.type===t.EVENT?t.BINARY_EVENT:t.BINARY_ACK),r("encoding packet %j",e),t.BINARY_EVENT===e.type||t.BINARY_ACK===e.type)?function(e,t){s.removeBlobs(e,(function(e){var n=s.deconstructPacket(e),r=l(n.packet),o=n.buffers;o.unshift(r),t(o)}))}(e,n):n([l(e)])},o(f.prototype),f.prototype.add=function(e){var n;if("string"==typeof e)n=function(e){var n=0,o={type:Number(e.charAt(0))};if(null==t.types[o.type])return p("unknown packet type "+o.type);if(t.BINARY_EVENT===o.type||t.BINARY_ACK===o.type){for(var i="";"-"!==e.charAt(++n)&&(i+=e.charAt(n),n!=e.length););if(i!=Number(i)||"-"!==e.charAt(n))throw new Error("Illegal attachments");o.attachments=Number(i)}if("/"===e.charAt(n+1))for(o.nsp="";++n;){if(","===(c=e.charAt(n)))break;if(o.nsp+=c,n===e.length)break}else o.nsp="/";var s=e.charAt(n+1);if(""!==s&&Number(s)==s){for(o.id="";++n;){var c;if(null==(c=e.charAt(n))||Number(c)!=c){--n;break}if(o.id+=e.charAt(n),n===e.length)break}o.id=Number(o.id)}if(e.charAt(++n)){var u=function(e){try{return JSON.parse(e)}catch(e){return!1}}(e.substr(n));if(!(!1!==u&&(o.type===t.ERROR||a(u))))return p("invalid payload");o.data=u}return r("decoded %s as %j",e,o),o}(e),t.BINARY_EVENT===n.type||t.BINARY_ACK===n.type?(this.reconstructor=new h(n),0===this.reconstructor.reconPack.attachments&&this.emit("decoded",n)):this.emit("decoded",n);else{if(!c(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");(n=this.reconstructor.takeBinaryData(e))&&(this.reconstructor=null,this.emit("decoded",n))}},f.prototype.destroy=function(){this.reconstructor&&this.reconstructor.finishedReconstruction()},h.prototype.takeBinaryData=function(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){var t=s.reconstructPacket(this.reconPack,this.buffers);return this.finishedReconstruction(),t}return null},h.prototype.finishedReconstruction=function(){this.reconPack=null,this.buffers=[]}},function(e,t,n){function r(e){if(e)return function(e){for(var t in r.prototype)e[t]=r.prototype[t];return e}(e)}e.exports=r,r.prototype.on=r.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},r.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+e];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var o=0;o0)return function(e){if((e=String(e)).length>100)return;var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(!t)return;var s=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*o;case"minutes":case"minute":case"mins":case"min":case"m":return s*r;case"seconds":case"second":case"secs":case"sec":case"s":return s*n;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}(e);if("number"===c&&!1===isNaN(e))return t.long?s(a=e,i,"day")||s(a,o,"hour")||s(a,r,"minute")||s(a,n,"second")||a+" ms":function(e){if(e>=i)return Math.round(e/i)+"d";if(e>=o)return Math.round(e/o)+"h";if(e>=r)return Math.round(e/r)+"m";if(e>=n)return Math.round(e/n)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},function(e,t,n){(function(t){var r=n(41),o=Object.prototype.toString,i="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===o.call(Blob),s="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===o.call(File);e.exports=function e(n){if(!n||"object"!=typeof n)return!1;if(r(n)){for(var o=0,a=n.length;o0&&!this.encoding){var e=this.packetBuffer.shift();this.packet(e)}},p.prototype.cleanup=function(){u("cleanup");for(var e=this.subs.length,t=0;t=this._reconnectionAttempts)u("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var t=this.backoff.duration();u("will wait %dms before reconnect attempt",t),this.reconnecting=!0;var n=setTimeout((function(){e.skipReconnect||(u("attempting reconnect"),e.emitAll("reconnect_attempt",e.backoff.attempts),e.emitAll("reconnecting",e.backoff.attempts),e.skipReconnect||e.open((function(t){t?(u("reconnect attempt error"),e.reconnecting=!1,e.reconnect(),e.emitAll("reconnect_error",t.data)):(u("reconnect success"),e.onreconnect())})))}),t);this.subs.push({destroy:function(){clearTimeout(n)}})}},p.prototype.onreconnect=function(){var e=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",e)}},function(e,t,n){(function(e){var r=n(10),o=n(46),i=n(55),s=n(56);t.polling=function(t){var n=!1,s=!1,a=!1!==t.jsonp;if(e.location){var c="https:"===location.protocol,u=location.port;u||(u=c?443:80),n=t.hostname!==location.hostname||u!==t.port,s=t.secure!==c}if(t.xdomain=n,t.xscheme=s,"open"in new r(t)&&!t.forceJSONP)return new o(t);if(!a)throw new Error("JSONP disabled");return new i(t)},t.websocket=s}).call(this,n(0))},function(e,t,n){var r=n(11),o=n(5),i=n(2),s=n(6),a=n(21),c=n(7)("engine.io-client:polling");e.exports=l;var u=null!=new(n(10))({xdomain:!1}).responseType;function l(e){var t=e&&e.forceBase64;u&&!t||(this.supportsBinary=!1),r.call(this,e)}s(l,r),l.prototype.name="polling",l.prototype.doOpen=function(){this.poll()},l.prototype.pause=function(e){var t=this;function n(){c("paused"),t.readyState="paused",e()}if(this.readyState="pausing",this.polling||!this.writable){var r=0;this.polling&&(c("we are currently polling - waiting to pause"),r++,this.once("pollComplete",(function(){c("pre-pause polling complete"),--r||n()}))),this.writable||(c("we are currently writing - waiting to pause"),r++,this.once("drain",(function(){c("pre-pause writing complete"),--r||n()})))}else n()},l.prototype.poll=function(){c("polling"),this.polling=!0,this.doPoll(),this.emit("poll")},l.prototype.onData=function(e){var t=this;c("polling got data %s",e);i.decodePayload(e,this.socket.binaryType,(function(e,n,r){if("opening"===t.readyState&&t.onOpen(),"close"===e.type)return t.onClose(),!1;t.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emit("pollComplete"),"open"===this.readyState?this.poll():c('ignoring poll - transport state "%s"',this.readyState))},l.prototype.doClose=function(){var e=this;function t(){c("writing close packet"),e.write([{type:"close"}])}"open"===this.readyState?(c("transport open - closing"),t()):(c("transport not open - deferring close"),this.once("open",t))},l.prototype.write=function(e){var t=this;this.writable=!1;var n=function(){t.writable=!0,t.emit("drain")};i.encodePayload(e,this.supportsBinary,(function(e){t.doWrite(e,n)}))},l.prototype.uri=function(){var e=this.query||{},t=this.secure?"https":"http",n="";return!1!==this.timestampRequests&&(e[this.timestampParam]=a()),this.supportsBinary||e.sid||(e.b64=1),e=o.encode(e),this.port&&("https"===t&&443!==Number(this.port)||"http"===t&&80!==Number(this.port))&&(n=":"+this.port),e.length&&(e="?"+e),t+"://"+(-1!==this.hostname.indexOf(":")?"["+this.hostname+"]":this.hostname)+n+this.path+e}},function(e,t,n){"use strict";var r,o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),i={},s=0,a=0;function c(e){var t="";do{t=o[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}function u(){var e=c(+new Date);return e!==r?(s=0,r=e):e+"."+c(s++)}for(;a<64;a++)i[o[a]]=a;u.encode=c,u.decode=function(e){var t=0;for(a=0;a{"%%"!==e&&(r++,"%c"===e&&(o=r))}),t.splice(o,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG);return e},t.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(29)(t);const{formatters:o}=e.exports;o.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}).call(this,n(3))},function(e,t,n){e.exports=function(e){function t(e){let n,o=null;function i(...e){if(!i.enabled)return;const r=i,o=Number(new Date),s=o-(n||o);r.diff=s,r.prev=n,r.curr=o,n=o,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(n,o)=>{if("%%"===n)return"%";a++;const i=t.formatters[o];if("function"==typeof i){const t=e[a];n=i.call(r,t),e.splice(a,1),a--}return n}),t.formatArgs.call(r,e);(r.log||t.log).apply(r,e)}return i.namespace=e,i.useColors=t.useColors(),i.color=t.selectColor(e),i.extend=r,i.destroy=t.destroy,Object.defineProperty(i,"enabled",{enumerable:!0,configurable:!1,get:()=>null===o?t.enabled(e):o,set:e=>{o=e}}),"function"==typeof t.init&&t.init(i),i}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function o(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){if(e instanceof Error)return e.stack||e.message;return e},t.disable=function(){const e=[...t.names.map(o),...t.skips.map(o).map(e=>"-"+e)].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),o=r.length;for(n=0;n{t[n]=e[n]}),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t=1.5*n;return Math.round(e/n)+" "+r+(o?"s":"")}e.exports=function(e,t){t=t||{};var a=typeof e;if("string"===a&&e.length>0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var s=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"weeks":case"week":case"w":return 6048e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*o;case"minutes":case"minute":case"mins":case"min":case"m":return s*r;case"seconds":case"second":case"secs":case"sec":case"s":return s*n;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}(e);if("number"===a&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=i)return s(e,t,i,"day");if(t>=o)return s(e,t,o,"hour");if(t>=r)return s(e,t,r,"minute");if(t>=n)return s(e,t,n,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=i)return Math.round(e/i)+"d";if(t>=o)return Math.round(e/o)+"h";if(t>=r)return Math.round(e/r)+"m";if(t>=n)return Math.round(e/n)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},function(e,t,n){var r; +window.offload=function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=815)}([,,function(t,e,n){var r=n(446),o=n(293);t.exports=function(t,e){var n=o(t,e,"get");return r(t,n)},t.exports.default=t.exports,t.exports.__esModule=!0},,,,,function(t,e){t.exports=function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t},t.exports.default=t.exports,t.exports.__esModule=!0},function(t,e,n){var r,o;!function(i,s){"use strict";void 0===(o="function"==typeof(r=function(){var t=function(){},e="undefined"!=typeof window&&void 0!==window.navigator&&/Trident\/|MSIE /.test(window.navigator.userAgent),n=["trace","debug","info","warn","error"];function r(t,e){var n=t[e];if("function"==typeof n.bind)return n.bind(t);try{return Function.prototype.bind.call(n,t)}catch(e){return function(){return Function.prototype.apply.apply(n,[t,arguments])}}}function o(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function i(n){return"debug"===n&&(n="log"),"undefined"!=typeof console&&("trace"===n&&e?o:void 0!==console[n]?r(console,n):void 0!==console.log?r(console,"log"):t)}function s(e,r){for(var o=0;o=0&&e<=i.levels.SILENT))throw"log.setLevel() called with invalid level: "+e;if(o=e,!1!==r&&function(t){var e=(n[t]||"silent").toUpperCase();if("undefined"!=typeof window&&a){try{return void(window.localStorage[a]=e)}catch(t){}try{window.document.cookie=encodeURIComponent(a)+"="+e+";"}catch(t){}}}(e),s.call(i,e,t),"undefined"==typeof console&&e=e.length?(t.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:r,done:!1}:"values"==n?{value:e[r],done:!1}:{value:[r,e[r]],done:!1}}),"values");var p=i.Arguments=i.Array;if(o("keys"),o("values"),o("entries"),!u&&f&&"values"!==p.name)try{a(p,"name",{value:"values"})}catch(t){}},,function(t,e,n){var r=n(39),o=n(54),i=n(91);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r,o,i,s=n(289),a=n(14),c=n(17),u=n(26),f=n(73),l=n(33),h=n(201),p=n(162),d=n(134),v=a.TypeError,g=a.WeakMap;if(s||h.state){var y=h.state||(h.state=new g),m=c(y.get),b=c(y.has),w=c(y.set);r=function(t,e){if(b(y,t))throw new v("Object already initialized");return e.facade=t,w(y,t,e),e},o=function(t){return m(y,t)||{}},i=function(t){return b(y,t)}}else{var A=p("state");d[A]=!0,r=function(t,e){if(l(t,A))throw new v("Object already initialized");return e.facade=t,f(t,A,e),e},o=function(t){return l(t,A)?t[A]:{}},i=function(t){return l(t,A)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=o(e)).type!==t)throw v("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(25),o=n(249),i=r({}.hasOwnProperty);t.exports=Object.hasOwn||function(t,e){return i(o(t),e)}},,,function(t,e,n){var r=n(39),o=n(50),i=n(181),s=n(91),a=n(65),c=n(154),u=n(33),f=n(281),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=a(t),e=c(e),f)try{return l(t,e)}catch(t){}if(u(t,e))return s(!o(i.f,t,e),t[e])}},function(t,e,n){var r=n(14),o=n(27),i=n(156),s=r.TypeError;t.exports=function(t){if(o(t))return t;throw s(i(t)+" is not a function")}},function(t,e,n){var r=n(14),o=n(123),i=r.Object;t.exports=function(t){return i(o(t))}},function(t,e,n){var r=n(17),o=n(79),i=n(132),s=r(r.bind);t.exports=function(t,e){return o(t),void 0===e?t:i?s(t,e):function(){return t.apply(e,arguments)}}},function(t,e){},function(t,e,n){var r=n(81),o=n(17),i=n(242),s=n(80),a=n(100),c=n(284),u=o([].push),f=function(t){var e=1==t,n=2==t,o=3==t,f=4==t,l=6==t,h=7==t,p=5==t||l;return function(d,v,g,y){for(var m,b,w=s(d),A=i(w),x=r(v,g),k=a(A),C=0,E=y||c,S=e?E(d,k):n||h?E(d,0):void 0;k>C;C++)if((p||C in A)&&(b=x(m=A[C],C,w),t))if(e)S[C]=b;else if(b)switch(t){case 3:return!0;case 5:return m;case 6:return C;case 2:u(S,m)}else switch(t){case 4:return!1;case 7:u(S,m)}return l?-1:o||f?f:S}};t.exports={forEach:f(0),map:f(1),filter:f(2),some:f(3),every:f(4),find:f(5),findIndex:f(6),filterReject:f(7)}},function(t,e,n){var r=n(45);t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(t,e,n){var r=n(16),o=n(186),i=r.String;t.exports=function(t){if("Symbol"===o(t))throw TypeError("Cannot convert a Symbol value to a string");return i(t)}},function(t,e,n){var r=n(610),o=n(616);t.exports=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=r(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&o(t,e)},t.exports.default=t.exports,t.exports.__esModule=!0},function(t,e,n){var r=n(176).default,o=n(7);t.exports=function(t,e){if(e&&("object"===r(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return o(t)},t.exports.default=t.exports,t.exports.__esModule=!0},,,function(t,e){var n,r,o=t.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}function a(t){if(n===setTimeout)return setTimeout(t,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(t){n=i}try{r="function"==typeof clearTimeout?clearTimeout:s}catch(t){r=s}}();var c,u=[],f=!1,l=-1;function h(){f&&c&&(f=!1,c.length?u=c.concat(u):l=-1,u.length&&p())}function p(){if(!f){var t=a(h);f=!0;for(var e=u.length;e;){for(c=u,u=[];++l1)for(var n=1;n"+t+"<\/script>"},d=function(t){t.write(p("")),t.close();var e=t.parentWindow.Object;return t=null,e},v=function(){try{r=new ActiveXObject("htmlfile")}catch(t){}var t,e;v="undefined"!=typeof document?document.domain&&r?d(r):((e=u("iframe")).style.display="none",c.appendChild(e),e.src=String("javascript:"),(t=e.contentWindow.document).open(),t.write(p("document.F=Object")),t.close(),t.F):d(r);for(var n=s.length;n--;)delete v.prototype[s[n]];return v()};a[l]=!0,t.exports=Object.create||function(t,e){var n;return null!==t?(h.prototype=o(t),n=new h,h.prototype=null,n[l]=t):n=v(),void 0===e?n:i.f(n,e)}},function(t,e,n){var r=n(16),o=n(43),i=n(75),s=n(124),a=n(216),c=n(184),u=n(166),f=n(185).CONFIGURABLE,l=u.get,h=u.enforce,p=String(String).split("String");(t.exports=function(t,e,n,c){var u,l=!!c&&!!c.unsafe,d=!!c&&!!c.enumerable,v=!!c&&!!c.noTargetGet,g=c&&void 0!==c.name?c.name:e;o(n)&&("Symbol("===String(g).slice(0,7)&&(g="["+String(g).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),(!i(n,"name")||f&&n.name!==g)&&s(n,"name",g),(u=h(n)).source||(u.source=p.join("string"==typeof g?g:""))),t!==r?(l?!v&&t[e]&&(d=!0):delete t[e],d?t[e]=n:s(t,e,n)):d?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return o(this)&&l(this).source||c(this)}))},function(t,e,n){var r=n(43);t.exports=function(t){return"object"==typeof t?null!==t:r(t)}},,function(t,e,n){var r=n(132),o=Function.prototype,i=o.apply,s=o.call;t.exports="object"==typeof Reflect&&Reflect.apply||(r?s.bind(i):function(){return s.apply(i,arguments)})},function(t,e,n){var r=n(17),o=r({}.toString),i=r("".slice);t.exports=function(t){return i(o(t),8,-1)}},function(t,e,n){var r=n(203);t.exports=function(t){return r(t.length)}},function(t,e,n){var r=n(73);t.exports=function(t,e,n,o){o&&o.enumerable?t[e]=n:r(t,e,n)}},function(t,e,n){var r=n(205),o=n(54).f,i=n(73),s=n(33),a=n(410),c=n(24)("toStringTag");t.exports=function(t,e,n,u){if(t){var f=n?t:t.prototype;s(f,c)||o(f,c,{configurable:!0,value:e}),u&&!r&&i(f,"toString",a)}}},function(t,e,n){var r=n(14),o=n(81),i=n(50),s=n(47),a=n(156),c=n(295),u=n(100),f=n(34),l=n(247),h=n(146),p=n(296),d=r.TypeError,v=function(t,e){this.stopped=t,this.result=e},g=v.prototype;t.exports=function(t,e,n){var r,y,m,b,w,A,x,k=n&&n.that,C=!(!n||!n.AS_ENTRIES),E=!(!n||!n.IS_ITERATOR),S=!(!n||!n.INTERRUPTED),B=o(e,k),I=function(t){return r&&p(r,"normal",t),new v(!0,t)},O=function(t){return C?(s(t),S?B(t[0],t[1],I):B(t[0],t[1])):S?B(t,I):B(t)};if(E)r=t;else{if(!(y=h(t)))throw d(a(t)+" is not iterable");if(c(y)){for(m=0,b=u(t);b>m;m++)if((w=O(t[m]))&&f(g,w))return w;return new v(!1)}r=l(t,y)}for(A=r.next;!(x=i(A,r)).done;){try{w=O(x.value)}catch(t){p(r,"throw",t)}if("object"==typeof w&&w&&f(g,w))return w}return new v(!1)}},function(t,e,n){var r=n(213),o=n(95),i=n(474);r||o(Object.prototype,"toString",i,{unsafe:!0})},function(t,e,n){var r=n(16).TypeError;t.exports=function(t){if(null==t)throw r("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r,o="object"==typeof Reflect?Reflect:null,i=o&&"function"==typeof o.apply?o.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};r=o&&"function"==typeof o.ownKeys?o.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,t.exports.once=function(t,e){return new Promise((function(n,r){function o(n){t.removeListener(e,i),r(n)}function i(){"function"==typeof t.removeListener&&t.removeListener("error",o),n([].slice.call(arguments))}y(t,e,i,{once:!0}),"error"!==e&&function(t,e,n){"function"==typeof t.on&&y(t,"error",e,n)}(t,o,{once:!0})}))},a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var c=10;function u(t){if("function"!=typeof t)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof t)}function f(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function l(t,e,n,r){var o,i,s,a;if(u(n),void 0===(i=t._events)?(i=t._events=Object.create(null),t._eventsCount=0):(void 0!==i.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),i=t._events),s=i[e]),void 0===s)s=i[e]=n,++t._eventsCount;else if("function"==typeof s?s=i[e]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(o=f(t))>0&&s.length>o&&!s.warned){s.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=t,c.type=e,c.count=s.length,a=c,console&&console.warn&&console.warn(a)}return t}function h(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(t,e,n){var r={fired:!1,wrapFn:void 0,target:t,type:e,listener:n},o=h.bind(r);return o.listener=n,r.wrapFn=o,o}function d(t,e,n){var r=t._events;if(void 0===r)return[];var o=r[e];return void 0===o?[]:"function"==typeof o?n?[o.listener||o]:[o]:n?function(t){for(var e=new Array(t.length),n=0;n0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var c=o[t];if(void 0===c)return!1;if("function"==typeof c)i(c,this,e);else{var u=c.length,f=g(c,u);for(n=0;n=0;i--)if(n[i]===e||n[i].listener===e){s=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():function(t,e){for(;e+1=0;r--)this.removeListener(t,e[r]);return this},a.prototype.listeners=function(t){return d(this,t,!0)},a.prototype.rawListeners=function(t){return d(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):v.call(t,e)},a.prototype.listenerCount=v,a.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(t,e,n){t.exports=n(349)},,function(t,e,n){"use strict";var r=n(347).charAt,o=n(93),i=n(74),s=n(210),a=i.set,c=i.getterFor("String Iterator");s(String,"String",(function(t){a(this,{type:"String Iterator",string:o(t),index:0})}),(function(){var t,e=c(this),n=e.string,o=e.index;return o>=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){t.exports=n(483)},,function(t,e,n){var r=n(99);t.exports=Array.isArray||function(t){return"Array"==r(t)}},function(t,e){t.exports={}},function(t,e,n){var r=n(16),o=n(43),i=function(t){return o(t)?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t]):r[t]&&r[t][e]}},function(t,e,n){var r=n(16),o=n(84),i=n(309),s=n(49),a=n(310),c=r.TypeError,u=Object.defineProperty;e.f=o?u:function(t,e,n){if(s(t),e=a(e),s(n),i)try{return u(t,e,n)}catch(t){}if("get"in n||"set"in n)throw c("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(218);t.exports=function(t,e){var n=t[e];return null==n?void 0:r(n)}},function(t,e,n){function r(t){if(t)return function(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}(t)}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var o=0;o1?{type:p[o],data:t.substring(1)}:{type:p[o]}:d}o=new Uint8Array(t)[0];var i=s(t,1);return v&&"blob"===n&&(i=new v([i])),{type:p[o],data:i}},e.decodeBase64Packet=function(t,e){var n=p[t.charAt(0)];if(!r)return{type:n,data:{base64:!0,data:t.substr(1)}};var o=r.decode(t.substr(1));return"blob"===e&&v&&(o=new v([o])),{type:n,data:o}},e.encodePayload=function(t,n,r){"function"==typeof n&&(r=n,n=null);var o=i(t);if(n&&o)return v&&!l?e.encodePayloadAsBlob(t,r):e.encodePayloadAsArrayBuffer(t,r);if(!t.length)return r("0:");g(t,(function(t,r){e.encodePacket(t,!!o&&n,!1,(function(t){r(null,function(t){return t.length+":"+t}(t))}))}),(function(t,e){return r(e.join(""))}))},e.decodePayload=function(t,n,r){if("string"!=typeof t)return e.decodePayloadAsBinary(t,n,r);var o;if("function"==typeof n&&(r=n,n=null),""===t)return r(d,0,1);for(var i,s,a="",c=0,u=t.length;c0;){for(var a=new Uint8Array(o),c=0===a[0],u="",f=1;255!==a[f];f++){if(u.length>310)return r(d,0,1);u+=a[f]}o=s(o,2+u.length),u=parseInt(u);var l=s(o,0,u);if(c)try{l=String.fromCharCode.apply(null,new Uint8Array(l))}catch(t){var h=new Uint8Array(l);l="";for(f=0;f0&&r[0]<4?1:+(r[0]+r[1])),!o&&s&&(!(r=s.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=s.match(/Chrome\/(\d+)/))&&(o=+r[1]),t.exports=o},function(t,e,n){var r=n(14).String;t.exports=function(t){try{return r(t)}catch(t){return"Object"}}},function(t,e,n){var r=n(17),o=0,i=Math.random(),s=r(1..toString);t.exports=function(t){return"Symbol("+(void 0===t?"":t)+")_"+s(++o+i,36)}},function(t,e,n){"use strict";var r=n(154),o=n(54),i=n(91);t.exports=function(t,e,n){var s=r(e);s in t?o.f(t,s,i(0,n)):t[s]=n}},function(t,e,n){var r=n(17),o=n(20),i=n(27),s=n(92),a=n(56),c=n(206),u=function(){},f=[],l=a("Reflect","construct"),h=/^\s*(?:class|function)\b/,p=r(h.exec),d=!h.exec(u),v=function(t){if(!i(t))return!1;try{return l(u,f,t),!0}catch(t){return!1}},g=function(t){if(!i(t))return!1;switch(s(t)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return d||!!p(h,c(t))}catch(t){return!0}};g.sham=!0,t.exports=!l||o((function(){var t;return v(v.call)||!v(Object)||!v((function(){t=!0}))||t}))?g:v},function(t,e,n){var r=n(20),o=n(24),i=n(155),s=o("species");t.exports=function(t){return i>=51||!r((function(){var e=[];return(e.constructor={})[s]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},function(t,e,n){var r=n(285),o=n(208);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e,n){var r=n(200),o=n(157),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e,n){var r=n(285),o=n(208).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},function(t,e,n){var r=n(17),o=n(47),i=n(428);t.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var t,e=!1,n={};try{(t=r(Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set))(n,[]),e=n instanceof Array}catch(t){}return function(n,r){return o(n),i(r),e?t(n,r):n.__proto__=r,n}}():void 0)},function(t,e,n){"use strict";var r=n(15),o=n(14),i=n(145),s=n(20),a=n(73),c=n(103),u=n(137),f=n(27),l=n(26),h=n(102),p=n(54).f,d=n(83).forEach,v=n(39),g=n(74),y=g.set,m=g.getterFor;t.exports=function(t,e,n){var g,b=-1!==t.indexOf("Map"),w=-1!==t.indexOf("Weak"),A=b?"set":"add",x=o[t],k=x&&x.prototype,C={};if(v&&f(x)&&(w||k.forEach&&!s((function(){(new x).entries().next()})))){var E=(g=e((function(e,n){y(u(e,E),{type:t,collection:new x}),null!=n&&c(n,e[A],{that:e,AS_ENTRIES:b})}))).prototype,S=m(t);d(["add","clear","delete","forEach","get","has","set","keys","values","entries"],(function(t){var e="add"==t||"set"==t;!(t in k)||w&&"clear"==t||a(E,t,(function(n,r){var o=S(this).collection;if(!e&&w&&!l(n))return"get"==t&&void 0;var i=o[t](0===n?0:n,r);return e?this:i}))})),w||p(E,"size",{configurable:!0,get:function(){return S(this).collection.size}})}else g=n.getConstructor(e,t,b,A),i.enable();return h(g,t,!1,!0),C[t]=g,r({global:!0,forced:!0},C),w||n.setStrong(g,t,b),g}},function(t,e,n){var r,o,i,s=n(473),a=n(16),c=n(25),u=n(96),f=n(124),l=n(75),h=n(215),p=n(252),d=n(220),v=a.TypeError,g=a.WeakMap;if(s||h.state){var y=h.state||(h.state=new g),m=c(y.get),b=c(y.has),w=c(y.set);r=function(t,e){if(b(y,t))throw new v("Object already initialized");return e.facade=t,w(y,t,e),e},o=function(t){return m(y,t)||{}},i=function(t){return b(y,t)}}else{var A=p("state");d[A]=!0,r=function(t,e){if(l(t,A))throw new v("Object already initialized");return e.facade=t,f(t,A,e),e},o=function(t){return l(t,A)?t[A]:{}},i=function(t){return l(t,A)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=o(e)).type!==t)throw v("Incompatible receiver, "+t+" required");return n}}}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){var e=+t;return e!=e||0===e?0:(e>0?r:n)(e)}},function(t,e,n){var r=n(167),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){"use strict";var r,o,i=n(59),s=n(25),a=n(85),c=n(254),u=n(255),f=n(214),l=n(256),h=n(166).get,p=n(359),d=n(360),v=f("native-string-replace",String.prototype.replace),g=RegExp.prototype.exec,y=g,m=s("".charAt),b=s("".indexOf),w=s("".replace),A=s("".slice),x=(o=/b*/g,i(g,r=/a/,"a"),i(g,o,"a"),0!==r.lastIndex||0!==o.lastIndex),k=u.UNSUPPORTED_Y||u.BROKEN_CARET,C=void 0!==/()??/.exec("")[1];(x||C||k||p||d)&&(y=function(t){var e,n,r,o,s,u,f,p=this,d=h(p),E=a(t),S=d.raw;if(S)return S.lastIndex=p.lastIndex,e=i(y,S,E),p.lastIndex=S.lastIndex,e;var B=d.groups,I=k&&p.sticky,O=i(c,p),P=p.source,T=0,R=E;if(I&&(O=w(O,"y",""),-1===b(O,"g")&&(O+="g"),R=A(E,p.lastIndex),p.lastIndex>0&&(!p.multiline||p.multiline&&"\n"!==m(E,p.lastIndex-1))&&(P="(?: "+P+")",R=" "+R,T++),n=new RegExp("^(?:"+P+")",O)),C&&(n=new RegExp("^"+P+"$(?!\\s)",O)),x&&(r=p.lastIndex),o=i(g,I?n:p,R),I?o?(o.input=A(o.input,T),o[0]=A(o[0],T),o.index=p.lastIndex,p.lastIndex+=o[0].length):p.lastIndex=0:x&&o&&(p.lastIndex=p.global?o.index+o[0].length:r),C&&o&&o.length>1&&i(v,o[0],n,(function(){for(s=1;s=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},e.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(t){}}(),e.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},e.enable(o())}).call(this,n(90))},function(t,e){e.encode=function(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e},e.decode=function(t){for(var e={},n=t.split("&"),r=0,o=n.length;r=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},e.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(t){}}(),e.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},e.enable(o())}).call(this,n(90))},function(t,e,n){var r=n(401),o=n(437);function i(e){return"function"==typeof r&&"symbol"==typeof o?(t.exports=i=function(t){return typeof t},t.exports.default=t.exports,t.exports.__esModule=!0):(t.exports=i=function(t){return t&&"function"==typeof r&&t.constructor===r&&t!==r.prototype?"symbol":typeof t},t.exports.default=t.exports,t.exports.__esModule=!0),i(e)}t.exports=i,t.exports.default=t.exports,t.exports.__esModule=!0},,,,,function(t,e,n){"use strict";var r={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!r.call({1:2},1);e.f=i?function(t){var e=o(this,t);return!!e&&e.enumerable}:r},function(t,e){t.exports=function(t){try{return{error:!1,value:t()}}catch(t){return{error:!0,value:t}}}},function(t,e,n){var r=n(25);t.exports=r({}.isPrototypeOf)},function(t,e,n){var r=n(25),o=n(43),i=n(215),s=r(Function.toString);o(i.inspectSource)||(i.inspectSource=function(t){return s(t)}),t.exports=i.inspectSource},function(t,e,n){var r=n(84),o=n(75),i=Function.prototype,s=r&&Object.getOwnPropertyDescriptor,a=o(i,"name"),c=a&&"something"===function(){}.name,u=a&&(!r||r&&s(i,"name").configurable);t.exports={EXISTS:a,PROPER:c,CONFIGURABLE:u}},function(t,e,n){var r=n(16),o=n(213),i=n(43),s=n(148),a=n(57)("toStringTag"),c=r.Object,u="Arguments"==s(function(){return arguments}());t.exports=o?s:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=c(t),a))?n:u?s(e):"Object"==(r=s(e))&&i(e.callee)?"Arguments":r}},,,,,function(t,e,n){"use strict";var r=n(631);n.d(e,"a",(function(){return r.a}));n(368);var o=n(263);n.d(e,"b",(function(){return o.a}))},,,,function(t,e,n){"use strict";n.d(e,"d",(function(){return s})),n.d(e,"c",(function(){return a})),n.d(e,"b",(function(){return c})),n.d(e,"a",(function(){return u})),n.d(e,"e",(function(){return f}));n(151);var r=n(30),o=n.n(r),i=(n(337),n(126),n(363),n(539),n(541),n(125),n(225),n(104),n(226),n(367),n(237));function s(){if(location){if("http:"===location.protocol)return"http://"+location.hostname+":9559";if("https:"===location.protocol)return"https://"+location.hostname+":5443"}return null}function a(){var t;return"https:"===(null===(t=location)||void 0===t?void 0:t.protocol)?"https://localhost:5443":"http://localhost:9559"}function c(){var t,e=(new i.UAParser).getResult(),n="Unknown";if(e.device.vendor&&e.device.model)n=o()(t="[".concat(e.device.vendor,"] ")).call(t,e.device.model);else if(e.os.name&&e.browser.name){var r;n=o()(r="[".concat(e.os.name,"] ")).call(r,e.browser.name)}return n}function u(){var t=localStorage.getItem("clientId");if(null===t){var e=(new i.UAParser).getResult(),n="Unknown";void 0!==e.device.vendor?n=e.device.vendor:void 0!==e.os.name&&(n=e.os.name),t=n+"_"+f(),localStorage.setItem("clientId",t)}return t}function f(){return Math.random().toString(36).substring(2,9)}},,function(t,e,n){var r=n(14),o=n(56),i=n(27),s=n(34),a=n(280),c=r.Object;t.exports=a?function(t){return"symbol"==typeof t}:function(t){var e=o("Symbol");return i(e)&&s(e.prototype,c(t))}},function(t,e,n){var r=n(155),o=n(20);t.exports=!!Object.getOwnPropertySymbols&&!o((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&r&&r<41}))},function(t,e,n){var r=n(79);t.exports=function(t,e){var n=t[e];return null==n?void 0:r(n)}},function(t,e,n){var r=n(70),o=n(201);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.21.1",mode:r?"pure":"global",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE",source:"https://github.com/zloirock/core-js"})},function(t,e,n){var r=n(14),o=n(407),i=r["__core-js_shared__"]||o("__core-js_shared__",{});t.exports=i},function(t,e,n){var r=n(14),o=n(26),i=r.document,s=o(i)&&o(i.createElement);t.exports=function(t){return s?i.createElement(t):{}}},function(t,e,n){var r=n(204),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){var e=+t;return e!=e||0===e?0:(e>0?r:n)(e)}},function(t,e,n){var r={};r[n(24)("toStringTag")]="z",t.exports="[object z]"===String(r)},function(t,e,n){var r=n(17),o=n(27),i=n(201),s=r(Function.toString);o(i.inspectSource)||(i.inspectSource=function(t){return s(t)}),t.exports=i.inspectSource},function(t,e,n){var r=n(204),o=Math.max,i=Math.min;t.exports=function(t,e){var n=r(t);return n<0?o(n+e,0):i(n,e)}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e,n){var r=n(24);e.f=r},function(t,e,n){"use strict";var r=n(15),o=n(50),i=n(70),s=n(427),a=n(27),c=n(346),u=n(136),f=n(164),l=n(102),h=n(73),p=n(101),d=n(24),v=n(113),g=n(291),y=s.PROPER,m=s.CONFIGURABLE,b=g.IteratorPrototype,w=g.BUGGY_SAFARI_ITERATORS,A=d("iterator"),x=function(){return this};t.exports=function(t,e,n,s,d,g,k){c(n,e,s);var C,E,S,B=function(t){if(t===d&&R)return R;if(!w&&t in P)return P[t];switch(t){case"keys":case"values":case"entries":return function(){return new n(this,t)}}return function(){return new n(this)}},I=e+" Iterator",O=!1,P=t.prototype,T=P[A]||P["@@iterator"]||d&&P[d],R=!w&&T||B(d),j="Array"==e&&P.entries||T;if(j&&(C=u(j.call(new t)))!==Object.prototype&&C.next&&(i||u(C)===b||(f?f(C,b):a(C[A])||p(C,A,x)),l(C,I,!0,!0),i&&(v[I]=x)),y&&"values"==d&&T&&"values"!==T.name&&(!i&&m?h(P,"name","values"):(O=!0,R=function(){return o(T,this)})),d)if(E={values:B("values"),keys:g?R:B("keys"),entries:B("entries")},k)for(S in E)(w||O||!(S in P))&&p(P,S,E[S]);else r({target:e,proto:!0,forced:w||O},E);return i&&!k||P[A]===R||p(P,A,R,{name:d}),v[e]=R,E}},function(t,e,n){var r=n(14).TypeError;t.exports=function(t,e){if(t0)return function(t){if((t=String(t)).length>100)return;var e=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(t);if(!e)return;var s=parseFloat(e[1]);switch((e[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*o;case"minutes":case"minute":case"mins":case"min":case"m":return s*r;case"seconds":case"second":case"secs":case"sec":case"s":return s*n;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}(t);if("number"===c&&!1===isNaN(t))return e.long?s(a=t,i,"day")||s(a,o,"hour")||s(a,r,"minute")||s(a,n,"second")||a+" ms":function(t){if(t>=i)return Math.round(t/i)+"d";if(t>=o)return Math.round(t/o)+"h";if(t>=r)return Math.round(t/r)+"m";if(t>=n)return Math.round(t/n)+"s";return t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,n){var r=n(546)("socket.io-parser"),o=n(117),i=n(318),s=n(552),a=n(320),c=n(321);function u(){}function f(t){var n=""+t.type;return e.BINARY_EVENT!==t.type&&e.BINARY_ACK!==t.type||(n+=t.attachments+"-"),t.nsp&&"/"!==t.nsp&&(n+=t.nsp+","),null!=t.id&&(n+=t.id),null!=t.data&&(n+=JSON.stringify(t.data)),r("encoded %j as %s",t,n),n}function l(){this.reconstructor=null}function h(t){this.reconPack=t,this.buffers=[]}function p(t){return{type:e.ERROR,data:"parser error: "+t}}e.protocol=4,e.types=["CONNECT","DISCONNECT","EVENT","ACK","ERROR","BINARY_EVENT","BINARY_ACK"],e.CONNECT=0,e.DISCONNECT=1,e.EVENT=2,e.ACK=3,e.ERROR=4,e.BINARY_EVENT=5,e.BINARY_ACK=6,e.Encoder=u,e.Decoder=l,u.prototype.encode=function(t,n){(t.type!==e.EVENT&&t.type!==e.ACK||!i(t.data)||(t.type=t.type===e.EVENT?e.BINARY_EVENT:e.BINARY_ACK),r("encoding packet %j",t),e.BINARY_EVENT===t.type||e.BINARY_ACK===t.type)?function(t,e){s.removeBlobs(t,(function(t){var n=s.deconstructPacket(t),r=f(n.packet),o=n.buffers;o.unshift(r),e(o)}))}(t,n):n([f(t)])},o(l.prototype),l.prototype.add=function(t){var n;if("string"==typeof t)n=function(t){var n=0,o={type:Number(t.charAt(0))};if(null==e.types[o.type])return p("unknown packet type "+o.type);if(e.BINARY_EVENT===o.type||e.BINARY_ACK===o.type){for(var i="";"-"!==t.charAt(++n)&&(i+=t.charAt(n),n!=t.length););if(i!=Number(i)||"-"!==t.charAt(n))throw new Error("Illegal attachments");o.attachments=Number(i)}if("/"===t.charAt(n+1))for(o.nsp="";++n;){if(","===(c=t.charAt(n)))break;if(o.nsp+=c,n===t.length)break}else o.nsp="/";var s=t.charAt(n+1);if(""!==s&&Number(s)==s){for(o.id="";++n;){var c;if(null==(c=t.charAt(n))||Number(c)!=c){--n;break}if(o.id+=t.charAt(n),n===t.length)break}o.id=Number(o.id)}if(t.charAt(++n)){var u=function(t){try{return JSON.parse(t)}catch(t){return!1}}(t.substr(n));if(!(!1!==u&&(o.type===e.ERROR||a(u))))return p("invalid payload");o.data=u}return r("decoded %s as %j",t,o),o}(t),e.BINARY_EVENT===n.type||e.BINARY_ACK===n.type?(this.reconstructor=new h(n),0===this.reconstructor.reconPack.attachments&&this.emit("decoded",n)):this.emit("decoded",n);else{if(!c(t)&&!t.base64)throw new Error("Unknown type: "+t);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");(n=this.reconstructor.takeBinaryData(t))&&(this.reconstructor=null,this.emit("decoded",n))}},l.prototype.destroy=function(){this.reconstructor&&this.reconstructor.finishedReconstruction()},h.prototype.takeBinaryData=function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=s.reconstructPacket(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null},h.prototype.finishedReconstruction=function(){this.reconPack=null,this.buffers=[]}},function(t,e,n){(function(e){var r=n(555);t.exports=function(t){var n=t.xdomain,o=t.xscheme,i=t.enablesXDR;try{if("undefined"!=typeof XMLHttpRequest&&(!n||r))return new XMLHttpRequest}catch(t){}try{if("undefined"!=typeof XDomainRequest&&!o&&i)return new XDomainRequest}catch(t){}if(!n)try{return new(e[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(t){}}}).call(this,n(53))},function(t,e,n){var r=n(118),o=n(117);function i(t){this.path=t.path,this.hostname=t.hostname,this.port=t.port,this.secure=t.secure,this.query=t.query,this.timestampParam=t.timestampParam,this.timestampRequests=t.timestampRequests,this.readyState="",this.agent=t.agent||!1,this.socket=t.socket,this.enablesXDR=t.enablesXDR,this.pfx=t.pfx,this.key=t.key,this.passphrase=t.passphrase,this.cert=t.cert,this.ca=t.ca,this.ciphers=t.ciphers,this.rejectUnauthorized=t.rejectUnauthorized,this.forceNode=t.forceNode,this.extraHeaders=t.extraHeaders,this.localAddress=t.localAddress}t.exports=i,o(i.prototype),i.prototype.onError=function(t,e){var n=new Error(t);return n.type="TransportError",n.description=e,this.emit("error",n),this},i.prototype.open=function(){return"closed"!==this.readyState&&""!==this.readyState||(this.readyState="opening",this.doOpen()),this},i.prototype.close=function(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this},i.prototype.send=function(t){if("open"!==this.readyState)throw new Error("Transport not open");this.write(t)},i.prototype.onOpen=function(){this.readyState="open",this.writable=!0,this.emit("open")},i.prototype.onData=function(t){var e=r.decodePacket(t,this.socket.binaryType);this.onPacket(e)},i.prototype.onPacket=function(t){this.emit("packet",t)},i.prototype.onClose=function(){this.readyState="closed",this.emit("close")}},,function(t,e,n){t.exports=n(573)},function(t,e,n){t.exports=n(579)},,,,function(t,e,n){var r; /*! * UAParser.js v0.7.21 * Lightweight JavaScript-based User-Agent string parser @@ -6,15 +6,15 @@ window.offload=function(e){var t={};function n(r){if(t[r])return t[r].exports;va * * Copyright © 2012-2019 Faisal Salman * Licensed under MIT License - */!function(o,i){"use strict";var s="model",a="name",c="type",u="vendor",l="version",f="mobile",h="tablet",p="smarttv",d={extend:function(e,t){var n={};for(var r in e)t[r]&&t[r].length%2==0?n[r]=t[r].concat(e[r]):n[r]=e[r];return n},has:function(e,t){return"string"==typeof e&&-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()},major:function(e){return"string"==typeof e?e.replace(/[^\d\.]/g,"").split(".")[0]:void 0},trim:function(e){return e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}},g={rgx:function(e,t){for(var n,r,o,i,s,a,c=0;c0?2==i.length?"function"==typeof i[1]?this[i[0]]=i[1].call(this,a):this[i[0]]=i[1]:3==i.length?"function"!=typeof i[1]||i[1].exec&&i[1].test?this[i[0]]=a?a.replace(i[1],i[2]):void 0:this[i[0]]=a?i[1].call(this,a,i[2]):void 0:4==i.length&&(this[i[0]]=a?i[3].call(this,a.replace(i[1],i[2])):void 0):this[i]=a||void 0;c+=2}},str:function(e,t){for(var n in t)if("object"==typeof t[n]&&t[n].length>0){for(var r=0;r=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(o())}).call(this,n(3))},function(e,t,n){function r(e){var n;function r(){if(r.enabled){var e=r,o=+new Date,i=o-(n||o);e.diff=i,e.prev=n,e.curr=o,n=o;for(var s=new Array(arguments.length),a=0;a0?2==i.length?"function"==typeof i[1]?this[i[0]]=i[1].call(this,a):this[i[0]]=i[1]:3==i.length?"function"!=typeof i[1]||i[1].exec&&i[1].test?this[i[0]]=a?a.replace(i[1],i[2]):void 0:this[i[0]]=a?i[1].call(this,a,i[2]):void 0:4==i.length&&(this[i[0]]=a?i[3].call(this,a.replace(i[1],i[2])):void 0):this[i]=a||void 0;c+=2}},str:function(t,e){for(var n in e)if("object"==typeof e[n]&&e[n].length>0){for(var r=0;rf;)i.f(t,n=o[f++],r[n]);return t}},function(t,e,n){var r=n(65),o=n(207),i=n(100),s=function(t){return function(e,n,s){var a,c=r(e),u=i(c),f=o(s,u);if(t&&n!=n){for(;u>f;)if((a=c[f++])!=a)return!0}else for(;u>f;f++)if((t||f in c)&&c[f]===n)return t||f||0;return!t&&-1}};t.exports={includes:s(!0),indexOf:s(!1)}},function(t,e){e.f=Object.getOwnPropertySymbols},function(t,e){t.exports=function(){}},function(t,e,n){var r=n(14),o=n(50),i=n(79),s=n(47),a=n(156),c=n(146),u=r.TypeError;t.exports=function(t,e){var n=arguments.length<2?c(t):e;if(i(n))return s(o(n,t));throw u(a(t)+" is not iterable")}},function(t,e){t.exports=!1},function(t,e,n){var r=n(16),o=n(105),i=r.Object;t.exports=function(t){return i(o(t))}},function(t,e,n){var r=n(114);t.exports=r("navigator","userAgent")||""},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r=n(214),o=n(306),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e,n){var r=n(84),o=n(59),i=n(486),s=n(251),a=n(127),c=n(310),u=n(75),f=n(309),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=a(t),e=c(e),f)try{return l(t,e)}catch(t){}if(u(t,e))return s(!o(i.f,t,e),t[e])}},function(t,e,n){"use strict";var r=n(49);t.exports=function(){var t=r(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},function(t,e,n){var r=n(45),o=n(16).RegExp;e.UNSUPPORTED_Y=r((function(){var t=o("a","y");return t.lastIndex=2,null!=t.exec("abcd")})),e.BROKEN_CARET=r((function(){var t=o("^r","gy");return t.lastIndex=2,null!=t.exec("str")}))},function(t,e,n){var r,o=n(49),i=n(492),s=n(222),a=n(220),c=n(358),u=n(217),f=n(252),l=f("IE_PROTO"),h=function(){},p=function(t){return"