brightspace-mcp-server 1.6.3 → 2.0.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.
Files changed (92) hide show
  1. package/README.md +34 -7
  2. package/build/api/client.d.ts +5 -3
  3. package/build/api/client.d.ts.map +1 -1
  4. package/build/api/client.js +71 -79
  5. package/build/api/client.js.map +1 -1
  6. package/build/api/errors.d.ts +4 -0
  7. package/build/api/errors.d.ts.map +1 -1
  8. package/build/api/errors.js +7 -0
  9. package/build/api/errors.js.map +1 -1
  10. package/build/auth/auth-cooldown.d.ts +16 -0
  11. package/build/auth/auth-cooldown.d.ts.map +1 -0
  12. package/build/auth/auth-cooldown.js +47 -0
  13. package/build/auth/auth-cooldown.js.map +1 -0
  14. package/build/auth/auth-lock.d.ts +7 -0
  15. package/build/auth/auth-lock.d.ts.map +1 -0
  16. package/build/auth/auth-lock.js +114 -0
  17. package/build/auth/auth-lock.js.map +1 -0
  18. package/build/auth/auth-runner.d.ts +17 -7
  19. package/build/auth/auth-runner.d.ts.map +1 -1
  20. package/build/auth/auth-runner.js +122 -26
  21. package/build/auth/auth-runner.js.map +1 -1
  22. package/build/auth/browser-auth.d.ts +17 -86
  23. package/build/auth/browser-auth.d.ts.map +1 -1
  24. package/build/auth/browser-auth.js +256 -615
  25. package/build/auth/browser-auth.js.map +1 -1
  26. package/build/auth/browser-state-store.d.ts +19 -0
  27. package/build/auth/browser-state-store.d.ts.map +1 -0
  28. package/build/auth/browser-state-store.js +101 -0
  29. package/build/auth/browser-state-store.js.map +1 -0
  30. package/build/auth/credential-store.d.ts +29 -0
  31. package/build/auth/credential-store.d.ts.map +1 -0
  32. package/build/auth/credential-store.js +233 -0
  33. package/build/auth/credential-store.js.map +1 -0
  34. package/build/auth/encrypted-store.d.ts +25 -0
  35. package/build/auth/encrypted-store.d.ts.map +1 -0
  36. package/build/auth/encrypted-store.js +61 -0
  37. package/build/auth/encrypted-store.js.map +1 -0
  38. package/build/auth/legacy-profile.d.ts +3 -0
  39. package/build/auth/legacy-profile.d.ts.map +1 -0
  40. package/build/auth/legacy-profile.js +41 -0
  41. package/build/auth/legacy-profile.js.map +1 -0
  42. package/build/auth/legacy-state.d.ts +14 -0
  43. package/build/auth/legacy-state.d.ts.map +1 -0
  44. package/build/auth/legacy-state.js +107 -0
  45. package/build/auth/legacy-state.js.map +1 -0
  46. package/build/auth/purdue-sso.d.ts +18 -36
  47. package/build/auth/purdue-sso.d.ts.map +1 -1
  48. package/build/auth/purdue-sso.js +165 -192
  49. package/build/auth/purdue-sso.js.map +1 -1
  50. package/build/auth/session-store.d.ts +16 -38
  51. package/build/auth/session-store.d.ts.map +1 -1
  52. package/build/auth/session-store.js +157 -152
  53. package/build/auth/session-store.js.map +1 -1
  54. package/build/auth/sso-flow.d.ts +14 -3
  55. package/build/auth/sso-flow.d.ts.map +1 -1
  56. package/build/auth/sso-flow.js +16 -1
  57. package/build/auth/sso-flow.js.map +1 -1
  58. package/build/auth/suny-sso.d.ts +3 -2
  59. package/build/auth/suny-sso.d.ts.map +1 -1
  60. package/build/auth/suny-sso.js +15 -24
  61. package/build/auth/suny-sso.js.map +1 -1
  62. package/build/auth/token-manager.d.ts +10 -3
  63. package/build/auth/token-manager.d.ts.map +1 -1
  64. package/build/auth/token-manager.js +62 -26
  65. package/build/auth/token-manager.js.map +1 -1
  66. package/build/auth/token-mint.d.ts +2 -2
  67. package/build/auth/token-mint.d.ts.map +1 -1
  68. package/build/auth/token-mint.js +31 -9
  69. package/build/auth/token-mint.js.map +1 -1
  70. package/build/auth-cli.d.ts +1 -7
  71. package/build/auth-cli.d.ts.map +1 -1
  72. package/build/auth-cli.js +29 -73
  73. package/build/auth-cli.js.map +1 -1
  74. package/build/index.js +8 -4
  75. package/build/index.js.map +1 -1
  76. package/build/setup.js +14 -8
  77. package/build/setup.js.map +1 -1
  78. package/build/types/index.d.ts +6 -0
  79. package/build/types/index.d.ts.map +1 -1
  80. package/build/utils/config-store.d.ts +1 -0
  81. package/build/utils/config-store.d.ts.map +1 -1
  82. package/build/utils/config-store.js +3 -0
  83. package/build/utils/config-store.js.map +1 -1
  84. package/build/utils/config.d.ts +2 -1
  85. package/build/utils/config.d.ts.map +1 -1
  86. package/build/utils/config.js +30 -10
  87. package/build/utils/config.js.map +1 -1
  88. package/build/utils/secure-config.d.ts +6 -0
  89. package/build/utils/secure-config.d.ts.map +1 -0
  90. package/build/utils/secure-config.js +57 -0
  91. package/build/utils/secure-config.js.map +1 -0
  92. package/package.json +4 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encrypted-store.js","sourceRoot":"","sources":["../../src/auth/encrypted-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Retire only the known v1 profile after both encrypted state and token persistence succeed. */
