@chatwarden/player-react 0.0.0-stage → 0.1.3
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/LICENSE +202 -0
- package/README.md +401 -2
- package/dist/src/Dialog.d.ts +13 -0
- package/dist/src/Dialog.d.ts.map +1 -0
- package/dist/src/Dialog.js +83 -0
- package/dist/src/Dialog.js.map +1 -0
- package/dist/src/MyRecord.d.ts +12 -0
- package/dist/src/MyRecord.d.ts.map +1 -0
- package/dist/src/MyRecord.js +17 -0
- package/dist/src/MyRecord.js.map +1 -0
- package/dist/src/NoticeQueue.d.ts +26 -0
- package/dist/src/NoticeQueue.d.ts.map +1 -0
- package/dist/src/NoticeQueue.js +90 -0
- package/dist/src/NoticeQueue.js.map +1 -0
- package/dist/src/ReportDialog.d.ts +64 -0
- package/dist/src/ReportDialog.d.ts.map +1 -0
- package/dist/src/ReportDialog.js +146 -0
- package/dist/src/ReportDialog.js.map +1 -0
- package/dist/src/RestrictedChatLine.d.ts +12 -0
- package/dist/src/RestrictedChatLine.d.ts.map +1 -0
- package/dist/src/RestrictedChatLine.js +19 -0
- package/dist/src/RestrictedChatLine.js.map +1 -0
- package/dist/src/RulesPage.d.ts +10 -0
- package/dist/src/RulesPage.d.ts.map +1 -0
- package/dist/src/RulesPage.js +17 -0
- package/dist/src/RulesPage.js.map +1 -0
- package/dist/src/client.d.ts +51 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +98 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/constants.d.ts +5 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +5 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/format.d.ts +14 -0
- package/dist/src/format.d.ts.map +1 -0
- package/dist/src/format.js +55 -0
- package/dist/src/format.js.map +1 -0
- package/dist/src/hooks.d.ts +15 -0
- package/dist/src/hooks.d.ts.map +1 -0
- package/dist/src/hooks.js +29 -0
- package/dist/src/hooks.js.map +1 -0
- package/dist/src/i18n.d.ts +153 -0
- package/dist/src/i18n.d.ts.map +1 -0
- package/dist/src/i18n.js +191 -0
- package/dist/src/i18n.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/reporting.d.ts +20 -0
- package/dist/src/reporting.d.ts.map +1 -0
- package/dist/src/reporting.js +45 -0
- package/dist/src/reporting.js.map +1 -0
- package/dist/src/safeHref.d.ts +5 -0
- package/dist/src/safeHref.d.ts.map +1 -0
- package/dist/src/safeHref.js +41 -0
- package/dist/src/safeHref.js.map +1 -0
- package/dist/src/transport.d.ts +69 -0
- package/dist/src/transport.d.ts.map +1 -0
- package/dist/src/transport.js +74 -0
- package/dist/src/transport.js.map +1 -0
- package/dist/src/ui.d.ts +91 -0
- package/dist/src/ui.d.ts.map +1 -0
- package/dist/src/ui.js +116 -0
- package/dist/src/ui.js.map +1 -0
- package/package.json +73 -4
- package/src/Dialog.tsx +107 -0
- package/src/MyRecord.tsx +60 -0
- package/src/NoticeQueue.tsx +203 -0
- package/src/ReportDialog.tsx +319 -0
- package/src/RestrictedChatLine.tsx +42 -0
- package/src/RulesPage.tsx +49 -0
- package/src/client.ts +132 -0
- package/src/constants.ts +5 -0
- package/src/format.ts +53 -0
- package/src/hooks.ts +41 -0
- package/src/i18n.ts +211 -0
- package/src/index.ts +32 -0
- package/src/reporting.ts +51 -0
- package/src/safeHref.ts +36 -0
- package/src/styles.css +500 -0
- package/src/transport.ts +134 -0
- package/src/ui.tsx +199 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PlayerNotice, PlayerReporting } from '@chatwarden/core';
|
|
2
|
+
import type { Transport } from './transport.js';
|
|
3
|
+
/**
|
|
4
|
+
* Why a call to the player routes failed. `status` is the HTTP status, or 0 when no answer arrived. `code` is the kit's error
|
|
5
|
+
* code (`not_found`, `rate_limited`, ...), `network` for a dropped connection, `bad_response` for an answer that is not the
|
|
6
|
+
* shape the components expect, `unexpected` for anything else, and `http_<status>` when the body is not a kit error.
|
|
7
|
+
* `retryAfter` is the seconds from a `retry-after` header (a 429).
|
|
8
|
+
*/
|
|
9
|
+
export declare class PlayerError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly code: string;
|
|
12
|
+
readonly retryAfter: number | undefined;
|
|
13
|
+
constructor(init: {
|
|
14
|
+
status: number;
|
|
15
|
+
code: string;
|
|
16
|
+
message: string;
|
|
17
|
+
retryAfter?: number;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** A `PlayerError` as is; anything else (a bug in the caller's code, say) becomes status 0, code `unexpected`. */
|
|
21
|
+
export declare function toPlayerError(e: unknown): PlayerError;
|
|
22
|
+
/** One rule as `GET /rules` gives it. */
|
|
23
|
+
export interface PlayerRule {
|
|
24
|
+
number: number;
|
|
25
|
+
title: string;
|
|
26
|
+
text: string;
|
|
27
|
+
}
|
|
28
|
+
/** `GET /rules`: the profile's one-line summary, the active rules and how reporting works here (`undefined` from an older server). */
|
|
29
|
+
export interface PlayerRules {
|
|
30
|
+
summary: string;
|
|
31
|
+
rules: PlayerRule[];
|
|
32
|
+
/** The flow, the reasons a player may give and the thank-you: pass it to `ReportDialog` as `reporting`. */
|
|
33
|
+
reporting?: PlayerReporting;
|
|
34
|
+
}
|
|
35
|
+
export interface PlayerClient {
|
|
36
|
+
/** `GET /notices`: notices not yet acknowledged, as the kit sends them (oldest first). */
|
|
37
|
+
notices(): Promise<PlayerNotice[]>;
|
|
38
|
+
/** `POST /notices/:id/ack`: `true` when it was this player's live notice, `false` (still a 200) when it was not, or it is gone. */
|
|
39
|
+
ack(id: string): Promise<boolean>;
|
|
40
|
+
/** `GET /record`: the player's sanctions that still apply (seen or not). */
|
|
41
|
+
record(): Promise<PlayerNotice[]>;
|
|
42
|
+
/** `GET /rules`: the summary, the numbered rules and the reporting settings. */
|
|
43
|
+
rules(): Promise<PlayerRules>;
|
|
44
|
+
}
|
|
45
|
+
export interface PlayerClientOptions {
|
|
46
|
+
/** How to reach the player routes: `fetchTransport({ baseUrl: '/player' })`, or any function with the same shape. */
|
|
47
|
+
transport: Transport;
|
|
48
|
+
}
|
|
49
|
+
/** A client over the kit's player routes. It resolves with typed values and rejects with a `PlayerError`. */
|
|
50
|
+
export declare function createPlayerClient({ transport }: PlayerClientOptions): PlayerClient;
|
|
51
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAuC,MAAM,gBAAgB,CAAC;AAErF;;;;;GAKG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;gBAE5B,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;CAOzF;AAED,kHAAkH;AAClH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,WAAW,CAGrD;AAmDD,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sIAAsI;AACtI,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,2GAA2G;IAC3G,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,0FAA0F;IAC1F,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACnC,mIAAmI;IACnI,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,4EAA4E;IAC5E,MAAM,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAClC,gFAAgF;IAChF,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,qHAAqH;IACrH,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,6GAA6G;AAC7G,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,GAAG,YAAY,CAoBnF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readReporting } from './reporting.js';
|
|
2
|
+
/**
|
|
3
|
+
* Why a call to the player routes failed. `status` is the HTTP status, or 0 when no answer arrived. `code` is the kit's error
|
|
4
|
+
* code (`not_found`, `rate_limited`, ...), `network` for a dropped connection, `bad_response` for an answer that is not the
|
|
5
|
+
* shape the components expect, `unexpected` for anything else, and `http_<status>` when the body is not a kit error.
|
|
6
|
+
* `retryAfter` is the seconds from a `retry-after` header (a 429).
|
|
7
|
+
*/
|
|
8
|
+
export class PlayerError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
code;
|
|
11
|
+
retryAfter;
|
|
12
|
+
constructor(init) {
|
|
13
|
+
super(init.message);
|
|
14
|
+
this.name = 'PlayerError';
|
|
15
|
+
this.status = init.status;
|
|
16
|
+
this.code = init.code;
|
|
17
|
+
this.retryAfter = init.retryAfter;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** A `PlayerError` as is; anything else (a bug in the caller's code, say) becomes status 0, code `unexpected`. */
|
|
21
|
+
export function toPlayerError(e) {
|
|
22
|
+
if (e instanceof PlayerError)
|
|
23
|
+
return e;
|
|
24
|
+
return new PlayerError({ status: 0, code: 'unexpected', message: e instanceof Error ? e.message : 'Something went wrong.' });
|
|
25
|
+
}
|
|
26
|
+
const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
27
|
+
const text = (v) => typeof v === 'string';
|
|
28
|
+
function errorOf(res) {
|
|
29
|
+
const b = res.body;
|
|
30
|
+
const raw = res.headers['retry-after'];
|
|
31
|
+
const rest = raw !== undefined && /^\d{1,9}$/.test(raw) ? { retryAfter: Number(raw) } : {};
|
|
32
|
+
if (isObject(b) && text(b.error) && text(b.message))
|
|
33
|
+
return new PlayerError({ status: res.status, code: b.error, message: b.message, ...rest });
|
|
34
|
+
// A proxy's HTML page, or an empty body: say the status, never echo the body.
|
|
35
|
+
return new PlayerError({ status: res.status, code: `http_${res.status}`, message: `The server answered with status ${res.status}.`, ...rest });
|
|
36
|
+
}
|
|
37
|
+
async function send(transport, req) {
|
|
38
|
+
let res;
|
|
39
|
+
try {
|
|
40
|
+
res = await transport(req);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
throw new PlayerError({ status: 0, code: 'network', message: e instanceof Error && e.name === 'AbortError' ? 'The request was cancelled.' : 'Could not reach the server.' });
|
|
44
|
+
}
|
|
45
|
+
if (res.status < 200 || res.status > 299)
|
|
46
|
+
throw errorOf(res);
|
|
47
|
+
return res.body;
|
|
48
|
+
}
|
|
49
|
+
const bad = () => new PlayerError({ status: 200, code: 'bad_response', message: 'The server sent an answer these components do not understand.' });
|
|
50
|
+
/** One notice, keeping only the fields the kit documents for a player. Anything else the server sent never reaches the page. */
|
|
51
|
+
function noticeOf(raw) {
|
|
52
|
+
if (!isObject(raw) || !text(raw.id) || !text(raw.kind))
|
|
53
|
+
return null;
|
|
54
|
+
const excerpt = Array.isArray(raw.excerpt)
|
|
55
|
+
? raw.excerpt.filter(isObject).filter((l) => text(l.text) && text(l.day)).map((l) => ({ text: l.text, day: l.day }))
|
|
56
|
+
: [];
|
|
57
|
+
return {
|
|
58
|
+
id: raw.id,
|
|
59
|
+
kind: raw.kind,
|
|
60
|
+
rule: typeof raw.rule === 'number' || raw.rule === 'uncovered' ? raw.rule : null,
|
|
61
|
+
ruleLabel: text(raw.ruleLabel) ? raw.ruleLabel : null,
|
|
62
|
+
until: typeof raw.until === 'number' && Number.isFinite(raw.until) ? raw.until : null,
|
|
63
|
+
refCode: text(raw.refCode) ? raw.refCode : null,
|
|
64
|
+
excerpt,
|
|
65
|
+
createdAt: typeof raw.createdAt === 'number' && Number.isFinite(raw.createdAt) ? raw.createdAt : 0,
|
|
66
|
+
mustAcknowledge: raw.mustAcknowledge === true,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function noticesOf(body, key) {
|
|
70
|
+
if (!isObject(body) || !Array.isArray(body[key]))
|
|
71
|
+
throw bad();
|
|
72
|
+
return body[key].map(noticeOf).filter((n) => n !== null);
|
|
73
|
+
}
|
|
74
|
+
/** A client over the kit's player routes. It resolves with typed values and rejects with a `PlayerError`. */
|
|
75
|
+
export function createPlayerClient({ transport }) {
|
|
76
|
+
return {
|
|
77
|
+
notices: async () => noticesOf(await send(transport, { method: 'GET', path: '/notices' }), 'notices'),
|
|
78
|
+
record: async () => noticesOf(await send(transport, { method: 'GET', path: '/record' }), 'record'),
|
|
79
|
+
ack: async (id) => {
|
|
80
|
+
const body = await send(transport, { method: 'POST', path: `/notices/${encodeURIComponent(id)}/ack` });
|
|
81
|
+
if (!isObject(body) || typeof body.ok !== 'boolean')
|
|
82
|
+
throw bad();
|
|
83
|
+
return body.ok;
|
|
84
|
+
},
|
|
85
|
+
rules: async () => {
|
|
86
|
+
const body = await send(transport, { method: 'GET', path: '/rules' });
|
|
87
|
+
if (!isObject(body) || !text(body.summary) || !Array.isArray(body.rules))
|
|
88
|
+
throw bad();
|
|
89
|
+
const rules = body.rules
|
|
90
|
+
.filter(isObject)
|
|
91
|
+
.filter((r) => typeof r.number === 'number' && text(r.title) && text(r.text))
|
|
92
|
+
.map((r) => ({ number: r.number, title: r.title, text: r.text }));
|
|
93
|
+
const reporting = readReporting(body.reporting);
|
|
94
|
+
return { summary: body.summary, rules, ...(reporting === undefined ? {} : { reporting }) };
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The longest note the kit keeps (a test keeps this the same as core's `REPORT_NOTE_MAX`). */
|
|
2
|
+
export declare const NOTE_MAX = 500;
|
|
3
|
+
/** How many days a warning stays on a record (a test keeps this the same as core's notice record window). */
|
|
4
|
+
export declare const WARNING_DAYS = 90;
|
|
5
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,6GAA6G;AAC7G,eAAO,MAAM,YAAY,KAAK,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The longest note the kit keeps (a test keeps this the same as core's `REPORT_NOTE_MAX`). */
|
|
2
|
+
export const NOTE_MAX = 500;
|
|
3
|
+
/** How many days a warning stays on a record (a test keeps this the same as core's notice record window). */
|
|
4
|
+
export const WARNING_DAYS = 90;
|
|
5
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAE5B,6GAA6G;AAC7G,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UTC day from the kit (`2027-01-15`) as the locale writes a date (`Jan 15, 2027`), in UTC whatever the viewer's zone: the kit
|
|
3
|
+
* names the day in UTC, so a notice never shows a different day than the moderator's tools. A value that is not a day comes back
|
|
4
|
+
* as it was; it is never shown as "Invalid Date".
|
|
5
|
+
*/
|
|
6
|
+
export declare function dayText(day: string, locale: string): string;
|
|
7
|
+
/** A date and time: `Jan 15, 2027, 8:30 PM`. Pass a time zone for a fixed one; the default is the viewer's. An unknown zone is ignored. */
|
|
8
|
+
export declare function untilText(at: number, locale: string, timeZone?: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* How long is left until `at`, as the locale says it ("in 3 hours"): minutes under an hour (a part of a minute counts as a whole
|
|
11
|
+
* one, so a live restriction never reads "in 0 minutes"), hours under two days, then days. Null when `at` is now or has passed.
|
|
12
|
+
*/
|
|
13
|
+
export declare function timeLeft(at: number, now: number, locale: string): string | null;
|
|
14
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO3D;AAED,2IAA2I;AAC3I,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO/E"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Small pure helpers for showing days, times and waits. Times use Intl with the component's `locale`; none holds English.
|
|
2
|
+
const MIN = 60_000;
|
|
3
|
+
const HOUR = 60 * MIN;
|
|
4
|
+
const DAY = 24 * HOUR;
|
|
5
|
+
function safeLocale(locale) {
|
|
6
|
+
try {
|
|
7
|
+
return Intl.getCanonicalLocales(locale)[0] ?? 'en';
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return 'en';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Some runtimes put a narrow no-break space before "PM". A plain space reads the same and survives a copy. */
|
|
14
|
+
const plain = (text) => text.replace(/[\u202f\u00a0]/g, ' ');
|
|
15
|
+
/**
|
|
16
|
+
* A UTC day from the kit (`2027-01-15`) as the locale writes a date (`Jan 15, 2027`), in UTC whatever the viewer's zone: the kit
|
|
17
|
+
* names the day in UTC, so a notice never shows a different day than the moderator's tools. A value that is not a day comes back
|
|
18
|
+
* as it was; it is never shown as "Invalid Date".
|
|
19
|
+
*/
|
|
20
|
+
export function dayText(day, locale) {
|
|
21
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
22
|
+
if (m === null)
|
|
23
|
+
return day;
|
|
24
|
+
const [y, mo, d] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
25
|
+
const date = new Date(Date.UTC(y, mo - 1, d));
|
|
26
|
+
if (date.getUTCFullYear() !== y || date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d)
|
|
27
|
+
return day;
|
|
28
|
+
return new Intl.DateTimeFormat(safeLocale(locale), { dateStyle: 'medium', timeZone: 'UTC' }).format(date);
|
|
29
|
+
}
|
|
30
|
+
/** A date and time: `Jan 15, 2027, 8:30 PM`. Pass a time zone for a fixed one; the default is the viewer's. An unknown zone is ignored. */
|
|
31
|
+
export function untilText(at, locale, timeZone) {
|
|
32
|
+
const options = { dateStyle: 'medium', timeStyle: 'short' };
|
|
33
|
+
try {
|
|
34
|
+
return plain(new Intl.DateTimeFormat(safeLocale(locale), { ...options, ...(timeZone === undefined ? {} : { timeZone }) }).format(at));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return plain(new Intl.DateTimeFormat(safeLocale(locale), options).format(at));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* How long is left until `at`, as the locale says it ("in 3 hours"): minutes under an hour (a part of a minute counts as a whole
|
|
42
|
+
* one, so a live restriction never reads "in 0 minutes"), hours under two days, then days. Null when `at` is now or has passed.
|
|
43
|
+
*/
|
|
44
|
+
export function timeLeft(at, now, locale) {
|
|
45
|
+
const left = at - now;
|
|
46
|
+
if (!(left > 0))
|
|
47
|
+
return null;
|
|
48
|
+
const rtf = new Intl.RelativeTimeFormat(safeLocale(locale), { numeric: 'always' });
|
|
49
|
+
if (left < HOUR)
|
|
50
|
+
return rtf.format(Math.max(1, Math.ceil(left / MIN)), 'minute');
|
|
51
|
+
if (left < 2 * DAY)
|
|
52
|
+
return rtf.format(Math.round(left / HOUR), 'hour');
|
|
53
|
+
return rtf.format(Math.round(left / DAY), 'day');
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PlayerError } from './client.js';
|
|
2
|
+
export interface PlayerData<T> {
|
|
3
|
+
/** The last answer, kept when a later load fails. */
|
|
4
|
+
data: T | undefined;
|
|
5
|
+
/** The last failure, or null. Cleared when a load starts. */
|
|
6
|
+
error: PlayerError | null;
|
|
7
|
+
/** Starts the same load again. */
|
|
8
|
+
reload: () => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Runs `load` on mount, again when `refreshKey` changes, and again on `reload()`. An answer from a load that has been replaced
|
|
12
|
+
* (or from a component that is gone) is dropped, so a slow old request never overwrites a newer one.
|
|
13
|
+
*/
|
|
14
|
+
export declare function usePlayerData<T>(load: () => Promise<T>, refreshKey: unknown): PlayerData<T>;
|
|
15
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAiB,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,qDAAqD;IACrD,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,6DAA6D;IAC7D,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,kCAAkC;IAClC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAwB3F"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { PlayerError, toPlayerError } from './client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runs `load` on mount, again when `refreshKey` changes, and again on `reload()`. An answer from a load that has been replaced
|
|
5
|
+
* (or from a component that is gone) is dropped, so a slow old request never overwrites a newer one.
|
|
6
|
+
*/
|
|
7
|
+
export function usePlayerData(load, refreshKey) {
|
|
8
|
+
const [state, setState] = useState({ data: undefined, error: null });
|
|
9
|
+
const [again, setAgain] = useState(0);
|
|
10
|
+
const loader = useRef(load);
|
|
11
|
+
loader.current = load;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
let live = true;
|
|
14
|
+
setState((s) => (s.error === null ? s : { ...s, error: null }));
|
|
15
|
+
loader.current().then((data) => {
|
|
16
|
+
if (live)
|
|
17
|
+
setState({ data, error: null });
|
|
18
|
+
}, (e) => {
|
|
19
|
+
if (live)
|
|
20
|
+
setState((s) => ({ data: s.data, error: toPlayerError(e) }));
|
|
21
|
+
});
|
|
22
|
+
return () => {
|
|
23
|
+
live = false;
|
|
24
|
+
};
|
|
25
|
+
}, [refreshKey, again]);
|
|
26
|
+
const reload = useCallback(() => setAgain((n) => n + 1), []);
|
|
27
|
+
return { data: state.data, error: state.error, reload };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWzD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAI,IAAsB,EAAE,UAAmB;IAC1E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqD,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAEtB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CACnB,CAAC,IAAI,EAAE,EAAE;YACP,IAAI,IAAI;gBAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC,EACD,CAAC,CAAU,EAAE,EAAE;YACb,IAAI,IAAI;gBAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzE,CAAC,CACF,CAAC;QACF,OAAO,GAAG,EAAE;YACV,IAAI,GAAG,KAAK,CAAC;QACf,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
export declare const en: {
|
|
2
|
+
readonly 'player.error.network': "Could not reach the server. Check your connection and try again.";
|
|
3
|
+
readonly 'player.error.unauthorized': "You are signed out. Sign in again, then try again.";
|
|
4
|
+
readonly 'player.error.forbidden': "This account cannot do that.";
|
|
5
|
+
readonly 'player.error.notFound': "That could not be found.";
|
|
6
|
+
readonly 'player.error.rateLimited': "Too many requests. Try again in a moment.";
|
|
7
|
+
readonly 'player.error.rateLimited.after.one': "Too many requests. Try again in {count} second.";
|
|
8
|
+
readonly 'player.error.rateLimited.after.other': "Too many requests. Try again in {count} seconds.";
|
|
9
|
+
readonly 'player.error.server': "The server had a problem. Try again in a moment.";
|
|
10
|
+
readonly 'player.error.generic': "Something went wrong.";
|
|
11
|
+
readonly 'player.state.retry': "Try again";
|
|
12
|
+
readonly 'player.notices.loadFailed': "We could not check for notices.";
|
|
13
|
+
readonly 'player.notice.title.warning': "You have a warning";
|
|
14
|
+
readonly 'player.notice.title.chat': "Your chat is turned off";
|
|
15
|
+
readonly 'player.notice.title.area': "You cannot join public rooms";
|
|
16
|
+
readonly 'player.notice.title.ban': "You are banned";
|
|
17
|
+
readonly 'player.notice.title.report_outcome': "Thanks for your report";
|
|
18
|
+
readonly 'player.notice.title.fallback': "A message from the moderators";
|
|
19
|
+
readonly 'player.notice.body.warning': "A moderator gave you a warning for something you wrote. You can keep playing.";
|
|
20
|
+
readonly 'player.notice.body.chat': "A moderator turned off your chat. You can still play.";
|
|
21
|
+
readonly 'player.notice.body.area': "A moderator stopped you joining public rooms and matchmaking. You can still play in private rooms.";
|
|
22
|
+
readonly 'player.notice.body.ban': "A moderator banned you from playing.";
|
|
23
|
+
readonly 'player.notice.body.report_outcome': "A moderator looked at your report and took action. We do not share what was done.";
|
|
24
|
+
readonly 'player.notice.body.fallback': "There is a new message about your account.";
|
|
25
|
+
readonly 'player.notice.position': "Notice {n} of {total}";
|
|
26
|
+
readonly 'player.notice.rule': "Rule";
|
|
27
|
+
readonly 'player.notice.given': "Given";
|
|
28
|
+
readonly 'player.notice.until': "Until";
|
|
29
|
+
readonly 'player.notice.ended': "Ended";
|
|
30
|
+
readonly 'player.notice.noEnd': "No end date";
|
|
31
|
+
readonly 'player.notice.onRecordUntil': "On your record until";
|
|
32
|
+
readonly 'player.notice.untilLeft': "{when} ({left})";
|
|
33
|
+
readonly 'player.notice.ref': "Reference";
|
|
34
|
+
readonly 'player.notice.refHint': "Quote this code if you contact us.";
|
|
35
|
+
readonly 'player.notice.lines': "Your messages that led to this";
|
|
36
|
+
readonly 'player.notice.todo.warning': "Press Acknowledge to confirm you saw this.";
|
|
37
|
+
readonly 'player.notice.acknowledge': "Acknowledge";
|
|
38
|
+
readonly 'player.notice.gotIt': "Got it";
|
|
39
|
+
readonly 'player.notice.appeal': "Think this is a mistake?";
|
|
40
|
+
readonly 'player.notice.ackFailed': "Your notice is still here.";
|
|
41
|
+
readonly 'player.notice.closeForNow': "Close for now";
|
|
42
|
+
readonly 'player.record.title': "Your record";
|
|
43
|
+
readonly 'player.record.loading': "Loading your record";
|
|
44
|
+
readonly 'player.record.loadFailed': "We could not load your record.";
|
|
45
|
+
readonly 'player.record.intro': "This is what is on your record now. A warning stays for {days} days.";
|
|
46
|
+
readonly 'player.record.empty': "Your record is clear. Nothing is on it right now.";
|
|
47
|
+
readonly 'player.record.kind.warning': "Warning";
|
|
48
|
+
readonly 'player.record.kind.chat': "Chat restriction";
|
|
49
|
+
readonly 'player.record.kind.area': "Public rooms restriction";
|
|
50
|
+
readonly 'player.record.kind.ban': "Ban";
|
|
51
|
+
readonly 'player.record.kind.fallback': "Notice";
|
|
52
|
+
readonly 'player.rules.title': "Community rules";
|
|
53
|
+
readonly 'player.rules.loading': "Loading the rules";
|
|
54
|
+
readonly 'player.rules.loadFailed': "We could not load the rules.";
|
|
55
|
+
readonly 'player.rules.empty': "No rules are published yet.";
|
|
56
|
+
readonly 'player.restricted.moderator.until': "A moderator turned off your chat until {when} ({left}).";
|
|
57
|
+
readonly 'player.restricted.moderator.noEnd': "A moderator turned off your chat. It does not end on its own.";
|
|
58
|
+
readonly 'player.restricted.filter.until': "Your chat is off until {when} ({left}). The automatic filter caught a message.";
|
|
59
|
+
readonly 'player.restricted.filter.noEnd': "Your chat is off. It does not end on its own. The automatic filter caught a message.";
|
|
60
|
+
readonly 'player.restricted.ended': "Your chat is back on. The restriction ended {when}.";
|
|
61
|
+
readonly 'player.restricted.ref': "Reference {code}";
|
|
62
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
63
|
+
readonly 'player.report.title': "Report a player";
|
|
64
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
65
|
+
readonly 'player.report.titleNamed': "Report {name}";
|
|
66
|
+
readonly 'player.report.intro': "Tell us why and a moderator will look at it.";
|
|
67
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
68
|
+
readonly 'player.report.legend': "What happened?";
|
|
69
|
+
readonly 'player.report.titleOneTap': "Report this message?";
|
|
70
|
+
readonly 'player.report.titleOneTapNamed': "Report {name}?";
|
|
71
|
+
readonly 'player.report.titleOneTapPlayer': "Report this player?";
|
|
72
|
+
readonly 'player.report.titleSent': "Report sent";
|
|
73
|
+
readonly 'player.report.titleRefused': "Couldn't send the report";
|
|
74
|
+
readonly 'player.report.oneTap.intro': "We will pass it to the moderators. You do not need to say why.";
|
|
75
|
+
readonly 'player.report.oneTap.send': "Report";
|
|
76
|
+
readonly 'player.report.quote': "“{line}”";
|
|
77
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
78
|
+
readonly 'player.report.skip': "Skip and report";
|
|
79
|
+
readonly 'player.report.needReason': "Choose a reason.";
|
|
80
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
81
|
+
readonly 'player.report.needReasonOrSkip': "Choose what happened, or skip.";
|
|
82
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
83
|
+
readonly 'player.report.addReason': "Add a reason";
|
|
84
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
85
|
+
readonly 'player.report.addReasonHint': "This helps, but the moderators decide what it really is. You can add this for a few minutes after you report.";
|
|
86
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
87
|
+
readonly 'player.report.detail.legend': "What was it about?";
|
|
88
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
89
|
+
readonly 'player.report.detail.send': "Add to my report";
|
|
90
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
91
|
+
readonly 'player.report.detail.need': "Choose a reason or write a note.";
|
|
92
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
93
|
+
readonly 'player.report.detail.added': "Added. Thanks.";
|
|
94
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
95
|
+
readonly 'player.report.detail.failed': "We could not add that.";
|
|
96
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
97
|
+
readonly 'player.report.detail.refused.off': "Adding to a report is not available right now.";
|
|
98
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
99
|
+
readonly 'player.report.detail.refused.not_found': "We cannot find that report any more.";
|
|
100
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
101
|
+
readonly 'player.report.detail.refused.not_reporter': "Only the player who sent a report can add to it.";
|
|
102
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
103
|
+
readonly 'player.report.detail.refused.too_late': "It is too late to add to this report. We still have the report.";
|
|
104
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
105
|
+
readonly 'player.report.detail.refused.already_added': "You already added to this report.";
|
|
106
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
107
|
+
readonly 'player.report.detail.refused.reason_unknown': "That reason is not available any more. Your report is still with us.";
|
|
108
|
+
readonly 'player.report.note': "Note (optional)";
|
|
109
|
+
readonly 'player.report.addNote': "Add a note";
|
|
110
|
+
readonly 'player.report.why': "Why? (optional)";
|
|
111
|
+
readonly 'player.report.whyRequired': "Why?";
|
|
112
|
+
readonly 'player.report.choose': "Choose a reason (optional)";
|
|
113
|
+
readonly 'player.report.chooseRequired': "Choose a reason";
|
|
114
|
+
readonly 'player.report.noteHint': "A moderator will read this. Up to {max} characters. Do not include passwords or personal details.";
|
|
115
|
+
/** @deprecated unused since 0.1.3; removed in a later minor */
|
|
116
|
+
readonly 'player.report.send': "Send report";
|
|
117
|
+
readonly 'player.report.cancel': "Cancel";
|
|
118
|
+
readonly 'player.report.close': "Close";
|
|
119
|
+
readonly 'player.report.failed': "Your report was not sent.";
|
|
120
|
+
readonly 'player.report.thanks': "Thanks. We got your report.";
|
|
121
|
+
readonly 'player.report.remaining.zero': "You have no more reports left today.";
|
|
122
|
+
readonly 'player.report.remaining.one': "You can send {count} more report today.";
|
|
123
|
+
readonly 'player.report.remaining.other': "You can send {count} more reports today.";
|
|
124
|
+
readonly 'player.report.refused.duplicate': "You already reported this player here. We have your report.";
|
|
125
|
+
readonly 'player.report.refused.rate': "You have sent as many reports as you can today. You can send more tomorrow.";
|
|
126
|
+
readonly 'player.report.refused.self': "You cannot report yourself.";
|
|
127
|
+
readonly 'player.report.refused.not_player': "We cannot find that player any more. They may have left.";
|
|
128
|
+
readonly 'player.report.refused.off': "Reports are not available right now. Try again later.";
|
|
129
|
+
readonly 'player.report.refused.suspended': "You cannot send reports from this account for now.";
|
|
130
|
+
readonly 'player.report.refused.reason_required': "This report needs a reason. Close this and report again to choose one.";
|
|
131
|
+
readonly 'player.report.refused.reason_unknown': "That reason is not available any more. Close this and report again.";
|
|
132
|
+
readonly 'player.report.refused.unknown': "We could not take that report.";
|
|
133
|
+
};
|
|
134
|
+
/** A catalog: keys to English (or translated) text. Any object of strings will do. */
|
|
135
|
+
export type PlayerCatalog = Readonly<Record<string, string>>;
|
|
136
|
+
type PluralForm = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
|
|
137
|
+
type BaseKey<K extends string> = K extends `${infer B}.${PluralForm}` ? B : K;
|
|
138
|
+
/** Every key a component may ask for: the English catalog's keys with the plural suffix taken off. */
|
|
139
|
+
export type PlayerText = BaseKey<keyof typeof en>;
|
|
140
|
+
export type PlayerParams = Readonly<Record<string, string | number>>;
|
|
141
|
+
/** The `t` the components take: a key and optional values, always a string back. */
|
|
142
|
+
export type PlayerT = (key: PlayerText, params?: PlayerParams) => string;
|
|
143
|
+
/**
|
|
144
|
+
* Builds the `t` function for a catalog and a locale.
|
|
145
|
+
* - `{name}` is replaced by `params.name`; a name with no value stays as written; a value is never expanded again.
|
|
146
|
+
* - Numbers are formatted for the locale (`1,234`).
|
|
147
|
+
* - With a numeric `count`, the plural form for the locale is used (`key.one`, `key.other`, ...), `key.zero` for 0 if it
|
|
148
|
+
* exists, and `key.other` when the locale's form is missing.
|
|
149
|
+
* - A key with no text comes back as the key itself, so a gap in a translation is visible instead of blank.
|
|
150
|
+
*/
|
|
151
|
+
export declare function createT(catalog: PlayerCatalog, locale?: string): PlayerT;
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoEb,+DAA+D;;IAE/D,+DAA+D;;;IAG/D,+DAA+D;;;;;;;;;;IAU/D,+DAA+D;;;IAG/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;IAE/D,+DAA+D;;;;;;;;;IAS/D,+DAA+D;;;;;;;;;;;;;;;;;;CAkBvD,CAAC;AAEX,sFAAsF;AACtF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7D,KAAK,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AACpE,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAE9E,sGAAsG;AACtG,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAErE,oFAAoF;AACpF,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC;AAIzE;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAO,GAAG,OAAO,CAiCtE"}
|