querysub 0.2.0
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/.dependency-cruiser.js +304 -0
- package/.eslintrc.js +51 -0
- package/.github/copilot-instructions.md +1 -0
- package/.vscode/settings.json +25 -0
- package/bin/deploy.js +4 -0
- package/bin/function.js +4 -0
- package/bin/server.js +4 -0
- package/costsBenefits.txt +112 -0
- package/deploy.ts +3 -0
- package/inject.ts +1 -0
- package/package.json +60 -0
- package/prompts.txt +54 -0
- package/spec.txt +820 -0
- package/src/-a-archives/archiveCache.ts +913 -0
- package/src/-a-archives/archives.ts +148 -0
- package/src/-a-archives/archivesBackBlaze.ts +792 -0
- package/src/-a-archives/archivesDisk.ts +418 -0
- package/src/-a-archives/copyLocalToBackblaze.ts +24 -0
- package/src/-a-auth/certs.ts +517 -0
- package/src/-a-auth/der.ts +122 -0
- package/src/-a-auth/ed25519.ts +1015 -0
- package/src/-a-auth/node-forge-ed25519.d.ts +17 -0
- package/src/-b-authorities/dnsAuthority.ts +203 -0
- package/src/-b-authorities/emailAuthority.ts +57 -0
- package/src/-c-identity/IdentityController.ts +200 -0
- package/src/-d-trust/NetworkTrust2.ts +150 -0
- package/src/-e-certs/EdgeCertController.ts +288 -0
- package/src/-e-certs/certAuthority.ts +192 -0
- package/src/-f-node-discovery/NodeDiscovery.ts +543 -0
- package/src/-g-core-values/NodeCapabilities.ts +134 -0
- package/src/-g-core-values/oneTimeForward.ts +91 -0
- package/src/-h-path-value-serialize/PathValueSerializer.ts +769 -0
- package/src/-h-path-value-serialize/stringSerializer.ts +176 -0
- package/src/0-path-value-core/LoggingClient.tsx +24 -0
- package/src/0-path-value-core/NodePathAuthorities.ts +978 -0
- package/src/0-path-value-core/PathController.ts +1 -0
- package/src/0-path-value-core/PathValueCommitter.ts +565 -0
- package/src/0-path-value-core/PathValueController.ts +231 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +154 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +820 -0
- package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +180 -0
- package/src/0-path-value-core/debugLogs.ts +90 -0
- package/src/0-path-value-core/pathValueArchives.ts +483 -0
- package/src/0-path-value-core/pathValueCore.ts +2217 -0
- package/src/1-path-client/RemoteWatcher.ts +558 -0
- package/src/1-path-client/pathValueClientWatcher.ts +702 -0
- package/src/2-proxy/PathValueProxyWatcher.ts +1857 -0
- package/src/2-proxy/archiveMoveHarness.ts +376 -0
- package/src/2-proxy/garbageCollection.ts +753 -0
- package/src/2-proxy/pathDatabaseProxyBase.ts +37 -0
- package/src/2-proxy/pathValueProxy.ts +139 -0
- package/src/2-proxy/schema2.ts +518 -0
- package/src/3-path-functions/PathFunctionHelpers.ts +129 -0
- package/src/3-path-functions/PathFunctionRunner.ts +619 -0
- package/src/3-path-functions/PathFunctionRunnerMain.ts +67 -0
- package/src/3-path-functions/deployBlock.ts +10 -0
- package/src/3-path-functions/deployCheck.ts +7 -0
- package/src/3-path-functions/deployMain.ts +160 -0
- package/src/3-path-functions/pathFunctionLoader.ts +282 -0
- package/src/3-path-functions/syncSchema.ts +475 -0
- package/src/3-path-functions/tests/functionsTest.ts +135 -0
- package/src/3-path-functions/tests/rejectTest.ts +77 -0
- package/src/4-dom/css.tsx +29 -0
- package/src/4-dom/cssTypes.d.ts +212 -0
- package/src/4-dom/qreact.tsx +2322 -0
- package/src/4-dom/qreactTest.tsx +417 -0
- package/src/4-querysub/Querysub.ts +877 -0
- package/src/4-querysub/QuerysubController.ts +620 -0
- package/src/4-querysub/copyEvent.ts +0 -0
- package/src/4-querysub/permissions.ts +289 -0
- package/src/4-querysub/permissionsShared.ts +1 -0
- package/src/4-querysub/querysubPrediction.ts +525 -0
- package/src/5-diagnostics/FullscreenModal.tsx +67 -0
- package/src/5-diagnostics/GenericFormat.tsx +165 -0
- package/src/5-diagnostics/Modal.tsx +79 -0
- package/src/5-diagnostics/Table.tsx +183 -0
- package/src/5-diagnostics/TimeGrouper.tsx +114 -0
- package/src/5-diagnostics/diskValueAudit.ts +216 -0
- package/src/5-diagnostics/memoryValueAudit.ts +442 -0
- package/src/5-diagnostics/nodeMetadata.ts +135 -0
- package/src/5-diagnostics/qreactDebug.tsx +309 -0
- package/src/5-diagnostics/shared.ts +26 -0
- package/src/5-diagnostics/synchronousLagTracking.ts +47 -0
- package/src/TestController.ts +35 -0
- package/src/allowclient.flag +0 -0
- package/src/bits.ts +86 -0
- package/src/buffers.ts +69 -0
- package/src/config.ts +53 -0
- package/src/config2.ts +48 -0
- package/src/diagnostics/ActionsHistory.ts +56 -0
- package/src/diagnostics/NodeViewer.tsx +503 -0
- package/src/diagnostics/SizeLimiter.ts +62 -0
- package/src/diagnostics/TimeDebug.tsx +18 -0
- package/src/diagnostics/benchmark.ts +139 -0
- package/src/diagnostics/errorLogs/ErrorLogController.ts +515 -0
- package/src/diagnostics/errorLogs/ErrorLogCore.ts +274 -0
- package/src/diagnostics/errorLogs/LogClassifiers.tsx +302 -0
- package/src/diagnostics/errorLogs/LogFilterUI.tsx +84 -0
- package/src/diagnostics/errorLogs/LogNotify.tsx +101 -0
- package/src/diagnostics/errorLogs/LogTimeSelector.tsx +724 -0
- package/src/diagnostics/errorLogs/LogViewer.tsx +757 -0
- package/src/diagnostics/errorLogs/hookErrors.ts +60 -0
- package/src/diagnostics/errorLogs/logFiltering.tsx +149 -0
- package/src/diagnostics/heapTag.ts +13 -0
- package/src/diagnostics/listenOnDebugger.ts +77 -0
- package/src/diagnostics/logs/DiskLoggerPage.tsx +572 -0
- package/src/diagnostics/logs/ObjectDisplay.tsx +165 -0
- package/src/diagnostics/logs/ansiFormat.ts +108 -0
- package/src/diagnostics/logs/diskLogGlobalContext.ts +38 -0
- package/src/diagnostics/logs/diskLogger.ts +305 -0
- package/src/diagnostics/logs/diskShimConsoleLogs.ts +32 -0
- package/src/diagnostics/logs/injectFileLocationToConsole.ts +50 -0
- package/src/diagnostics/logs/logGitHashes.ts +30 -0
- package/src/diagnostics/managementPages.tsx +289 -0
- package/src/diagnostics/periodic.ts +89 -0
- package/src/diagnostics/runSaturationTest.ts +416 -0
- package/src/diagnostics/satSchema.ts +64 -0
- package/src/diagnostics/trackResources.ts +82 -0
- package/src/diagnostics/watchdog.ts +55 -0
- package/src/errors.ts +132 -0
- package/src/forceProduction.ts +3 -0
- package/src/fs.ts +72 -0
- package/src/heapDumps.ts +666 -0
- package/src/https.ts +2 -0
- package/src/inject.ts +1 -0
- package/src/library-components/ATag.tsx +84 -0
- package/src/library-components/Button.tsx +344 -0
- package/src/library-components/ButtonSelector.tsx +64 -0
- package/src/library-components/DropdownCustom.tsx +151 -0
- package/src/library-components/DropdownSelector.tsx +32 -0
- package/src/library-components/Input.tsx +334 -0
- package/src/library-components/InputLabel.tsx +198 -0
- package/src/library-components/InputPicker.tsx +125 -0
- package/src/library-components/LazyComponent.tsx +62 -0
- package/src/library-components/MeasureHeightCSS.tsx +48 -0
- package/src/library-components/MeasuredDiv.tsx +47 -0
- package/src/library-components/ShowMore.tsx +51 -0
- package/src/library-components/SyncedController.ts +171 -0
- package/src/library-components/TimeRangeSelector.tsx +407 -0
- package/src/library-components/URLParam.ts +263 -0
- package/src/library-components/colors.tsx +14 -0
- package/src/library-components/drag.ts +114 -0
- package/src/library-components/icons.tsx +692 -0
- package/src/library-components/niceStringify.ts +50 -0
- package/src/library-components/renderToString.ts +52 -0
- package/src/misc/PromiseRace.ts +101 -0
- package/src/misc/color.ts +30 -0
- package/src/misc/getParentProcessId.cs +53 -0
- package/src/misc/getParentProcessId.ts +53 -0
- package/src/misc/hash.ts +83 -0
- package/src/misc/ipPong.js +13 -0
- package/src/misc/networking.ts +2 -0
- package/src/misc/random.ts +45 -0
- package/src/misc.ts +19 -0
- package/src/noserverhotreload.flag +0 -0
- package/src/path.ts +226 -0
- package/src/persistentLocalStore.ts +37 -0
- package/src/promise.ts +15 -0
- package/src/server.ts +73 -0
- package/src/src.d.ts +1 -0
- package/src/test/heapProcess.ts +36 -0
- package/src/test/mongoSatTest.tsx +55 -0
- package/src/test/satTest.ts +193 -0
- package/src/test/test.tsx +552 -0
- package/src/zip.ts +92 -0
- package/src/zipThreaded.ts +106 -0
- package/src/zipThreadedWorker.js +19 -0
- package/tsconfig.json +27 -0
- package/yarnSpec.txt +56 -0
package/src/buffers.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { canHaveChildren } from "socket-function/src/types";
|
|
2
|
+
|
|
3
|
+
export type ArrayBufferViewTypes = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | BigUint64Array | BigInt64Array | Float64Array | Float32Array | Uint8ClampedArray;
|
|
4
|
+
export type BufferType = ArrayBuffer | SharedArrayBuffer | ArrayBufferViewTypes;
|
|
5
|
+
|
|
6
|
+
export function cloneBuffer(data: Buffer): Buffer {
|
|
7
|
+
let newBuffer = Buffer.alloc(data.length);
|
|
8
|
+
data.copy(newBuffer);
|
|
9
|
+
return newBuffer;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export function asBuffer(data: BufferType): Buffer {
|
|
14
|
+
if (!data) return data;
|
|
15
|
+
if (data instanceof Buffer) return data;
|
|
16
|
+
if (!canHaveChildren(data)) return data as any;
|
|
17
|
+
if (!("buffer" in data) || !("byteOffset" in data) || !("byteLength" in data)) {
|
|
18
|
+
return Buffer.from(data);
|
|
19
|
+
}
|
|
20
|
+
let result = Buffer.from((data as any).buffer, (data as any).byteOffset, (data as any).byteLength);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
export function asFloat64(data: Buffer): Float64Array {
|
|
24
|
+
if (data.length % 8 !== 0) {
|
|
25
|
+
throw new Error(`Data is not 8 count aligned, received length of ${data.length}`);
|
|
26
|
+
}
|
|
27
|
+
if (data.byteOffset % 8 !== 0) {
|
|
28
|
+
throw new Error(`Data is not 8 byte aligned, received offset of ${data.byteOffset}`);
|
|
29
|
+
}
|
|
30
|
+
return new Float64Array(data.buffer, data.byteOffset, Math.floor(data.length / 8));
|
|
31
|
+
}
|
|
32
|
+
export function asFloat32(data: Buffer): Float32Array {
|
|
33
|
+
if (data.length % 4 !== 0) {
|
|
34
|
+
throw new Error(`Data is not 4 byte aligned, received length of ${data.length}`);
|
|
35
|
+
}
|
|
36
|
+
if (data.byteOffset % 4 !== 0) {
|
|
37
|
+
throw new Error(`Data is not 4 byte aligned, received offset of ${data.byteOffset}`);
|
|
38
|
+
}
|
|
39
|
+
return new Float32Array(data.buffer, data.byteOffset, Math.floor(data.length / 4));
|
|
40
|
+
}
|
|
41
|
+
export function asUint32(data: Buffer): Uint32Array {
|
|
42
|
+
if (data.length % 4 !== 0) {
|
|
43
|
+
throw new Error(`Data is not 4 byte aligned, received length of ${data.length}`);
|
|
44
|
+
}
|
|
45
|
+
if (data.byteOffset % 4 !== 0) {
|
|
46
|
+
throw new Error(`Data is not 4 byte aligned, received offset of ${data.byteOffset}`);
|
|
47
|
+
}
|
|
48
|
+
return new Uint32Array(data.buffer, data.byteOffset, Math.floor(data.length / 4));
|
|
49
|
+
}
|
|
50
|
+
export function asInt32(data: Buffer): Int32Array {
|
|
51
|
+
if (data.length % 4 !== 0) {
|
|
52
|
+
throw new Error(`Data is not 4 byte aligned, received length of ${data.length}`);
|
|
53
|
+
}
|
|
54
|
+
if (data.byteOffset % 4 !== 0) {
|
|
55
|
+
throw new Error(`Data is not 4 byte aligned, received offset of ${data.byteOffset}`);
|
|
56
|
+
}
|
|
57
|
+
return new Int32Array(data.buffer, data.byteOffset, Math.floor(data.length / 4));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
export function asFloat64MaybeCopy(data: Buffer) {
|
|
62
|
+
if (data.length % 8 !== 0) {
|
|
63
|
+
throw new Error(`Data is not 8 count aligned, received length of ${data.length}`);
|
|
64
|
+
}
|
|
65
|
+
if (data.byteOffset % 8 !== 0) {
|
|
66
|
+
return asFloat64(cloneBuffer(data));
|
|
67
|
+
}
|
|
68
|
+
return new Float64Array(data.buffer, data.byteOffset, Math.floor(data.length / 8));
|
|
69
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isNode, isNodeTrue } from "socket-function/src/misc";
|
|
2
|
+
import yargs from "yargs";
|
|
3
|
+
import debugbreak from "debugbreak";
|
|
4
|
+
|
|
5
|
+
export const serverPort = 11748;
|
|
6
|
+
|
|
7
|
+
let yargObj = isNodeTrue() && yargs(process.argv)
|
|
8
|
+
.option("nonetwork", { type: "boolean", desc: `Disables all network requirements. Reduces security, as this means we cannot use real certificates.` })
|
|
9
|
+
.option("domain", { type: "string", desc: `Sets the domain` })
|
|
10
|
+
.option("client", { type: "boolean", desc: `Drops permissions, acting as an unauthenticated node` })
|
|
11
|
+
.option("authority", { type: "string", desc: `Defines the base paths we are an authority on (the domain is prepended to them). Either a file path to a JSON(AuthorityPath[]), or a base64 representation of the JSON(AuthorityPath[]).` })
|
|
12
|
+
.option("debugbreak", { type: "boolean", desc: "Break and show a popup when there are fatal errors" })
|
|
13
|
+
.option("nobreak", { type: "boolean", desc: "Do not break on errors. Safer to set this than to just not set debugbreak, as some places might break without checking debugbreak, but nobreak works at a level where it is always used." })
|
|
14
|
+
.option("public", { type: "boolean", desc: "Expose on public ports." })
|
|
15
|
+
.argv || {}
|
|
16
|
+
;
|
|
17
|
+
|
|
18
|
+
export function isNoNetwork() {
|
|
19
|
+
return yargObj.nonetwork;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getDomain() {
|
|
23
|
+
if (!isNode()) {
|
|
24
|
+
return location.hostname.split(".").slice(-2).join(".");
|
|
25
|
+
}
|
|
26
|
+
return yargObj.domain || "querysub.com";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function baseIsClient() {
|
|
30
|
+
return !isNode() || yargObj.client;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function devDebugbreak() {
|
|
34
|
+
if (!isNode()) {
|
|
35
|
+
debugger;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!yargObj.debugbreak) return;
|
|
39
|
+
debugbreak(2);
|
|
40
|
+
debugger;
|
|
41
|
+
}
|
|
42
|
+
export function isDevDebugbreak() {
|
|
43
|
+
return yargObj.debugbreak;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
export function authorityRaw() {
|
|
48
|
+
return yargObj.authority;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isPublic() {
|
|
52
|
+
return !!yargObj.public;
|
|
53
|
+
}
|
package/src/config2.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { deepCloneJSON, isNode } from "socket-function/src/misc";
|
|
2
|
+
import { hasArchivesPermissions } from "./-a-archives/archives";
|
|
3
|
+
import { authorityRaw, baseIsClient, getDomain } from "./config";
|
|
4
|
+
import { JSONLACKS } from "socket-function/src/JSONLACKS/JSONLACKS";
|
|
5
|
+
import { AuthorityPath } from "./0-path-value-core/NodePathAuthorities";
|
|
6
|
+
import { rootPathStr, prependToPathStr } from "./path";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
|
|
9
|
+
let isInCall = false;
|
|
10
|
+
export function isClient() {
|
|
11
|
+
isInCall = true;
|
|
12
|
+
try {
|
|
13
|
+
return !isNode() || baseIsClient() || !isInCall && !hasArchivesPermissions();
|
|
14
|
+
} finally {
|
|
15
|
+
isInCall = false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isServer() {
|
|
20
|
+
return !isClient();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getOurAuthorities() {
|
|
24
|
+
let authorities: AuthorityPath[] = [];
|
|
25
|
+
let authority = authorityRaw();
|
|
26
|
+
|
|
27
|
+
let baseAuthorityPaths: AuthorityPath[] = [{
|
|
28
|
+
pathPrefix: rootPathStr
|
|
29
|
+
}];
|
|
30
|
+
if (authority) {
|
|
31
|
+
if (fs.existsSync(authority)) {
|
|
32
|
+
baseAuthorityPaths = JSONLACKS.parse(fs.readFileSync(authority, "utf8"));
|
|
33
|
+
} else {
|
|
34
|
+
baseAuthorityPaths = JSONLACKS.parse(Buffer.from(authority, "base64").toString("utf8"));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let domain = getDomain();
|
|
39
|
+
for (let base of baseAuthorityPaths) {
|
|
40
|
+
base = deepCloneJSON(base);
|
|
41
|
+
base.pathPrefix = prependToPathStr(base.pathPrefix, domain);
|
|
42
|
+
if (base.excludedChildren) {
|
|
43
|
+
base.excludedChildren = base.excludedChildren.map(x => prependToPathStr(x, domain));
|
|
44
|
+
}
|
|
45
|
+
authorities.push(base);
|
|
46
|
+
}
|
|
47
|
+
return authorities;
|
|
48
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { cache } from "socket-function/src/caching";
|
|
2
|
+
import { blue, green, red } from "socket-function/src/formatting/logColors";
|
|
3
|
+
import { getStorageDir, getSubFolder } from "../fs";
|
|
4
|
+
import { ClientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
5
|
+
import { PathValueProxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
6
|
+
import { debugPathValuePath, PathValue, PathWatcherCallback, ReadLock, WatchConfig, WriteState } from "../0-path-value-core/pathValueCore";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import { measureWrap } from "socket-function/src/profiling/measure";
|
|
9
|
+
import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
function group(expanded: boolean) {
|
|
14
|
+
return expanded ? console.group : console.groupCollapsed;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let epoch = Date.now();
|
|
18
|
+
export class ActionsHistory {
|
|
19
|
+
public static LOG_ACTION_HISTORY = "";
|
|
20
|
+
public static OnNewWatches(config: { newPathsWatched: Set<string>; newParentsWatched: Set<string>; debugName?: string; authorityId: string; }) {
|
|
21
|
+
if (ClientWatcher.DEBUG_READS) {
|
|
22
|
+
let now = Date.now();
|
|
23
|
+
group(ClientWatcher.DEBUG_READS_EXPANDED)(`(${now - epoch}ms) New watch count ${config.newPathsWatched.size} (${config.newParentsWatched.size} parent watches) for ${JSON.stringify(config.debugName || "anonymous")}. Authority ${config.authorityId}, time ${now}`);
|
|
24
|
+
for (let path of config.newParentsWatched) {
|
|
25
|
+
console.log(blue(path));
|
|
26
|
+
}
|
|
27
|
+
for (let path of config.newPathsWatched) {
|
|
28
|
+
console.log(path);
|
|
29
|
+
}
|
|
30
|
+
console.groupEnd();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
public static OnRead(values: PathValue[]) {
|
|
34
|
+
if (ClientWatcher.DEBUG_READS && values.length > 0) {
|
|
35
|
+
let now = Date.now();
|
|
36
|
+
let oldest = Math.min(...values.map(x => x.time.time).filter(x => x), now);
|
|
37
|
+
group(ClientWatcher.DEBUG_READS_EXPANDED)(`(${now - epoch}ms, ${now}) Read count ${values.length}, ${(Date.now() - oldest).toFixed()}ms old`);
|
|
38
|
+
for (let value of values) {
|
|
39
|
+
console.log(blue(debugPathValuePath(value)), "===", pathValueSerializer.getPathValue(value), `(${value.valid ? "valid" : "invalid"})`);
|
|
40
|
+
}
|
|
41
|
+
console.groupEnd();
|
|
42
|
+
}
|
|
43
|
+
if (!ActionsHistory.LOG_ACTION_HISTORY) return;
|
|
44
|
+
}
|
|
45
|
+
public static OnWrite(values: PathValue[]) {
|
|
46
|
+
if (ClientWatcher.DEBUG_WRITES) {
|
|
47
|
+
let now = Date.now();
|
|
48
|
+
group(ClientWatcher.DEBUG_WRITES_EXPANDED)(green(`(${now - epoch}ms, ${now}) Committing writes ${values.length}`));
|
|
49
|
+
for (let value of values) {
|
|
50
|
+
console.log(green(debugPathValuePath(value)), "=", pathValueSerializer.getPathValue(value), `(${value.valid ? "valid" : "invalid"})`);
|
|
51
|
+
}
|
|
52
|
+
console.groupEnd();
|
|
53
|
+
}
|
|
54
|
+
if (!ActionsHistory.LOG_ACTION_HISTORY) return;
|
|
55
|
+
}
|
|
56
|
+
}
|