@supraio/client-daemon-js 0.0.1 → 1.0.0-mzscreengeometry.449
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/daemon.html +1 -1
- package/daemon.js +25 -17
- package/daemon.js.map +2 -2
- package/package.json +3 -3
- package/screen/control.d.ts +16 -0
- package/screen/nacldecoder.d.ts +2 -1
- package/screen/options.d.ts +11 -0
- package/screen/plain.d.ts +2 -1
- package/screen/samsungwasmdecoder.d.ts +1 -1
- package/screen/shared.d.ts +2 -1
- package/screen/wasm.d.ts +2 -1
- package/screen/workerFrameConnection.d.ts +2 -1
- package/screen.html +1 -1
- package/screen.js +100 -42
- package/screen.js.map +2 -2
- package/sdk.d.ts +1 -0
- package/sdk.js +110 -44
- package/sdk.js.map +2 -2
- package/supra-client-daemon.js +402 -232
- package/supra-client-daemon.js.map +1 -1
- package/supra-client-daemon.wasm +0 -0
- package/supra-client-screen.js +925 -491
- package/supra-client-screen.js.map +1 -1
- package/supra-client-screen.wasm +0 -0
package/sdk.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { IScreenOptions, IEncodingPreferences } from "./screen/options";
|
|
|
3
3
|
export { IScreenControl, IClientStats, createScreenControl } from "./screen/control";
|
|
4
4
|
export interface StartOptions {
|
|
5
5
|
forcePlain?: boolean;
|
|
6
|
+
netInWorker?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare function startDaemon(options?: StartOptions): Promise<void>;
|
|
8
9
|
export declare function startScreen(options?: StartOptions & IScreenOptions): Promise<void>;
|
package/sdk.js
CHANGED
|
@@ -17226,8 +17226,8 @@ var require_module = __commonJS({
|
|
|
17226
17226
|
function handleCrash(event) {
|
|
17227
17227
|
console.log("nacl crash", event);
|
|
17228
17228
|
}
|
|
17229
|
-
function createNaClModule(handleMessage) {
|
|
17230
|
-
var _a, _b;
|
|
17229
|
+
function createNaClModule(handleMessage, geometry) {
|
|
17230
|
+
var _a, _b, _c, _d;
|
|
17231
17231
|
var listenerEl = document.createElement("div");
|
|
17232
17232
|
listenerEl.setAttribute("id", "listener");
|
|
17233
17233
|
listenerEl.addEventListener("message", handleMessage, true);
|
|
@@ -17237,8 +17237,15 @@ var require_module = __commonJS({
|
|
|
17237
17237
|
var baseHref = (_b = (_a = document.getElementsByTagName("base")[0]) === null || _a === void 0 ? void 0 : _a.href) !== null && _b !== void 0 ? _b : location.href;
|
|
17238
17238
|
var nmpPath = new URL("nacl-decoder.nmf", baseHref).href;
|
|
17239
17239
|
var naclModuleEl = document.createElement("embed");
|
|
17240
|
-
|
|
17241
|
-
|
|
17240
|
+
var width = (_c = geometry === null || geometry === void 0 ? void 0 : geometry.width) !== null && _c !== void 0 ? _c : window.screen.width;
|
|
17241
|
+
var height = (_d = geometry === null || geometry === void 0 ? void 0 : geometry.height) !== null && _d !== void 0 ? _d : window.screen.height;
|
|
17242
|
+
naclModuleEl.setAttribute("width", "".concat(width));
|
|
17243
|
+
naclModuleEl.setAttribute("height", "".concat(height));
|
|
17244
|
+
if (geometry) {
|
|
17245
|
+
naclModuleEl.style.position = "absolute";
|
|
17246
|
+
naclModuleEl.style.left = "".concat(geometry.x, "px");
|
|
17247
|
+
naclModuleEl.style.top = "".concat(geometry.y, "px");
|
|
17248
|
+
}
|
|
17242
17249
|
naclModuleEl.setAttribute("src", nmpPath);
|
|
17243
17250
|
naclModuleEl.setAttribute("type", "application/x-nacl");
|
|
17244
17251
|
naclModuleEl.setAttribute("id", "nacl_module");
|
|
@@ -18337,20 +18344,20 @@ var require_dist = __commonJS({
|
|
|
18337
18344
|
if (!isNaClSupported3()) {
|
|
18338
18345
|
throw new Error("NaCl is not supported in this browser.");
|
|
18339
18346
|
}
|
|
18340
|
-
var runtime = getNaClRuntime(requiredOptions.timeoutMs);
|
|
18347
|
+
var runtime = getNaClRuntime(requiredOptions.timeoutMs, options === null || options === void 0 ? void 0 : options.geometry);
|
|
18341
18348
|
return new naclDecoder_1.NaClDecoder(runtime.messageSender, runtime.naclModuleEl);
|
|
18342
18349
|
}
|
|
18343
18350
|
function createNaClTCP2(options) {
|
|
18344
18351
|
var decoder = createNaClDecoder2(options);
|
|
18345
18352
|
return decoder.createTCP();
|
|
18346
18353
|
}
|
|
18347
|
-
function getNaClRuntime(timeoutMs) {
|
|
18354
|
+
function getNaClRuntime(timeoutMs, geometry) {
|
|
18348
18355
|
if (naclRuntime) {
|
|
18349
18356
|
return naclRuntime;
|
|
18350
18357
|
}
|
|
18351
18358
|
var messageListeners = (0, messageListeners_1.createMessageListeners)();
|
|
18352
18359
|
var messageReceiver = new messageReceiver_1.MessageReceiver(messageListeners);
|
|
18353
|
-
var naclModuleEl = (0, module_1.createNaClModule)(messageReceiver.handleMessage.bind(messageReceiver));
|
|
18360
|
+
var naclModuleEl = (0, module_1.createNaClModule)(messageReceiver.handleMessage.bind(messageReceiver), geometry);
|
|
18354
18361
|
var messageSender = new messageSender_1.MessageSender(naclModuleEl, messageListeners, timeoutMs);
|
|
18355
18362
|
naclRuntime = {
|
|
18356
18363
|
messageSender,
|
|
@@ -19697,16 +19704,17 @@ var require_wasmDecoder = __commonJS({
|
|
|
19697
19704
|
}
|
|
19698
19705
|
return false;
|
|
19699
19706
|
}
|
|
19700
|
-
function ensureVideoElement(videoElementId) {
|
|
19707
|
+
function ensureVideoElement(videoElementId, geometry) {
|
|
19708
|
+
var _a, _b, _c, _d;
|
|
19701
19709
|
var el = document.getElementById(videoElementId);
|
|
19702
19710
|
if (!el) {
|
|
19703
19711
|
el = document.createElement("video");
|
|
19704
19712
|
el.id = videoElementId;
|
|
19705
19713
|
el.style.position = "absolute";
|
|
19706
|
-
el.style.top = "0";
|
|
19707
|
-
el.style.left = "0";
|
|
19708
|
-
el.style.width = "
|
|
19709
|
-
el.style.height = "
|
|
19714
|
+
el.style.top = "".concat((_a = geometry === null || geometry === void 0 ? void 0 : geometry.y) !== null && _a !== void 0 ? _a : 0, "px");
|
|
19715
|
+
el.style.left = "".concat((_b = geometry === null || geometry === void 0 ? void 0 : geometry.x) !== null && _b !== void 0 ? _b : 0, "px");
|
|
19716
|
+
el.style.width = "".concat((_c = geometry === null || geometry === void 0 ? void 0 : geometry.width) !== null && _c !== void 0 ? _c : 1920, "px");
|
|
19717
|
+
el.style.height = "".concat((_d = geometry === null || geometry === void 0 ? void 0 : geometry.height) !== null && _d !== void 0 ? _d : 1080, "px");
|
|
19710
19718
|
el.style.backgroundColor = "#000";
|
|
19711
19719
|
document.body.appendChild(el);
|
|
19712
19720
|
}
|
|
@@ -19718,14 +19726,14 @@ var require_wasmDecoder = __commonJS({
|
|
|
19718
19726
|
var SamsungWasmDecoder2 = (
|
|
19719
19727
|
/** @class */
|
|
19720
19728
|
function() {
|
|
19721
|
-
function SamsungWasmDecoder3(videoElementId) {
|
|
19729
|
+
function SamsungWasmDecoder3(videoElementId, geometry) {
|
|
19722
19730
|
this.videoElementId = videoElementId;
|
|
19723
19731
|
this.initialized = false;
|
|
19724
19732
|
this.destroyed = false;
|
|
19725
19733
|
this.decoderHandle = 0;
|
|
19726
19734
|
this.ptsSeconds = 0;
|
|
19727
19735
|
this.frameDurationSeconds = 0;
|
|
19728
|
-
this.videoElement = ensureVideoElement(videoElementId);
|
|
19736
|
+
this.videoElement = ensureVideoElement(videoElementId, geometry);
|
|
19729
19737
|
}
|
|
19730
19738
|
SamsungWasmDecoder3.prototype.destroy = function() {
|
|
19731
19739
|
return __awaiter(this, void 0, void 0, function() {
|
|
@@ -20098,7 +20106,7 @@ var require_dist2 = __commonJS({
|
|
|
20098
20106
|
return [4, (0, wasmLoader_1.loadWasmModule)()];
|
|
20099
20107
|
case 1:
|
|
20100
20108
|
_a.sent();
|
|
20101
|
-
return [2, new wasmDecoder_1.SamsungWasmDecoder(options.videoElementId)];
|
|
20109
|
+
return [2, new wasmDecoder_1.SamsungWasmDecoder(options.videoElementId, options.geometry)];
|
|
20102
20110
|
}
|
|
20103
20111
|
});
|
|
20104
20112
|
});
|
|
@@ -20643,7 +20651,7 @@ async function initSamsungWasmTCP() {
|
|
|
20643
20651
|
}
|
|
20644
20652
|
|
|
20645
20653
|
// daemon/plain.ts
|
|
20646
|
-
var DAEMON_JS_URL = "supra-client-daemon.js?v=0.0.
|
|
20654
|
+
var DAEMON_JS_URL = "supra-client-daemon.js?v=1.0.0-mzscreengeometry.449";
|
|
20647
20655
|
async function startPlainDaemon() {
|
|
20648
20656
|
await initNaClTCP();
|
|
20649
20657
|
await initSamsungWasmTCP();
|
|
@@ -20656,7 +20664,7 @@ async function startPlainDaemon() {
|
|
|
20656
20664
|
}
|
|
20657
20665
|
|
|
20658
20666
|
// daemon/wasm.ts
|
|
20659
|
-
var DAEMON_WASM_URL = "supra-client-daemon.wasm?v=0.0.
|
|
20667
|
+
var DAEMON_WASM_URL = "supra-client-daemon.wasm?v=1.0.0-mzscreengeometry.449";
|
|
20660
20668
|
async function startWasmDaemon() {
|
|
20661
20669
|
await initNaClTCP();
|
|
20662
20670
|
await initSamsungWasmTCP();
|
|
@@ -20678,9 +20686,10 @@ function getGoArgv() {
|
|
|
20678
20686
|
|
|
20679
20687
|
// screen/nacldecoder.ts
|
|
20680
20688
|
var import_nacl_decoder2 = __toESM(require_dist());
|
|
20681
|
-
function initNaCLDecoder() {
|
|
20689
|
+
function initNaCLDecoder(options) {
|
|
20682
20690
|
if ((0, import_nacl_decoder2.isNaClSupported)()) {
|
|
20683
|
-
|
|
20691
|
+
const geometry = options == null ? void 0 : options.geometry;
|
|
20692
|
+
window.createNaClDecoder = (decoderOptions) => (0, import_nacl_decoder2.createNaClDecoder)({ geometry, ...decoderOptions });
|
|
20684
20693
|
}
|
|
20685
20694
|
}
|
|
20686
20695
|
|
|
@@ -20693,8 +20702,17 @@ var frames = {};
|
|
|
20693
20702
|
var closed = false;
|
|
20694
20703
|
var GENERAL_HEADER_SIZE = 6;
|
|
20695
20704
|
var FIRST_HEADER_SIZE = GENERAL_HEADER_SIZE + 9;
|
|
20696
|
-
|
|
20697
|
-
|
|
20705
|
+
|
|
20706
|
+
function now() {
|
|
20707
|
+
if (
|
|
20708
|
+
typeof performance !== 'undefined' &&
|
|
20709
|
+
typeof performance.timeOrigin === 'number' &&
|
|
20710
|
+
typeof performance.now === 'function'
|
|
20711
|
+
) {
|
|
20712
|
+
return performance.timeOrigin + performance.now();
|
|
20713
|
+
}
|
|
20714
|
+
return Date.now();
|
|
20715
|
+
}
|
|
20698
20716
|
|
|
20699
20717
|
function postError(id, error) {
|
|
20700
20718
|
self.postMessage({ type: 'error', id: id, error: error && error.message ? error.message : String(error) });
|
|
@@ -20714,7 +20732,8 @@ function resolveFrame() {
|
|
|
20714
20732
|
frameType: frame.frameType,
|
|
20715
20733
|
timestamp: frame.timestamp,
|
|
20716
20734
|
length: frame.length,
|
|
20717
|
-
data: frame.data
|
|
20735
|
+
data: frame.data,
|
|
20736
|
+
firstPacketAt: frame.firstPacketAt
|
|
20718
20737
|
}, [frame.data]);
|
|
20719
20738
|
}
|
|
20720
20739
|
|
|
@@ -20741,11 +20760,12 @@ function handlePacket(buffer) {
|
|
|
20741
20760
|
var item = frames[frameID];
|
|
20742
20761
|
if (!item || seq === 0 || item.total !== total) {
|
|
20743
20762
|
item = {
|
|
20744
|
-
|
|
20763
|
+
packets: new Array(total),
|
|
20745
20764
|
frameType: 0,
|
|
20746
20765
|
timestamp: 0,
|
|
20747
20766
|
total: total,
|
|
20748
|
-
received: 0
|
|
20767
|
+
received: 0,
|
|
20768
|
+
firstPacketAt: now()
|
|
20749
20769
|
};
|
|
20750
20770
|
frames[frameID] = item;
|
|
20751
20771
|
if (seq === 0) {
|
|
@@ -20759,25 +20779,39 @@ function handlePacket(buffer) {
|
|
|
20759
20779
|
}
|
|
20760
20780
|
}
|
|
20761
20781
|
|
|
20762
|
-
|
|
20763
|
-
|
|
20764
|
-
|
|
20782
|
+
if (total === 0 || seq >= total) {
|
|
20783
|
+
delete frames[frameID];
|
|
20784
|
+
return;
|
|
20765
20785
|
}
|
|
20766
20786
|
var packetData = new Uint8Array(buffer, headerSize);
|
|
20767
|
-
item.
|
|
20768
|
-
|
|
20787
|
+
if (!item.packets[seq]) {
|
|
20788
|
+
item.received++;
|
|
20789
|
+
}
|
|
20790
|
+
item.packets[seq] = packetData;
|
|
20769
20791
|
|
|
20770
20792
|
if (seq + 1 === total) {
|
|
20771
20793
|
delete frames[frameID];
|
|
20772
20794
|
if (item.received !== item.total) {
|
|
20773
20795
|
return;
|
|
20774
20796
|
}
|
|
20775
|
-
var
|
|
20797
|
+
var dataLength = 0;
|
|
20798
|
+
var packetIndex;
|
|
20799
|
+
for (packetIndex = 0; packetIndex < item.packets.length; packetIndex++) {
|
|
20800
|
+
dataLength += item.packets[packetIndex].byteLength;
|
|
20801
|
+
}
|
|
20802
|
+
var frameBuffer = new Uint8Array(dataLength);
|
|
20803
|
+
var dataStartsAt = 0;
|
|
20804
|
+
for (packetIndex = 0; packetIndex < item.packets.length; packetIndex++) {
|
|
20805
|
+
var completedPacket = item.packets[packetIndex];
|
|
20806
|
+
frameBuffer.set(completedPacket, dataStartsAt);
|
|
20807
|
+
dataStartsAt += completedPacket.byteLength;
|
|
20808
|
+
}
|
|
20776
20809
|
latestFrame = {
|
|
20777
20810
|
frameType: item.frameType,
|
|
20778
20811
|
timestamp: item.timestamp,
|
|
20779
|
-
length:
|
|
20780
|
-
data:
|
|
20812
|
+
length: dataLength,
|
|
20813
|
+
data: frameBuffer.buffer,
|
|
20814
|
+
firstPacketAt: item.firstPacketAt
|
|
20781
20815
|
};
|
|
20782
20816
|
resolveFrame();
|
|
20783
20817
|
}
|
|
@@ -20864,7 +20898,8 @@ var createSupraFrameWorkerConnection = (url) => {
|
|
|
20864
20898
|
frameType: message.frameType,
|
|
20865
20899
|
timestamp: message.timestamp,
|
|
20866
20900
|
length: message.length,
|
|
20867
|
-
data: message.data
|
|
20901
|
+
data: message.data,
|
|
20902
|
+
firstPacketAt: message.firstPacketAt
|
|
20868
20903
|
});
|
|
20869
20904
|
}
|
|
20870
20905
|
};
|
|
@@ -20890,8 +20925,9 @@ var createSupraFrameWorkerConnection = (url) => {
|
|
|
20890
20925
|
}
|
|
20891
20926
|
};
|
|
20892
20927
|
};
|
|
20893
|
-
function initWorkerFrameConnection() {
|
|
20894
|
-
|
|
20928
|
+
function initWorkerFrameConnection(enabled) {
|
|
20929
|
+
delete window.createSupraFrameWorkerConnection;
|
|
20930
|
+
if (enabled && typeof Worker !== "undefined") {
|
|
20895
20931
|
window.createSupraFrameWorkerConnection = createSupraFrameWorkerConnection;
|
|
20896
20932
|
}
|
|
20897
20933
|
}
|
|
@@ -20902,7 +20938,8 @@ var import_videoDecoder = __toESM(require_videoDecoder2());
|
|
|
20902
20938
|
async function initSamsungWasmDecoder(options) {
|
|
20903
20939
|
if ((0, import_samsung_wasm_decoder2.isSamsungWasmSupported)()) {
|
|
20904
20940
|
window.samsungWasmDecoder = await (0, import_samsung_wasm_decoder2.createSamsungWasmDecoder)({
|
|
20905
|
-
videoElementId: "samsung-wasm-video"
|
|
20941
|
+
videoElementId: "samsung-wasm-video",
|
|
20942
|
+
geometry: options.geometry
|
|
20906
20943
|
});
|
|
20907
20944
|
const latencyMode = options.interactive ? import_videoDecoder.LatencyMode.UltraLow : import_videoDecoder.LatencyMode.Low;
|
|
20908
20945
|
await window.samsungWasmDecoder.initialize({ latencyMode });
|
|
@@ -20943,7 +20980,8 @@ function parseQueryOptions() {
|
|
|
20943
20980
|
clientID: params.clientID,
|
|
20944
20981
|
clientSecret: params.clientSecret,
|
|
20945
20982
|
secure: params.secure !== "false",
|
|
20946
|
-
interactive: params.interactive === "true"
|
|
20983
|
+
interactive: params.interactive === "true",
|
|
20984
|
+
netInWorker: params.netInWorker === "true"
|
|
20947
20985
|
};
|
|
20948
20986
|
if (typeof params.forceScreenSize === "string") {
|
|
20949
20987
|
const sizeParts = params.forceScreenSize.split("x");
|
|
@@ -20957,6 +20995,17 @@ function parseQueryOptions() {
|
|
|
20957
20995
|
}
|
|
20958
20996
|
options.forceScreenSize = { width, height };
|
|
20959
20997
|
}
|
|
20998
|
+
if (typeof params.geometry === "string" && params.geometry !== "") {
|
|
20999
|
+
const geometryParts = params.geometry.split(",");
|
|
21000
|
+
if (geometryParts.length !== 4) {
|
|
21001
|
+
throw new Error(`Invalid geometry query param, expected "x,y,width,height"`);
|
|
21002
|
+
}
|
|
21003
|
+
const [x, y, width, height] = geometryParts.map(Number);
|
|
21004
|
+
if ([x, y, width, height].some(isNaN) || width <= 0 || height <= 0) {
|
|
21005
|
+
throw new Error(`Invalid geometry query param`);
|
|
21006
|
+
}
|
|
21007
|
+
options.geometry = { x, y, width, height };
|
|
21008
|
+
}
|
|
20960
21009
|
const encodingPreferences = {};
|
|
20961
21010
|
if (params.preferredPreset) {
|
|
20962
21011
|
encodingPreferences.preferredPreset = params.preferredPreset;
|
|
@@ -20991,16 +21040,17 @@ function getGoArgv2(binFile, options) {
|
|
|
20991
21040
|
options.clientSecret,
|
|
20992
21041
|
options.secure ? "1" : "0",
|
|
20993
21042
|
options.forceScreenSize ? `${options.forceScreenSize.width}x${options.forceScreenSize.height}` : "",
|
|
20994
|
-
encodingPrefsJson
|
|
21043
|
+
encodingPrefsJson,
|
|
21044
|
+
options.geometry ? JSON.stringify(options.geometry) : ""
|
|
20995
21045
|
];
|
|
20996
21046
|
}
|
|
20997
21047
|
|
|
20998
21048
|
// screen/plain.ts
|
|
20999
|
-
var SCREEN_JS_URL = "supra-client-screen.js?v=0.0.
|
|
21049
|
+
var SCREEN_JS_URL = "supra-client-screen.js?v=1.0.0-mzscreengeometry.449";
|
|
21000
21050
|
async function startPlainScreen(options) {
|
|
21001
21051
|
options = options != null ? options : parseQueryOptions();
|
|
21002
|
-
initNaCLDecoder();
|
|
21003
|
-
initWorkerFrameConnection();
|
|
21052
|
+
initNaCLDecoder(options);
|
|
21053
|
+
initWorkerFrameConnection(options.netInWorker === true);
|
|
21004
21054
|
await initNaClTCP();
|
|
21005
21055
|
await initSamsungWasmTCP();
|
|
21006
21056
|
await initSamsungWasmDecoder(options);
|
|
@@ -21009,7 +21059,15 @@ async function startPlainScreen(options) {
|
|
|
21009
21059
|
process.argv = ["go", ...getGoArgv2(SCREEN_JS_URL, options)];
|
|
21010
21060
|
Object.assign(process.env, getGoEnv());
|
|
21011
21061
|
await injectScript(SCREEN_JS_URL);
|
|
21012
|
-
await new Promise(() =>
|
|
21062
|
+
await new Promise((resolve) => {
|
|
21063
|
+
const interval = setInterval(() => {
|
|
21064
|
+
var _a;
|
|
21065
|
+
if (((_a = window.__supra) == null ? void 0 : _a.screenStopped) === true) {
|
|
21066
|
+
clearInterval(interval);
|
|
21067
|
+
resolve();
|
|
21068
|
+
}
|
|
21069
|
+
}, 500);
|
|
21070
|
+
});
|
|
21013
21071
|
}
|
|
21014
21072
|
|
|
21015
21073
|
// screen/h264decoder.ts
|
|
@@ -21026,10 +21084,10 @@ async function createH264Decoder() {
|
|
|
21026
21084
|
}
|
|
21027
21085
|
|
|
21028
21086
|
// screen/wasm.ts
|
|
21029
|
-
var SCREEN_WASM_URL = "supra-client-screen.wasm?v=0.0.
|
|
21087
|
+
var SCREEN_WASM_URL = "supra-client-screen.wasm?v=1.0.0-mzscreengeometry.449";
|
|
21030
21088
|
async function startWasmScreen(options) {
|
|
21031
21089
|
options = options != null ? options : parseQueryOptions();
|
|
21032
|
-
initWorkerFrameConnection();
|
|
21090
|
+
initWorkerFrameConnection(options.netInWorker === true);
|
|
21033
21091
|
await initSamsungWasmTCP();
|
|
21034
21092
|
await initSamsungWasmDecoder(options);
|
|
21035
21093
|
await initH264Decoder();
|
|
@@ -21076,6 +21134,14 @@ function createScreenControl(initialPreferences) {
|
|
|
21076
21134
|
} catch {
|
|
21077
21135
|
return null;
|
|
21078
21136
|
}
|
|
21137
|
+
},
|
|
21138
|
+
stop() {
|
|
21139
|
+
var _a;
|
|
21140
|
+
if (typeof window === "undefined" || !((_a = window.__supra) == null ? void 0 : _a.stopScreen)) {
|
|
21141
|
+
return false;
|
|
21142
|
+
}
|
|
21143
|
+
window.__supra.stopScreen();
|
|
21144
|
+
return true;
|
|
21079
21145
|
}
|
|
21080
21146
|
};
|
|
21081
21147
|
}
|