@webiny/api-file-manager-standalone 6.6.0-alpha.4

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 (128) hide show
  1. package/FileManagerStandaloneFeature.d.ts +5 -0
  2. package/FileManagerStandaloneFeature.js +41 -0
  3. package/FileManagerStandaloneFeature.js.map +1 -0
  4. package/LICENSE +21 -0
  5. package/README.md +11 -0
  6. package/assetDelivery/LazyLocalSharpTransform.d.ts +33 -0
  7. package/assetDelivery/LazyLocalSharpTransform.js +32 -0
  8. package/assetDelivery/LazyLocalSharpTransform.js.map +1 -0
  9. package/assetDelivery/LocalAssetResolver.d.ts +15 -0
  10. package/assetDelivery/LocalAssetResolver.js +40 -0
  11. package/assetDelivery/LocalAssetResolver.js.map +1 -0
  12. package/assetDelivery/LocalContentsReader.d.ts +7 -0
  13. package/assetDelivery/LocalContentsReader.js +18 -0
  14. package/assetDelivery/LocalContentsReader.js.map +1 -0
  15. package/assetDelivery/LocalOutputStrategy.d.ts +12 -0
  16. package/assetDelivery/LocalOutputStrategy.js +21 -0
  17. package/assetDelivery/LocalOutputStrategy.js.map +1 -0
  18. package/assetDelivery/LocalSharpTransform.d.ts +24 -0
  19. package/assetDelivery/LocalSharpTransform.js +161 -0
  20. package/assetDelivery/LocalSharpTransform.js.map +1 -0
  21. package/assetDelivery/abstractions.d.ts +8 -0
  22. package/assetDelivery/abstractions.js +6 -0
  23. package/assetDelivery/abstractions.js.map +1 -0
  24. package/assetDelivery/assetDeliveryConfig.d.ts +2 -0
  25. package/assetDelivery/assetDeliveryConfig.js +15 -0
  26. package/assetDelivery/assetDeliveryConfig.js.map +1 -0
  27. package/assetDelivery/createAssetDelivery.d.ts +3 -0
  28. package/assetDelivery/createAssetDelivery.js +7 -0
  29. package/assetDelivery/createAssetDelivery.js.map +1 -0
  30. package/assetDelivery/feature.d.ts +5 -0
  31. package/assetDelivery/feature.js +33 -0
  32. package/assetDelivery/feature.js.map +1 -0
  33. package/assetDelivery/types.d.ts +8 -0
  34. package/assetDelivery/types.js +0 -0
  35. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.d.ts +26 -0
  36. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js +71 -0
  37. package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js.map +1 -0
  38. package/features/CleanupStaleMultipartUploads/feature.d.ts +4 -0
  39. package/features/CleanupStaleMultipartUploads/feature.js +11 -0
  40. package/features/CleanupStaleMultipartUploads/feature.js.map +1 -0
  41. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.d.ts +13 -0
  42. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js +62 -0
  43. package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js.map +1 -0
  44. package/features/CompleteMultiPartUpload/feature.d.ts +4 -0
  45. package/features/CompleteMultiPartUpload/feature.js +11 -0
  46. package/features/CompleteMultiPartUpload/feature.js.map +1 -0
  47. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.d.ts +14 -0
  48. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js +58 -0
  49. package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js.map +1 -0
  50. package/features/CreateMultiPartUpload/feature.d.ts +4 -0
  51. package/features/CreateMultiPartUpload/feature.js +11 -0
  52. package/features/CreateMultiPartUpload/feature.js.map +1 -0
  53. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.d.ts +15 -0
  54. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js +34 -0
  55. package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js.map +1 -0
  56. package/features/DeleteFileFromDisk/feature.d.ts +4 -0
  57. package/features/DeleteFileFromDisk/feature.js +11 -0
  58. package/features/DeleteFileFromDisk/feature.js.map +1 -0
  59. package/features/ExtractMetadata/ExtractMetadataHandler.d.ts +1 -0
  60. package/features/ExtractMetadata/ExtractMetadataHandler.js +1 -0
  61. package/features/ExtractMetadata/ExtractMetadataTask.d.ts +29 -0
  62. package/features/ExtractMetadata/ExtractMetadataTask.js +93 -0
  63. package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -0
  64. package/features/ExtractMetadata/feature.d.ts +4 -0
  65. package/features/ExtractMetadata/feature.js +13 -0
  66. package/features/ExtractMetadata/feature.js.map +1 -0
  67. package/features/FileManagerStandaloneConfig/FileManagerStandaloneConfig.d.ts +12 -0
  68. package/features/FileManagerStandaloneConfig/FileManagerStandaloneConfig.js +28 -0
  69. package/features/FileManagerStandaloneConfig/FileManagerStandaloneConfig.js.map +1 -0
  70. package/features/FileManagerStandaloneConfig/abstractions.d.ts +10 -0
  71. package/features/FileManagerStandaloneConfig/abstractions.js +5 -0
  72. package/features/FileManagerStandaloneConfig/abstractions.js.map +1 -0
  73. package/features/FileManagerStandaloneConfig/feature.d.ts +4 -0
  74. package/features/FileManagerStandaloneConfig/feature.js +11 -0
  75. package/features/FileManagerStandaloneConfig/feature.js.map +1 -0
  76. package/features/FlushCache/FlushCacheOnFileBeforeUpdateHandler.d.ts +8 -0
  77. package/features/FlushCache/FlushCacheOnFileBeforeUpdateHandler.js +11 -0
  78. package/features/FlushCache/FlushCacheOnFileBeforeUpdateHandler.js.map +1 -0
  79. package/features/FlushCache/FlushCacheOnFileDeleteHandler.d.ts +8 -0
  80. package/features/FlushCache/FlushCacheOnFileDeleteHandler.js +11 -0
  81. package/features/FlushCache/FlushCacheOnFileDeleteHandler.js.map +1 -0
  82. package/features/FlushCache/feature.d.ts +4 -0
  83. package/features/FlushCache/feature.js +13 -0
  84. package/features/FlushCache/feature.js.map +1 -0
  85. package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +15 -0
  86. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +38 -0
  87. package/features/GetFileContentsById/GetFileContentsByIdUseCase.js.map +1 -0
  88. package/features/GetFileContentsById/feature.d.ts +4 -0
  89. package/features/GetFileContentsById/feature.js +11 -0
  90. package/features/GetFileContentsById/feature.js.map +1 -0
  91. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.d.ts +15 -0
  92. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +72 -0
  93. package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js.map +1 -0
  94. package/features/GetFileContentsByKey/feature.d.ts +4 -0
  95. package/features/GetFileContentsByKey/feature.js +11 -0
  96. package/features/GetFileContentsByKey/feature.js.map +1 -0
  97. package/features/GetUploadPayload/GetUploadPayloadUseCase.d.ts +16 -0
  98. package/features/GetUploadPayload/GetUploadPayloadUseCase.js +57 -0
  99. package/features/GetUploadPayload/GetUploadPayloadUseCase.js.map +1 -0
  100. package/features/GetUploadPayload/feature.d.ts +4 -0
  101. package/features/GetUploadPayload/feature.js +11 -0
  102. package/features/GetUploadPayload/feature.js.map +1 -0
  103. package/graphql/StandaloneGraphQLSchema.d.ts +15 -0
  104. package/graphql/StandaloneGraphQLSchema.js +221 -0
  105. package/graphql/StandaloneGraphQLSchema.js.map +1 -0
  106. package/index.d.ts +3 -0
  107. package/index.js +3 -0
  108. package/package.json +44 -0
  109. package/routes/UploadPartRoute/UploadPartRoute.d.ts +23 -0
  110. package/routes/UploadPartRoute/UploadPartRoute.js +71 -0
  111. package/routes/UploadPartRoute/UploadPartRoute.js.map +1 -0
  112. package/routes/UploadPartRoute/feature.d.ts +4 -0
  113. package/routes/UploadPartRoute/feature.js +11 -0
  114. package/routes/UploadPartRoute/feature.js.map +1 -0
  115. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.d.ts +23 -0
  116. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js +78 -0
  117. package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js.map +1 -0
  118. package/routes/UploadSingleFileRoute/feature.d.ts +4 -0
  119. package/routes/UploadSingleFileRoute/feature.js +11 -0
  120. package/routes/UploadSingleFileRoute/feature.js.map +1 -0
  121. package/routes/utils.d.ts +18 -0
  122. package/routes/utils.js +55 -0
  123. package/routes/utils.js.map +1 -0
  124. package/types.d.ts +10 -0
  125. package/types.js +1 -0
  126. package/utils/uploadToken.d.ts +3 -0
  127. package/utils/uploadToken.js +22 -0
  128. package/utils/uploadToken.js.map +1 -0