2
+ export declare function retireLegacyProfile(sessionDir: string): Promise<void>;
3
+ //# sourceMappingURL=legacy-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-profile.d.ts","sourceRoot":"","sources":["../../src/auth/legacy-profile.ts"],"names":[],"mappings":"AAMA,iGAAiG;AACjG,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B3E"}
@@ -0,0 +1,41 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ import trash from "trash";
5
+ import { log } from "../utils/logger.js";
6
+ /** Retire only the known v1 profile after both encrypted state and token persistence succeed. */
7
+ export async function retireLegacyProfile(sessionDir) {
8
+ const profile = path.join(sessionDir, "browser-data");
9
+ try {
10
+ const stat = await fs.lstat(profile);
11
+ if (!stat.isDirectory() || stat.isSymbolicLink())
12
+ return;
13
+ await fs.access(path.join(sessionDir, "storage-state.encrypted.json"));
14
+ try {
15
+ const owner = await fs.readlink(path.join(profile, "SingletonLock"));
16
+ const match = /^(.*)-(\d+)$/.exec(owner);
17
+ if (!match || match[1] !== os.hostname())
18
+ return;
19
+ try {
20
+ process.kill(Number(match[2]), 0);
21
+ return;
22
+ }
23
+ catch (error) {
24
+ if (error.code !== "ESRCH")
25
+ return;
26
+ }
27
+ }
28
+ catch (error) {
29
+ if (error.code !== "ENOENT")
30
+ return;
31
+ }
32
+ await trash([profile]);
33
+ log("INFO", "Moved the retired v1 browser-data profile to Trash. It can be restored there.");
34
+ }
35
+ catch (error) {
36
+ if (error.code !== "ENOENT") {
37
+ log("WARN", "Could not retire the inactive v1 browser profile. It was preserved.");
38
+ }
39
+ }
40
+ }
41
+ //# sourceMappingURL=legacy-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-profile.js","sourceRoot":"","sources":["../../src/auth/legacy-profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,OAAO;QACzD,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,8BAA8B,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;YACrE,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;gBAAE,OAAO;YACjD,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAClC,OAAO;YACT,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAK,KAA+B,CAAC,IAAI,KAAK,OAAO;oBAAE,OAAO;YAChE,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO;QACjE,CAAC;QACD,MAAM,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACvB,GAAG,CAAC,MAAM,EAAE,+EAA+E,CAAC,CAAC;IAC/F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,GAAG,CAAC,MAAM,EAAE,qEAAqE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT. See LICENSE file for details.
5
+ */
6
+ type StateDisposition = "absent" | "encrypted" | "preserved";
7
+ export interface LegacyMigrationResult {
8
+ tokenState: StateDisposition;
9
+ browserState: StateDisposition;
10
+ }
11
+ /** Secure v1 state in its original directory without assigning it to a new identity. */
12
+ export declare function migrateLegacyState(sessionRoot: string): Promise<LegacyMigrationResult>;
13
+ export {};
14
+ //# sourceMappingURL=legacy-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-state.d.ts","sourceRoot":"","sources":["../../src/auth/legacy-state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,KAAK,gBAAgB,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAC7D,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,gBAAgB,CAAC;CAChC;AAmCD,wFAAwF;AACxF,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAwD5F"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT. See LICENSE file for details.
5
+ */
6
+ import * as fs from "node:fs/promises";
7
+ import * as path from "node:path";
8
+ import { acquireProcessLock, AuthenticationInProgressError } from "./auth-lock.js";
9
+ import { BrowserStateStore } from "./browser-state-store.js";
10
+ import { NativeCredentialStoreError } from "./credential-store.js";
11
+ import { SessionStore } from "./session-store.js";
12
+ import { log } from "../utils/logger.js";
13
+ async function fileKind(root, name) {
14
+ try {
15
+ const stat = await fs.lstat(path.join(root, name));
16
+ return stat.isFile() && !stat.isSymbolicLink() ? "regular" : "unsafe";
17
+ }
18
+ catch (error) {
19
+ if (error.code === "ENOENT")
20
+ return "absent";
21
+ throw error;
22
+ }
23
+ }
24
+ function reportPreserved(label) {
25
+ log("WARN", `Legacy ${label} could not be migrated safely and was preserved in the original session directory. The new account will use a separate session.`);
26
+ }
27
+ async function migrate(label, operation) {
28
+ try {
29
+ await operation();
30
+ return "encrypted";
31
+ }
32
+ catch (error) {
33
+ if (error instanceof NativeCredentialStoreError || error instanceof AuthenticationInProgressError)
34
+ throw error;
35
+ reportPreserved(label);
36
+ return "preserved";
37
+ }
38
+ }
39
+ async function isV2Session(root) {
40
+ try {
41
+ return JSON.parse(await fs.readFile(path.join(root, "session.json"), "utf8")).version === 2;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ /** Secure v1 state in its original directory without assigning it to a new identity. */
48
+ export async function migrateLegacyState(sessionRoot) {
49
+ const names = ["session.json", "storage-state.json", "storage-state.encrypted.json"];
50
+ const kinds = await Promise.all(names.map((name) => fileKind(sessionRoot, name)));
51
+ if (kinds.every((kind) => kind === "absent"))
52
+ return { tokenState: "absent", browserState: "absent" };
53
+ const [token, plainBrowser, encryptedBrowser] = kinds;
54
+ const tokenAlreadyV2 = token === "regular" && await isV2Session(sessionRoot);
55
+ // Once migration is complete, validation is read-only and must not make
56
+ // concurrent MCP startups contend on the authentication lock.
57
+ if ((token === "absent" || token === "unsafe" || tokenAlreadyV2) && plainBrowser === "absent") {
58
+ let tokenState = "absent";
59
+ if (token === "unsafe") {
60
+ reportPreserved("token state");
61
+ tokenState = "preserved";
62
+ }
63
+ else if (tokenAlreadyV2) {
64
+ tokenState = await migrate("token state", () => new SessionStore(sessionRoot).load());
65
+ }
66
+ let browserState = "absent";
67
+ if (encryptedBrowser === "unsafe") {
68
+ reportPreserved("browser state");
69
+ browserState = "preserved";
70
+ }
71
+ else if (encryptedBrowser === "regular") {
72
+ browserState = await migrate("browser state", () => new BrowserStateStore(sessionRoot).load());
73
+ }
74
+ return { tokenState, browserState };
75
+ }
76
+ const release = await acquireProcessLock(path.join(sessionRoot, ".auth.lock"));
77
+ try {
78
+ const result = { tokenState: "absent", browserState: "absent" };
79
+ // Recheck under the process lock; never follow links into another directory.
80
+ const token = await fileKind(sessionRoot, "session.json");
81
+ if (token !== "absent") {
82
+ const salt = await fileKind(sessionRoot, "salt");
83
+ if (token === "unsafe" || salt === "unsafe") {
84
+ reportPreserved("token state");
85
+ result.tokenState = "preserved";
86
+ }
87
+ else {
88
+ result.tokenState = await migrate("token state", () => new SessionStore(sessionRoot).load());
89
+ }
90
+ }
91
+ const [plain, encrypted] = await Promise.all([
92
+ fileKind(sessionRoot, "storage-state.json"), fileKind(sessionRoot, "storage-state.encrypted.json"),
93
+ ]);
94
+ if (plain === "unsafe" || encrypted === "unsafe") {
95
+ reportPreserved("browser state");
96
+ result.browserState = "preserved";
97
+ }
98
+ else if (plain !== "absent" || encrypted !== "absent") {
99
+ result.browserState = await migrate("browser state", () => new BrowserStateStore(sessionRoot).load());
100
+ }
101
+ return result;
102
+ }
103
+ finally {
104
+ await release();
105
+ }
106
+ }
107
+ //# sourceMappingURL=legacy-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-state.js","sourceRoot":"","sources":["../../src/auth/legacy-state.ts"],"names":[],"mappings":"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"}
@@ -1,66 +1,48 @@
1
1
  /**
2
2
  * Purdue Brightspace MCP Server
3
3
  * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
- * Licensed under MIT — see LICENSE file for details.
4
+ * Licensed under MIT : see LICENSE file for details.
5
5
  */
6
6
  import type { Page } from "playwright";
7
7
  interface PurdueSSOConfig {
8
8
  username?: string;
9
9
  password?: string;
10
+ baseUrl?: string;
10
11
  }
11
12
  export declare class PurdueSSOFlow {
12
13
  private config;
14
+ private accountHintSubmitted;
13
15
  constructor(config: PurdueSSOConfig);
14
16
  /**
15
17
  * Returns true if credentials are available for automated SSO login.
16
18
  */
17
19
  hasCredentials(): boolean;
20
+ prepareLogin(page: Page): Promise<void>;
21
+ /** First half of Brightspace Bar's choreography, with no password access. */
22
+ identifyAccount(page: Page): Promise<boolean>;
18
23
  /**
19
24
  * Execute the complete Microsoft Entra ID SSO login flow for Purdue.
20
- * Handles institution selector, email/password entry, MFA (TOTP or manual), and "stay signed in" prompt.
25
+ * Handles the school selector, saved credentials, device MFA approval, and stay-signed-in.
21
26
  *
22
27
  * @param page - Playwright page instance (already navigated to Brightspace or redirected to login)
23
- * @returns true on successful login (URL contains /d2l/home), false on timeout/failure
28
+ * @returns true after reaching Brightspace home; failures are typed errors
24
29
  */
25
30
  login(page: Page): Promise<boolean>;
26
- /**
27
- * Manual login fallback: let the user type credentials and complete MFA themselves.
28
- * The browser stays open in headed mode while we wait for /d2l/home.
29
- */
30
- manualLogin(page: Page): Promise<boolean>;
31
31
  private handleCampusSelector;
32
32
  private enterCredentials;
33
- /**
34
- * Resolve a control only when it is actually on screen.
35
- *
36
- * Entra is a single-page app: the account-name view stays in the DOM once
37
- * the password view replaces it, so a plain page.$() returns the hidden
38
- * first-page input or button that precedes the live one in document order.
39
- * Filling or clicking those stalls on Playwright's actionability wait.
40
- */
41
- private findVisible;
42
- /**
43
- * Advance Microsoft Entra's account-name page.
44
- *
45
- * That page carries a password box of its own, and Playwright reports it as
46
- * visible, so presence cannot tell it apart from a single-page form. The
47
- * button label can: it reads "Next" there and "Sign in" on the view that
48
- * follows. Filling the password against the account-name page leaves the
49
- * browser parked with both fields populated and nothing submitted.
50
- */
51
- private submitAccountName;
33
+ /** Ported from Brightspace Bar's proven four-step Entra choreography. */
34
+ private actWhenReady;
35
+ private fillWhenReady;
36
+ private clickWhenReady;
37
+ /** Match Brightspace Bar's selector loop instead of trusting the first DOM match. */
38
+ private anyVisible;
39
+ /** Brightspace Bar's bounded number/auth/KMSI polling loop. */
52
40
  private handleMFA;
53
- /**
54
- * Log Entra's number-match digits until the MFA wait is over.
55
- *
56
- * Only a CHANGED value is logged: Entra re-mints the number whenever the
57
- * user asks for a new request, and repeating the same digits every two
58
- * seconds would bury everything else in the log.
59
- */
60
- private watchNumberMatch;
41
+ /** The login shell also exposes D2L.LP, so verify origin and home as well. */
42
+ private isAuthenticated;
43
+ private clickProvenKmsi;
61
44
  /** The digits on screen, or null when Entra is not showing any. */
62
45
  private readNumberMatch;
63
- private handleStaySignedIn;
64
46
  }
65
47
  export {};
66
48
  //# sourceMappingURL=purdue-sso.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"purdue-sso.d.ts","sourceRoot":"","sources":["../../src/auth/purdue-sso.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAiB,IAAI,EAAE,MAAM,YAAY,CAAC;AAyCtD,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;;;;;OAMG;IACG,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BzC;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;YAoBjC,oBAAoB;YAepB,gBAAgB;IAuD9B;;;;;;;OAOG;YACW,WAAW;IAUzB;;;;;;;;OAQG;YACW,iBAAiB;YAiBjB,SAAS;IA2CvB;;;;;;OAMG;YACW,gBAAgB;IAoB9B,mEAAmE;YACrD,eAAe;YASf,kBAAkB;CAiBjC"}
1
+ {"version":3,"file":"purdue-sso.d.ts","sourceRoot":"","sources":["../../src/auth/purdue-sso.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,YAAY,CAAC;AAyBhD,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,oBAAoB,CAAS;gBAEzB,MAAM,EAAE,eAAe;IAInC;;OAEG;IACH,cAAc,IAAI,OAAO;IAInB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,6EAA6E;IACvE,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IASnD;;;;;;OAMG;IACG,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;YA2B3B,oBAAoB;YAuBpB,gBAAgB;IAuB9B,yEAAyE;YAC3D,YAAY;YAeZ,aAAa;YAIb,cAAc;IAK5B,qFAAqF;YACvE,UAAU;IAOxB,+DAA+D;YACjD,SAAS;IAoCvB,8EAA8E;YAChE,eAAe;YAkBf,eAAe;IAa7B,mEAAmE;YACrD,eAAe;CAU9B"}