@swf2es/desktop 0.1.16 → 0.1.17
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/README.md +41 -1
- package/dist/main/air.d.ts +3 -3
- package/dist/main/air.d.ts.map +1 -1
- package/dist/main/air.js +17 -8
- package/dist/main/air.js.map +1 -1
- package/dist/main/case-paths.d.ts +12 -0
- package/dist/main/case-paths.d.ts.map +1 -0
- package/dist/main/case-paths.js +84 -0
- package/dist/main/case-paths.js.map +1 -0
- package/dist/main/connections.d.ts +20 -1
- package/dist/main/connections.d.ts.map +1 -1
- package/dist/main/connections.js +71 -8
- package/dist/main/connections.js.map +1 -1
- package/dist/main/main.js +80 -14
- package/dist/main/main.js.map +1 -1
- package/dist/main/network.d.ts +10 -0
- package/dist/main/network.d.ts.map +1 -1
- package/dist/main/network.js +111 -35
- package/dist/main/network.js.map +1 -1
- package/dist/main/proxy.d.ts +48 -0
- package/dist/main/proxy.d.ts.map +1 -0
- package/dist/main/proxy.js +402 -0
- package/dist/main/proxy.js.map +1 -0
- package/dist/main/sandbox.d.ts.map +1 -1
- package/dist/main/sandbox.js +2 -1
- package/dist/main/sandbox.js.map +1 -1
- package/dist/main/settings.d.ts +2 -0
- package/dist/main/settings.d.ts.map +1 -1
- package/dist/main/settings.js +4 -0
- package/dist/main/settings.js.map +1 -1
- package/dist/main/sockets.d.ts +4 -2
- package/dist/main/sockets.d.ts.map +1 -1
- package/dist/main/sockets.js +6 -4
- package/dist/main/sockets.js.map +1 -1
- package/dist/main/websocket-connections.d.ts +11 -0
- package/dist/main/websocket-connections.d.ts.map +1 -1
- package/dist/main/websocket-connections.js +72 -4
- package/dist/main/websocket-connections.js.map +1 -1
- package/dist/main/websockets.d.ts +3 -2
- package/dist/main/websockets.d.ts.map +1 -1
- package/dist/main/websockets.js +4 -3
- package/dist/main/websockets.js.map +1 -1
- package/package.json +7 -7
- package/src/main/air.ts +18 -8
- package/src/main/case-paths.ts +97 -0
- package/src/main/connections.ts +90 -8
- package/src/main/main.ts +105 -20
- package/src/main/network.ts +140 -37
- package/src/main/proxy.ts +497 -0
- package/src/main/sandbox.ts +2 -1
- package/src/main/settings.ts +5 -0
- package/src/main/sockets.ts +7 -4
- package/src/main/websocket-connections.ts +84 -4
- package/src/main/websockets.ts +4 -2
package/README.md
CHANGED
|
@@ -59,7 +59,9 @@ fetch-electron` does so ahead, for the tests.
|
|
|
59
59
|
MPL-2.0) and playerglobal that ship with the player, with nothing to set
|
|
60
60
|
up. File › Choose playerglobal.abc… plays on another playerglobal, such
|
|
61
61
|
as Flash Player's, in place of the app's own; the app keeps its path in
|
|
62
|
-
`settings.json` in Electron's user data directory
|
|
62
|
+
`settings.json` in Electron's user data directory, across updates of the
|
|
63
|
+
app, and says so on stderr at each start. File › Use the App's
|
|
64
|
+
playerglobal goes back to the app's own.
|
|
63
65
|
- **Trace.** `--trace` prints what the page logs, a SWF's `trace()` among
|
|
64
66
|
it, to the terminal: trace lines to stdout, warnings and errors to stderr.
|
|
65
67
|
- **Network log.** `--log-network` prints each of the SWF's requests to
|
|
@@ -85,6 +87,31 @@ fetch-electron` does so ahead, for the tests.
|
|
|
85
87
|
stderr, each time it starts with it, which hosts go unverified. The page
|
|
86
88
|
itself has no network (the main process makes a SWF's requests and
|
|
87
89
|
connections), so nothing but those is affected.
|
|
90
|
+
- **Proxy.** `--proxy=socks5://host:1080` sends everything the SWF does
|
|
91
|
+
on the network through a SOCKS5 proxy (RFC 1928; `socks5h://` is the
|
|
92
|
+
same), and `--proxy=http://host:3128` through an HTTP proxy, by a
|
|
93
|
+
`CONNECT` tunnel for each connection, plain http too: its http and https
|
|
94
|
+
requests, the policy files they need, its sockets with their socket
|
|
95
|
+
policies, and an AIR application's WebSockets. A username and password
|
|
96
|
+
go in the URL (`socks5://user:pass@host:1080`, %-escaped where they need
|
|
97
|
+
it): RFC 1929's for SOCKS5, `Proxy-Authorization: Basic` for HTTP. They
|
|
98
|
+
come from the command line alone, and are never kept nor said: the app
|
|
99
|
+
says on stderr, as it starts, which proxy it uses, by its host and port.
|
|
100
|
+
TLS is the app's own, over the tunnel, so certificates are verified, or
|
|
101
|
+
not for the hosts `--ignore-certificate-errors` names, as without a
|
|
102
|
+
proxy. Whether a host is on this machine or the local network (below)
|
|
103
|
+
is still judged by this machine's DNS, and the proxy is then asked for
|
|
104
|
+
the address judged, not the name, so it reaches nothing the judgement
|
|
105
|
+
did not; a socket or WebSocket nothing judged (a local SWF's, an AIR
|
|
106
|
+
application's) goes by its name, for the proxy to resolve. A proxy that
|
|
107
|
+
is not there, refuses the credentials or refuses a connection is, to
|
|
108
|
+
the SWF, a server that is not there (IOErrorEvent, a socket's #2031), and
|
|
109
|
+
a line on stderr says why: `swf2es: not loading http://…: the proxy
|
|
110
|
+
socks5://127.0.0.1:1080 refused: connection refused (SOCKS reply 5)`.
|
|
111
|
+
`--log-network`'s lines name the target, and end in `via proxy`. A
|
|
112
|
+
second start of the app with another `--proxy` opens nothing in the
|
|
113
|
+
first. An HTTP proxy that allows `CONNECT` only to port 443, as Squid
|
|
114
|
+
does by default, refuses plain http and sockets on other ports.
|
|
88
115
|
- **Sandbox.** A SWF plays in the sandbox Flash Player gave a local SWF,
|
|
89
116
|
by its FileAttributes' UseNetwork bit. Without it,
|
|
90
117
|
local-with-filesystem: it reads the files in its own directory and below
|
|
@@ -129,6 +156,9 @@ fetch-electron` does so ahead, for the tests.
|
|
|
129
156
|
in AIR's application sandbox: it is played from `app:/`, reads any
|
|
130
157
|
local file through File, FileStream and its `app:`, `app-storage:` and
|
|
131
158
|
`file:` URLs, writes any file but through its `app:` URLs, as AIR does,
|
|
159
|
+
makes temporary files and directories (`File.createTempFile()`,
|
|
160
|
+
`createTempDirectory()`) in the system's temporary directory, its
|
|
161
|
+
`File.cacheDirectory`, which it leaves for the application to delete,
|
|
132
162
|
and reaches the network, sockets and WebSockets (`air.net.WebSocket`)
|
|
133
163
|
without Flash's policy files or a prompt, as an installed application
|
|
134
164
|
does. Its storage directory is
|
|
@@ -140,6 +170,16 @@ fetch-electron` does so ahead, for the tests.
|
|
|
140
170
|
opened with the app runs the application too, from its own directory
|
|
141
171
|
with no arguments; the app asks first, once, until the descriptor
|
|
142
172
|
leaves the recent list.
|
|
173
|
+
- **Case in names.** Windows and macOS find a file whatever case its name
|
|
174
|
+
is given in, so content made there names files as it likes. On Linux, a
|
|
175
|
+
path a SWF or an AIR application names that is not there exactly is
|
|
176
|
+
found the same way: each missing name is the one in its directory equal
|
|
177
|
+
to it ignoring case (both as NFC, lowercased, which is close to how NTFS
|
|
178
|
+
and APFS fold case). `Maps/Town.swf` reads `maps/town.swf`; a file
|
|
179
|
+
written into `Saves/` goes into `saves/` where that is there, under the
|
|
180
|
+
name it was given. Where a directory holds two names that differ only in
|
|
181
|
+
case, neither is taken, and stderr says so once. A sandbox reaches no
|
|
182
|
+
more than before: what it lets a SWF read is judged on the file found.
|
|
143
183
|
- **File dialogs** requested by AS2 or AS3 FileReference use native open
|
|
144
184
|
and save dialogs after a click or key. Uploads and downloads use the
|
|
145
185
|
same network permissions as other data requests.
|
package/dist/main/air.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare function airLaunch(command: AirCommand, currentDirectory: string,
|
|
|
25
25
|
height: number | null;
|
|
26
26
|
};
|
|
27
27
|
/** What is at `path`, as File reads it; null where nothing is. */
|
|
28
|
-
export declare function statOf(
|
|
28
|
+
export declare function statOf(asked: string): AirFileStat | null;
|
|
29
29
|
/** The names in the directory at `path`; null where it is none. */
|
|
30
30
|
export declare function listOf(path: string): string[] | null;
|
|
31
31
|
/** The bytes of the file at `path`, as FileStream's open reads them at once; null where none can be read. */
|
|
@@ -61,11 +61,11 @@ export declare class EncryptedItems {
|
|
|
61
61
|
* `length` long, made with its directories where it is not: FileStream's
|
|
62
62
|
* writes. False where it cannot be written.
|
|
63
63
|
*/
|
|
64
|
-
export declare function writeOf(
|
|
64
|
+
export declare function writeOf(asked: string, bytes: Uint8Array, offset: number, length: number): boolean;
|
|
65
65
|
/** Makes the directory at `path` and those it is in; false where it cannot. */
|
|
66
66
|
export declare function createDirectoryOf(path: string): boolean;
|
|
67
67
|
/** Removes the file or directory at `path`, with all in it; false where it cannot. */
|
|
68
68
|
export declare function removeOf(path: string): boolean;
|
|
69
69
|
/** Moves what is at `from` to `to`, its directories made; false where it cannot. */
|
|
70
|
-
export declare function moveOf(
|
|
70
|
+
export declare function moveOf(askedFrom: string, askedTo: string): boolean;
|
|
71
71
|
//# sourceMappingURL=air.d.ts.map
|
package/dist/main/air.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"air.d.ts","sourceRoot":"","sources":["../../src/main/air.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"air.d.ts","sourceRoot":"","sources":["../../src/main/air.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG/D,wGAAwG;AACxG,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAezE;AAED,yGAAyG;AACzG,wBAAgB,SAAS,CACvB,OAAO,EAAE,UAAU,EACnB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,oGAAoG;IACpG,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CA2BA;AAED,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAiBxD;AAED,mEAAmE;AACnE,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAMpD;AAED,6GAA6G;AAC7G,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAMtD;AAED,sGAAsG;AACtG,MAAM,WAAW,MAAM;IACrB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAEhD,YAAY,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAI9C;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAEnC;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAGzC;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIzB;IAED,KAAK,IAAI,IAAI,CAGZ;IAED,sGAAsG;IACtG,OAAO,CAAC,IAAI;IAwBZ,OAAO,CAAC,IAAI;CAcb;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAcjG;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAsBlE"}
|
package/dist/main/air.js
CHANGED
|
@@ -7,6 +7,7 @@ import { closeSync, cpSync, ftruncateSync, lstatSync, mkdirSync, openSync, readd
|
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
9
9
|
import { readAirDescriptor } from "@swf2es/format";
|
|
10
|
+
import { resolveCase } from "./case-paths.js";
|
|
10
11
|
/**
|
|
11
12
|
* The AIR application `argv` names, from `cwd`: a descriptor (`.xml`), the
|
|
12
13
|
* directory its content is under if one follows, and what follows `--`.
|
|
@@ -35,7 +36,7 @@ export function airLaunch(command, currentDirectory, userData, directories) {
|
|
|
35
36
|
const applicationStorage = join(userData, "air", descriptor.id.replace(/[^\w.-]/g, "_"), "Local Store");
|
|
36
37
|
mkdirSync(applicationStorage, { recursive: true });
|
|
37
38
|
return {
|
|
38
|
-
content: resolve(application, ...descriptor.content.split("/")),
|
|
39
|
+
content: resolveCase(resolve(application, ...descriptor.content.split("/"))),
|
|
39
40
|
relative: descriptor.content,
|
|
40
41
|
launch: {
|
|
41
42
|
descriptor: xml,
|
|
@@ -51,7 +52,8 @@ export function airLaunch(command, currentDirectory, userData, directories) {
|
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
/** What is at `path`, as File reads it; null where nothing is. */
|
|
54
|
-
export function statOf(
|
|
55
|
+
export function statOf(asked) {
|
|
56
|
+
const path = resolveCase(asked);
|
|
55
57
|
try {
|
|
56
58
|
const s = statSync(path);
|
|
57
59
|
const link = lstatSync(path).isSymbolicLink();
|
|
@@ -72,7 +74,7 @@ export function statOf(path) {
|
|
|
72
74
|
/** The names in the directory at `path`; null where it is none. */
|
|
73
75
|
export function listOf(path) {
|
|
74
76
|
try {
|
|
75
|
-
return readdirSync(path);
|
|
77
|
+
return readdirSync(resolveCase(path));
|
|
76
78
|
}
|
|
77
79
|
catch {
|
|
78
80
|
return null;
|
|
@@ -81,7 +83,7 @@ export function listOf(path) {
|
|
|
81
83
|
/** The bytes of the file at `path`, as FileStream's open reads them at once; null where none can be read. */
|
|
82
84
|
export function readOf(path) {
|
|
83
85
|
try {
|
|
84
|
-
return new Uint8Array(readFileSync(path));
|
|
86
|
+
return new Uint8Array(readFileSync(resolveCase(path)));
|
|
85
87
|
}
|
|
86
88
|
catch {
|
|
87
89
|
return null;
|
|
@@ -164,7 +166,8 @@ export class EncryptedItems {
|
|
|
164
166
|
* `length` long, made with its directories where it is not: FileStream's
|
|
165
167
|
* writes. False where it cannot be written.
|
|
166
168
|
*/
|
|
167
|
-
export function writeOf(
|
|
169
|
+
export function writeOf(asked, bytes, offset, length) {
|
|
170
|
+
const path = resolveCase(asked);
|
|
168
171
|
return attempt(() => {
|
|
169
172
|
mkdirSync(dirname(path), { recursive: true });
|
|
170
173
|
// "a+" would only append; "r+" needs the file there, which "a" makes without emptying it.
|
|
@@ -181,14 +184,20 @@ export function writeOf(path, bytes, offset, length) {
|
|
|
181
184
|
}
|
|
182
185
|
/** Makes the directory at `path` and those it is in; false where it cannot. */
|
|
183
186
|
export function createDirectoryOf(path) {
|
|
184
|
-
return attempt(() => mkdirSync(path, { recursive: true }));
|
|
187
|
+
return attempt(() => mkdirSync(resolveCase(path), { recursive: true }));
|
|
185
188
|
}
|
|
186
189
|
/** Removes the file or directory at `path`, with all in it; false where it cannot. */
|
|
187
190
|
export function removeOf(path) {
|
|
188
|
-
return attempt(() => rmSync(path, { recursive: true }));
|
|
191
|
+
return attempt(() => rmSync(resolveCase(path), { recursive: true }));
|
|
189
192
|
}
|
|
190
193
|
/** Moves what is at `from` to `to`, its directories made; false where it cannot. */
|
|
191
|
-
export function moveOf(
|
|
194
|
+
export function moveOf(askedFrom, askedTo) {
|
|
195
|
+
const from = resolveCase(askedFrom);
|
|
196
|
+
let to = resolveCase(askedTo);
|
|
197
|
+
// A rename of its case alone, which Windows makes: the name as given, in its directory as found.
|
|
198
|
+
if (to === from) {
|
|
199
|
+
to = join(resolveCase(dirname(askedTo)), basename(askedTo));
|
|
200
|
+
}
|
|
192
201
|
return attempt(() => {
|
|
193
202
|
mkdirSync(dirname(to), { recursive: true });
|
|
194
203
|
try {
|
package/dist/main/air.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"air.js","sourceRoot":"","sources":["../../src/main/air.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,2EAA2E;AAC3E,yEAAyE;AACzE,SAAS;AACT,0EAA0E;AAC1E,OAAO,EACL,SAAS,EACT,MAAM,EACN,aAAa,EACb,SAAS,EACT,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,QAAQ,EACR,aAAa,EACb,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"air.js","sourceRoot":"","sources":["../../src/main/air.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `path`, absolute, as Windows would find it: unchanged where it is there
|
|
3
|
+
* exactly; otherwise from the deepest ancestor that is there, each missing
|
|
4
|
+
* segment taken as the entry of its directory equal to it ignoring case,
|
|
5
|
+
* until one has none, which is kept as given with all after it (a file to
|
|
6
|
+
* be made keeps its name). Where two entries or more are equal ignoring
|
|
7
|
+
* case, which one is meant is not guessed: `path` comes back unchanged.
|
|
8
|
+
* Each call lists the directories it needs afresh, as they change; one
|
|
9
|
+
* whose path is there costs one lstat.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveCase(path: string, caseSensitive?: boolean): string;
|
|
12
|
+
//# sourceMappingURL=case-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-paths.d.ts","sourceRoot":"","sources":["../../src/main/case-paths.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,UAAiB,GAAG,MAAM,CAyDhF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Local paths as a case-insensitive file system finds them. AIR runs on
|
|
2
|
+
// Windows and macOS, whose file systems ignore case, so an AIR application
|
|
3
|
+
// or a SWF made there may name a file in any case: maps/Town.swf for
|
|
4
|
+
// maps/town.swf. On Linux such a path finds nothing, so where the exact
|
|
5
|
+
// path is missing each missing segment is taken as the one entry of its
|
|
6
|
+
// directory equal to it ignoring case. Names are compared as NFC,
|
|
7
|
+
// lowercased by toLowerCase(): close enough to how NTFS and APFS fold
|
|
8
|
+
// case, and APFS keeps a name's normalization, as NFC compares it.
|
|
9
|
+
// Apart from Electron, so that node tests it (tests/desktop/case-paths.test.ts).
|
|
10
|
+
import { lstatSync, readdirSync } from "node:fs";
|
|
11
|
+
import { isAbsolute, parse, sep } from "node:path";
|
|
12
|
+
/** Whether this system's file system tells names apart by case: Linux's do; Windows' and macOS's do not. */
|
|
13
|
+
const CASE_SENSITIVE = process.platform === "linux";
|
|
14
|
+
/** The directories already said, on stderr, to hold names that differ only in case. */
|
|
15
|
+
const told = new Set();
|
|
16
|
+
const fold = (name) => name.normalize("NFC").toLowerCase();
|
|
17
|
+
function exists(path) {
|
|
18
|
+
try {
|
|
19
|
+
lstatSync(path);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* `path`, absolute, as Windows would find it: unchanged where it is there
|
|
28
|
+
* exactly; otherwise from the deepest ancestor that is there, each missing
|
|
29
|
+
* segment taken as the entry of its directory equal to it ignoring case,
|
|
30
|
+
* until one has none, which is kept as given with all after it (a file to
|
|
31
|
+
* be made keeps its name). Where two entries or more are equal ignoring
|
|
32
|
+
* case, which one is meant is not guessed: `path` comes back unchanged.
|
|
33
|
+
* Each call lists the directories it needs afresh, as they change; one
|
|
34
|
+
* whose path is there costs one lstat.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveCase(path, caseSensitive = CASE_SENSITIVE) {
|
|
37
|
+
if (!caseSensitive || !isAbsolute(path) || exists(path)) {
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
|
+
const root = parse(path).root;
|
|
41
|
+
const segments = path.slice(root.length).split(sep);
|
|
42
|
+
// Joined as given, not normalized: ".." is the file system's to follow, through links as today.
|
|
43
|
+
const at = (count, from) => root + from.slice(0, count).join(sep);
|
|
44
|
+
let found = segments.length - 1;
|
|
45
|
+
while (found > 0 && !exists(at(found, segments))) {
|
|
46
|
+
found--;
|
|
47
|
+
}
|
|
48
|
+
const resolved = segments.slice();
|
|
49
|
+
for (let i = found; i < segments.length; i++) {
|
|
50
|
+
const segment = segments[i];
|
|
51
|
+
if (segment === "" || segment === "." || segment === "..") {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const directory = at(i, resolved);
|
|
55
|
+
let names;
|
|
56
|
+
try {
|
|
57
|
+
names = readdirSync(directory);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
// In a directory resolved by case, a segment after it may be there exactly.
|
|
63
|
+
if (names.includes(segment)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const wanted = fold(segment);
|
|
67
|
+
const matches = names.filter((name) => fold(name) === wanted);
|
|
68
|
+
if (matches.length === 0) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (matches.length > 1) {
|
|
72
|
+
const key = `${directory}${sep}${wanted}`;
|
|
73
|
+
if (!told.has(key)) {
|
|
74
|
+
told.add(key);
|
|
75
|
+
console.error(`swf2es: ${directory} holds ${matches.join(", ")}, which differ only in case; ` +
|
|
76
|
+
`${segment} is taken as named, not as any of them.`);
|
|
77
|
+
}
|
|
78
|
+
return path;
|
|
79
|
+
}
|
|
80
|
+
resolved[i] = matches[0];
|
|
81
|
+
}
|
|
82
|
+
return root + resolved.join(sep);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=case-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-paths.js","sourceRoot":"","sources":["../../src/main/case-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SocketEvent } from "../shared/api.js";
|
|
2
|
+
import { type ProxyConfig } from "./proxy.ts";
|
|
2
3
|
/**
|
|
3
4
|
* The bytes a connection may hold unsent. A peer that stops reading would
|
|
4
5
|
* otherwise have the main process buffer all a SWF writes: 100 writes of
|
|
@@ -8,11 +9,21 @@ import type { SocketEvent } from "../shared/api.js";
|
|
|
8
9
|
export declare const MAX_BUFFERED: number;
|
|
9
10
|
/** Whether the page asked for a host name of DNS's length and a TCP port. */
|
|
10
11
|
export declare function validEndpoint(host: unknown, port: unknown): host is string;
|
|
12
|
+
export interface ConnectionOptions {
|
|
13
|
+
/** What every connection goes through; none by default. */
|
|
14
|
+
proxy?: ProxyConfig | null;
|
|
15
|
+
/** Told why a connection through the proxy did not come about, for stderr. */
|
|
16
|
+
warn?: (message: string) => void;
|
|
17
|
+
}
|
|
11
18
|
export declare class Connections {
|
|
12
19
|
private readonly sockets;
|
|
20
|
+
/** Connections still being made through the proxy, each stopped by its controller. */
|
|
21
|
+
private readonly opening;
|
|
13
22
|
private readonly tell;
|
|
23
|
+
private readonly proxy;
|
|
24
|
+
private readonly warn;
|
|
14
25
|
/** `tell` carries each connection's events to its page. */
|
|
15
|
-
constructor(tell: (id: number, event: SocketEvent) => void);
|
|
26
|
+
constructor(tell: (id: number, event: SocketEvent) => void, options?: ConnectionOptions);
|
|
16
27
|
get size(): number;
|
|
17
28
|
/** Counts closeAll's: a connection decided on before one belongs to a page that is gone. */
|
|
18
29
|
generation: number;
|
|
@@ -21,6 +32,14 @@ export declare class Connections {
|
|
|
21
32
|
* was pinned (a remote SWF's socket policy came from there); a refusal is an error, then a close.
|
|
22
33
|
*/
|
|
23
34
|
connect(id: number, host: unknown, port: unknown, address?: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Connect `id` through `proxy`, by the address where one was pinned, else
|
|
37
|
+
* by name for the proxy to resolve. Its peer is the target: the proxy's
|
|
38
|
+
* address is no business of the SWF's. A proxy that fails is a refusal,
|
|
39
|
+
* said with why.
|
|
40
|
+
*/
|
|
41
|
+
private connectThrough;
|
|
42
|
+
private attach;
|
|
24
43
|
/**
|
|
25
44
|
* Write `bytes`, unless the peer has left more than MAX_BUFFERED unread: then the connection
|
|
26
45
|
* fails.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../src/main/connections.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../src/main/connections.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAkB,KAAK,WAAW,EAAmB,MAAM,YAAY,CAAC;AAK/E;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAAkB,CAAC;AAI5C,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAU1E;AAED,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,8EAA8E;IAC9E,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2C;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IAEjD,2DAA2D;IAC3D,YAAY,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,KAAK,IAAI,EAAE,OAAO,GAAE,iBAAsB,EAI1F;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,4FAA4F;IAC5F,UAAU,SAAK;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CA4BxE;IAED;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,MAAM;IAcd;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAaxC;IAED,gFAAgF;IAChF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAGvB;IAED,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWtB;IAED;;;OAGG;IACH,QAAQ,IAAI,IAAI,CAcf;CACF"}
|
package/dist/main/connections.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
// One page's flash.net.Socket connections, made with node:net
|
|
2
|
-
//
|
|
3
|
-
// that node runs it in the tests
|
|
1
|
+
// One page's flash.net.Socket connections, made with node:net, or through
|
|
2
|
+
// the proxy (--proxy, proxy.ts): what the socket bridge (sockets.ts) holds
|
|
3
|
+
// for each page, apart from Electron so that node runs it in the tests
|
|
4
|
+
// (tests/desktop/connections.test.ts).
|
|
4
5
|
import { connect } from "node:net";
|
|
6
|
+
import { connectThrough } from "./proxy.js";
|
|
5
7
|
/** As many as a page may hold open at once; past it a connection is refused. */
|
|
6
8
|
const MAX_OPEN = 64;
|
|
7
9
|
/**
|
|
@@ -24,13 +26,19 @@ export function validEndpoint(host, port) {
|
|
|
24
26
|
}
|
|
25
27
|
export class Connections {
|
|
26
28
|
sockets = new Map();
|
|
29
|
+
/** Connections still being made through the proxy, each stopped by its controller. */
|
|
30
|
+
opening = new Map();
|
|
27
31
|
tell;
|
|
32
|
+
proxy;
|
|
33
|
+
warn;
|
|
28
34
|
/** `tell` carries each connection's events to its page. */
|
|
29
|
-
constructor(tell) {
|
|
35
|
+
constructor(tell, options = {}) {
|
|
30
36
|
this.tell = tell;
|
|
37
|
+
this.proxy = options.proxy ?? null;
|
|
38
|
+
this.warn = options.warn ?? (() => { });
|
|
31
39
|
}
|
|
32
40
|
get size() {
|
|
33
|
-
return this.sockets.size;
|
|
41
|
+
return this.sockets.size + this.opening.size;
|
|
34
42
|
}
|
|
35
43
|
/** Counts closeAll's: a connection decided on before one belongs to a page that is gone. */
|
|
36
44
|
generation = 0;
|
|
@@ -39,12 +47,19 @@ export class Connections {
|
|
|
39
47
|
* was pinned (a remote SWF's socket policy came from there); a refusal is an error, then a close.
|
|
40
48
|
*/
|
|
41
49
|
connect(id, host, port, address) {
|
|
42
|
-
if (!validEndpoint(host, port) ||
|
|
50
|
+
if (!validEndpoint(host, port) ||
|
|
51
|
+
this.sockets.has(id) ||
|
|
52
|
+
this.opening.has(id) ||
|
|
53
|
+
this.size >= MAX_OPEN) {
|
|
43
54
|
this.refuse(id);
|
|
44
55
|
return;
|
|
45
56
|
}
|
|
46
|
-
const
|
|
47
|
-
this.
|
|
57
|
+
const target = address ?? host;
|
|
58
|
+
if (this.proxy) {
|
|
59
|
+
this.connectThrough(this.proxy, id, target, port);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const socket = connect({ host: target, port: port });
|
|
48
63
|
socket.on("connect", () => this.tell(id, {
|
|
49
64
|
type: "open",
|
|
50
65
|
localAddress: socket.localAddress ?? "",
|
|
@@ -52,6 +67,42 @@ export class Connections {
|
|
|
52
67
|
remoteAddress: socket.remoteAddress ?? "",
|
|
53
68
|
remotePort: socket.remotePort ?? 0,
|
|
54
69
|
}));
|
|
70
|
+
this.attach(id, socket);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Connect `id` through `proxy`, by the address where one was pinned, else
|
|
74
|
+
* by name for the proxy to resolve. Its peer is the target: the proxy's
|
|
75
|
+
* address is no business of the SWF's. A proxy that fails is a refusal,
|
|
76
|
+
* said with why.
|
|
77
|
+
*/
|
|
78
|
+
connectThrough(proxy, id, target, port) {
|
|
79
|
+
const opening = new AbortController();
|
|
80
|
+
this.opening.set(id, opening);
|
|
81
|
+
connectThrough(proxy, target, port, { signal: opening.signal }).then((socket) => {
|
|
82
|
+
if (this.opening.get(id) !== opening) {
|
|
83
|
+
socket.destroy();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.opening.delete(id);
|
|
87
|
+
this.attach(id, socket);
|
|
88
|
+
this.tell(id, {
|
|
89
|
+
type: "open",
|
|
90
|
+
localAddress: socket.localAddress ?? "",
|
|
91
|
+
localPort: socket.localPort ?? 0,
|
|
92
|
+
remoteAddress: target,
|
|
93
|
+
remotePort: port,
|
|
94
|
+
});
|
|
95
|
+
}, (error) => {
|
|
96
|
+
if (this.opening.get(id) !== opening) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.opening.delete(id);
|
|
100
|
+
this.warn(`no socket to ${target}:${port}: ${error.message}`);
|
|
101
|
+
this.refuse(id);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
attach(id, socket) {
|
|
105
|
+
this.sockets.set(id, socket);
|
|
55
106
|
socket.on("data", (bytes) => this.tell(id, { type: "data", bytes: new Uint8Array(bytes) }));
|
|
56
107
|
socket.on("error", () => this.tell(id, { type: "error", message: SOCKET_ERROR }));
|
|
57
108
|
socket.on("close", () => {
|
|
@@ -84,6 +135,14 @@ export class Connections {
|
|
|
84
135
|
this.tell(id, { type: "close" });
|
|
85
136
|
}
|
|
86
137
|
close(id) {
|
|
138
|
+
const opening = this.opening.get(id);
|
|
139
|
+
if (opening) {
|
|
140
|
+
// Closed before the proxy made it: closed, as a socket destroyed before it connects.
|
|
141
|
+
this.opening.delete(id);
|
|
142
|
+
opening.abort();
|
|
143
|
+
this.tell(id, { type: "close" });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
87
146
|
this.sockets.get(id)?.destroy();
|
|
88
147
|
}
|
|
89
148
|
/**
|
|
@@ -96,7 +155,11 @@ export class Connections {
|
|
|
96
155
|
socket.on("error", () => { });
|
|
97
156
|
socket.destroy();
|
|
98
157
|
}
|
|
158
|
+
for (const opening of this.opening.values()) {
|
|
159
|
+
opening.abort();
|
|
160
|
+
}
|
|
99
161
|
this.sockets.clear();
|
|
162
|
+
this.opening.clear();
|
|
100
163
|
this.generation++;
|
|
101
164
|
}
|
|
102
165
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/main/connections.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/main/connections.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,uEAAuE;AACvE,uCAAuC;AACvC,OAAO,EAAE,OAAO,EAAe,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAqC,MAAM,YAAY,CAAC;AAE/E,gFAAgF;AAChF,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAElD,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,IAAa,EAAE,IAAa;IACxD,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,CAAC,MAAM,GAAG,CAAC;QACf,IAAI,CAAC,MAAM,IAAI,GAAG;QAClB,OAAO,IAAI,KAAK,QAAQ;QACxB,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;QACtB,IAAI,GAAG,CAAC;QACR,IAAI,GAAG,KAAK,CACb,CAAC;AACJ,CAAC;AASD,MAAM,OAAO,WAAW;IACL,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrD,sFAAsF;IACrE,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC7C,IAAI,CAA2C;IAC/C,KAAK,CAAqB;IAC1B,IAAI,CAA4B;IAEjD,2DAA2D;IAC3D,YAAY,IAA8C,EAAE,OAAO,GAAsB,EAAE;QACzF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC/C,CAAC;IAED,4FAA4F;IAC5F,UAAU,GAAG,CAAC,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAU,EAAE,IAAa,EAAE,IAAa,EAAE,OAAgB;QAChE,IACE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,IAAI,QAAQ,EACrB,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,IAAI,IAAI,CAAC;QAC/B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,IAAc,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAc,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CACxB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACZ,IAAI,EAAE,MAAM;YACZ,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;YACvC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,CAAC;YAChC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;YACzC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,CAAC;SACnC,CAAC,CACH,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;OAKG;IACK,cAAc,CAAC,KAAkB,EAAE,EAAU,EAAE,MAAc,EAAE,IAAY;QACjF,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC9B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAClE,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC;gBACrC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;gBACZ,IAAI,EAAE,MAAM;gBACZ,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;gBACvC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,CAAC;gBAChC,aAAa,EAAE,MAAM;gBACrB,UAAU,EAAE,IAAI;aACjB,CAAC,CAAC;QACL,CAAC,EACD,CAAC,KAAiB,EAAE,EAAE;YACpB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC;gBACrC,OAAO;YACT,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,MAAM,IAAI,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC,CACF,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,EAAU,EAAE,MAAc;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,2EAA2E;YAC3E,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;gBACpC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,EAAU,EAAE,KAAiB;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;YACxD,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,gFAAgF;IAChF,MAAM,CAAC,EAAU;QACf,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,EAAU;QACd,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,qFAAqF;YACrF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC5B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;CACF"}
|