@@ -0,0 +1,18 @@
1
+ export declare const isPathContained: (filePath: string, storagePath: string) => boolean;
2
+ export declare const toBuffer: (body: unknown) => Buffer;
3
+ interface MultipartField {
4
+ name: string;
5
+ value: string;
6
+ }
7
+ interface MultipartFile {
8
+ name: string;
9
+ filename: string;
10
+ data: Buffer;
11
+ }
12
+ export interface MultipartResult {
13
+ fields: MultipartField[];
14
+ files: MultipartFile[];
15
+ }
16
+ export declare const parseMultipart: (buffer: Buffer, boundary: string) => MultipartResult;
17
+ export declare const getBoundary: (contentType: string) => string | undefined;
18
+ export {};
@@ -0,0 +1,55 @@
1
+ import node_path from "node:path";
2
+ const isPathContained = (filePath, storagePath)=>{
3
+ const resolved = node_path.resolve(filePath);
4
+ const root = node_path.resolve(storagePath);
5
+ return resolved === root || resolved.startsWith(root + node_path.sep);
6
+ };
7
+ const toBuffer = (body)=>{
8
+ if (Buffer.isBuffer(body)) return body;
9
+ if (body instanceof Uint8Array) return Buffer.from(body);
10
+ if ("string" == typeof body) return Buffer.from(body, "base64");
11
+ return Buffer.alloc(0);
12
+ };
13
+ const parseMultipart = (buffer, boundary)=>{
14
+ const fields = [];
15
+ const files = [];
16
+ const separator = Buffer.from(`--${boundary}`);
17
+ let idx = buffer.indexOf(separator);
18
+ while(-1 !== idx){
19
+ const next = buffer.indexOf(separator, idx + separator.length);
20
+ if (-1 === next) break;
21
+ let part = buffer.subarray(idx + separator.length, next);
22
+ if ("\r\n" === part.subarray(0, 2).toString("latin1")) part = part.subarray(2);
23
+ if ("\r\n" === part.subarray(-2).toString("latin1")) part = part.subarray(0, -2);
24
+ const headerEnd = part.indexOf("\r\n\r\n");
25
+ if (-1 !== headerEnd) {
26
+ const rawHeaders = part.subarray(0, headerEnd).toString("utf8");
27
+ const content = part.subarray(headerEnd + 4);
28
+ const disposition = /content-disposition:[^\r\n]*/i.exec(rawHeaders)?.[0] ?? "";
29
+ const name = /name="([^"]*)"/i.exec(disposition)?.[1];
30
+ const filename = /filename="([^"]*)"/i.exec(disposition)?.[1];
31
+ if (void 0 !== name) if (void 0 !== filename) files.push({
32
+ name,
33
+ filename,
34
+ data: content
35
+ });
36
+ else fields.push({
37
+ name,
38
+ value: content.toString("utf8")
39
+ });
40
+ }
41
+ idx = next;
42
+ }
43
+ return {
44
+ fields,
45
+ files
46
+ };
47
+ };
48
+ const getBoundary = (contentType)=>{
49
+ const match = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType);
50
+ const value = match?.[1] ?? match?.[2];
51
+ return value?.trim();
52
+ };
53
+ export { getBoundary, isPathContained, parseMultipart, toBuffer };
54
+
55
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes/utils.js","sources":["../../src/routes/utils.ts"],"sourcesContent":["import path from \"node:path\";\n\nexport const isPathContained = (filePath: string, storagePath: string): boolean => {\n const resolved = path.resolve(filePath);\n const root = path.resolve(storagePath);\n return resolved === root || resolved.startsWith(root + path.sep);\n};\n\n/* Normalise a transport request body into a Buffer. */\nexport const toBuffer = (body: unknown): Buffer => {\n if (Buffer.isBuffer(body)) {\n return body;\n }\n if (body instanceof Uint8Array) {\n return Buffer.from(body);\n }\n if (typeof body === \"string\") {\n return Buffer.from(body, \"base64\");\n }\n return Buffer.alloc(0);\n};\n\ninterface MultipartField {\n name: string;\n value: string;\n}\n\ninterface MultipartFile {\n name: string;\n filename: string;\n data: Buffer;\n}\n\nexport interface MultipartResult {\n fields: MultipartField[];\n files: MultipartFile[];\n}\n\n/* Minimal multipart/form-data parser operating on the raw body buffer. */\nexport const parseMultipart = (buffer: Buffer, boundary: string): MultipartResult => {\n const fields: MultipartField[] = [];\n const files: MultipartFile[] = [];\n const separator = Buffer.from(`--${boundary}`);\n\n let idx = buffer.indexOf(separator);\n while (idx !== -1) {\n const next = buffer.indexOf(separator, idx + separator.length);\n if (next === -1) {\n break;\n }\n\n let part = buffer.subarray(idx + separator.length, next);\n if (part.subarray(0, 2).toString(\"latin1\") === \"\\r\\n\") {\n part = part.subarray(2);\n }\n if (part.subarray(-2).toString(\"latin1\") === \"\\r\\n\") {\n part = part.subarray(0, -2);\n }\n\n const headerEnd = part.indexOf(\"\\r\\n\\r\\n\");\n if (headerEnd !== -1) {\n const rawHeaders = part.subarray(0, headerEnd).toString(\"utf8\");\n const content = part.subarray(headerEnd + 4);\n\n const disposition = /content-disposition:[^\\r\\n]*/i.exec(rawHeaders)?.[0] ?? \"\";\n const name = /name=\"([^\"]*)\"/i.exec(disposition)?.[1];\n const filename = /filename=\"([^\"]*)\"/i.exec(disposition)?.[1];\n\n if (name !== undefined) {\n if (filename !== undefined) {\n files.push({ name, filename, data: content });\n } else {\n fields.push({ name, value: content.toString(\"utf8\") });\n }\n }\n }\n\n idx = next;\n }\n\n return { fields, files };\n};\n\nexport const getBoundary = (contentType: string): string | undefined => {\n const match = /boundary=(?:\"([^\"]+)\"|([^;]+))/i.exec(contentType);\n const value = match?.[1] ?? match?.[2];\n return value?.trim();\n};\n"],"names":["isPathContained","filePath","storagePath","resolved","path","root","toBuffer","body","Buffer","Uint8Array","parseMultipart","buffer","boundary","fields","files","separator","idx","next","part","headerEnd","rawHeaders","content","disposition","name","filename","undefined","getBoundary","contentType","match","value"],"mappings":";AAEO,MAAMA,kBAAkB,CAACC,UAAkBC;IAC9C,MAAMC,WAAWC,UAAAA,OAAY,CAACH;IAC9B,MAAMI,OAAOD,UAAAA,OAAY,CAACF;IAC1B,OAAOC,aAAaE,QAAQF,SAAS,UAAU,CAACE,OAAOD,UAAAA,GAAQ;AACnE;AAGO,MAAME,WAAW,CAACC;IACrB,IAAIC,OAAO,QAAQ,CAACD,OAChB,OAAOA;IAEX,IAAIA,gBAAgBE,YAChB,OAAOD,OAAO,IAAI,CAACD;IAEvB,IAAI,AAAgB,YAAhB,OAAOA,MACP,OAAOC,OAAO,IAAI,CAACD,MAAM;IAE7B,OAAOC,OAAO,KAAK,CAAC;AACxB;AAmBO,MAAME,iBAAiB,CAACC,QAAgBC;IAC3C,MAAMC,SAA2B,EAAE;IACnC,MAAMC,QAAyB,EAAE;IACjC,MAAMC,YAAYP,OAAO,IAAI,CAAC,CAAC,EAAE,EAAEI,UAAU;IAE7C,IAAII,MAAML,OAAO,OAAO,CAACI;IACzB,MAAOC,AAAQ,OAARA,IAAY;QACf,MAAMC,OAAON,OAAO,OAAO,CAACI,WAAWC,MAAMD,UAAU,MAAM;QAC7D,IAAIE,AAAS,OAATA,MACA;QAGJ,IAAIC,OAAOP,OAAO,QAAQ,CAACK,MAAMD,UAAU,MAAM,EAAEE;QACnD,IAAIC,AAA2C,WAA3CA,KAAK,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,WAC7BA,OAAOA,KAAK,QAAQ,CAAC;QAEzB,IAAIA,AAAyC,WAAzCA,KAAK,QAAQ,CAAC,IAAI,QAAQ,CAAC,WAC3BA,OAAOA,KAAK,QAAQ,CAAC,GAAG;QAG5B,MAAMC,YAAYD,KAAK,OAAO,CAAC;QAC/B,IAAIC,AAAc,OAAdA,WAAkB;YAClB,MAAMC,aAAaF,KAAK,QAAQ,CAAC,GAAGC,WAAW,QAAQ,CAAC;YACxD,MAAME,UAAUH,KAAK,QAAQ,CAACC,YAAY;YAE1C,MAAMG,cAAc,gCAAgC,IAAI,CAACF,aAAa,CAAC,EAAE,IAAI;YAC7E,MAAMG,OAAO,kBAAkB,IAAI,CAACD,cAAc,CAAC,EAAE;YACrD,MAAME,WAAW,sBAAsB,IAAI,CAACF,cAAc,CAAC,EAAE;YAE7D,IAAIC,AAASE,WAATF,MACA,IAAIC,AAAaC,WAAbD,UACAV,MAAM,IAAI,CAAC;gBAAES;gBAAMC;gBAAU,MAAMH;YAAQ;iBAE3CR,OAAO,IAAI,CAAC;gBAAEU;gBAAM,OAAOF,QAAQ,QAAQ,CAAC;YAAQ;QAGhE;QAEAL,MAAMC;IACV;IAEA,OAAO;QAAEJ;QAAQC;IAAM;AAC3B;AAEO,MAAMY,cAAc,CAACC;IACxB,MAAMC,QAAQ,kCAAkC,IAAI,CAACD;IACrD,MAAME,QAAQD,OAAO,CAAC,EAAE,IAAIA,OAAO,CAAC,EAAE;IACtC,OAAOC,OAAO;AAClB"}
package/types.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import "@webiny/background-tasks/api/features/TaskController/augmentation.js";
2
+ export type { PresignedPostPayloadData } from "@webiny/api-file-manager/features/upload/index.js";
3
+ export type { FileData } from "@webiny/api-file-manager/features/upload/index.js";
4
+ export interface UploadTokenPayload {
5
+ key: string;
6
+ tenantId: string;
7
+ expiresAt: number;
8
+ uploadMinFileSize: number;
9
+ uploadMaxFileSize: number;
10
+ }
package/types.js ADDED
@@ -0,0 +1 @@
1
+ import "@webiny/background-tasks/api/features/TaskController/augmentation.js";
@@ -0,0 +1,3 @@
1
+ import type { UploadTokenPayload } from "../types.js";
2
+ export declare const createUploadToken: (payload: UploadTokenPayload, secret: string) => string;
3
+ export declare const verifyUploadToken: (token: string, secret: string) => UploadTokenPayload;
@@ -0,0 +1,22 @@
1
+ import { createHmac } from "node:crypto";
2
+ const createUploadToken = (payload, secret)=>{
3
+ const json = JSON.stringify(payload);
4
+ const encoded = Buffer.from(json).toString("base64url");
5
+ const signature = createHmac("sha256", secret).update(encoded).digest("base64url");
6
+ return `${encoded}.${signature}`;
7
+ };
8
+ const verifyUploadToken = (token, secret)=>{
9
+ const dotIndex = token.indexOf(".");
10
+ if (-1 === dotIndex) throw new Error("Invalid token format.");
11
+ const encoded = token.slice(0, dotIndex);
12
+ const signature = token.slice(dotIndex + 1);
13
+ const expectedSignature = createHmac("sha256", secret).update(encoded).digest("base64url");
14
+ if (signature !== expectedSignature) throw new Error("Invalid token signature.");
15
+ const json = Buffer.from(encoded, "base64url").toString("utf-8");
16
+ const payload = JSON.parse(json);
17
+ if (payload.expiresAt < Date.now()) throw new Error("Token has expired.");
18
+ return payload;
19
+ };
20
+ export { createUploadToken, verifyUploadToken };
21
+
22
+ //# sourceMappingURL=uploadToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils/uploadToken.js","sources":["../../src/utils/uploadToken.ts"],"sourcesContent":["import { createHmac } from \"node:crypto\";\nimport type { UploadTokenPayload } from \"~/types.js\";\n\nexport const createUploadToken = (payload: UploadTokenPayload, secret: string): string => {\n const json = JSON.stringify(payload);\n const encoded = Buffer.from(json).toString(\"base64url\");\n const signature = createHmac(\"sha256\", secret).update(encoded).digest(\"base64url\");\n\n return `${encoded}.${signature}`;\n};\n\nexport const verifyUploadToken = (token: string, secret: string): UploadTokenPayload => {\n const dotIndex = token.indexOf(\".\");\n if (dotIndex === -1) {\n throw new Error(\"Invalid token format.\");\n }\n\n const encoded = token.slice(0, dotIndex);\n const signature = token.slice(dotIndex + 1);\n\n const expectedSignature = createHmac(\"sha256\", secret).update(encoded).digest(\"base64url\");\n\n if (signature !== expectedSignature) {\n throw new Error(\"Invalid token signature.\");\n }\n\n const json = Buffer.from(encoded, \"base64url\").toString(\"utf-8\");\n const payload = JSON.parse(json) as UploadTokenPayload;\n\n if (payload.expiresAt < Date.now()) {\n throw new Error(\"Token has expired.\");\n }\n\n return payload;\n};\n"],"names":["createUploadToken","payload","secret","json","JSON","encoded","Buffer","signature","createHmac","verifyUploadToken","token","dotIndex","Error","expectedSignature","Date"],"mappings":";AAGO,MAAMA,oBAAoB,CAACC,SAA6BC;IAC3D,MAAMC,OAAOC,KAAK,SAAS,CAACH;IAC5B,MAAMI,UAAUC,OAAO,IAAI,CAACH,MAAM,QAAQ,CAAC;IAC3C,MAAMI,YAAYC,WAAW,UAAUN,QAAQ,MAAM,CAACG,SAAS,MAAM,CAAC;IAEtE,OAAO,GAAGA,QAAQ,CAAC,EAAEE,WAAW;AACpC;AAEO,MAAME,oBAAoB,CAACC,OAAeR;IAC7C,MAAMS,WAAWD,MAAM,OAAO,CAAC;IAC/B,IAAIC,AAAa,OAAbA,UACA,MAAM,IAAIC,MAAM;IAGpB,MAAMP,UAAUK,MAAM,KAAK,CAAC,GAAGC;IAC/B,MAAMJ,YAAYG,MAAM,KAAK,CAACC,WAAW;IAEzC,MAAME,oBAAoBL,WAAW,UAAUN,QAAQ,MAAM,CAACG,SAAS,MAAM,CAAC;IAE9E,IAAIE,cAAcM,mBACd,MAAM,IAAID,MAAM;IAGpB,MAAMT,OAAOG,OAAO,IAAI,CAACD,SAAS,aAAa,QAAQ,CAAC;IACxD,MAAMJ,UAAUG,KAAK,KAAK,CAACD;IAE3B,IAAIF,QAAQ,SAAS,GAAGa,KAAK,GAAG,IAC5B,MAAM,IAAIF,MAAM;IAGpB,OAAOX;AACX"}