@dollhousemcp/mcp-server 1.5.1 → 1.6.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 (274) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +497 -110
  3. package/data/agents/code-reviewer.md +8 -1
  4. package/data/agents/research-assistant.md +8 -1
  5. package/data/agents/task-manager.md +8 -1
  6. package/data/ensembles/business-advisor.md +8 -1
  7. package/data/ensembles/creative-studio.md +8 -1
  8. package/data/ensembles/development-team.md +8 -1
  9. package/data/ensembles/security-analysis-team.md +8 -1
  10. package/data/memories/conversation-history.md +8 -1
  11. package/data/memories/learning-progress.md +8 -1
  12. package/data/memories/project-context.md +8 -1
  13. package/data/personas/business-consultant.md +8 -1
  14. package/data/personas/creative-writer.md +8 -1
  15. package/data/personas/debug-detective.md +8 -1
  16. package/data/personas/eli5-explainer.md +8 -1
  17. package/data/personas/security-analyst.md +8 -1
  18. package/data/personas/technical-analyst.md +8 -1
  19. package/data/skills/code-review.md +8 -1
  20. package/data/skills/creative-writing.md +8 -1
  21. package/data/skills/data-analysis.md +8 -1
  22. package/data/skills/penetration-testing.md +8 -1
  23. package/data/skills/research.md +8 -1
  24. package/data/skills/threat-modeling.md +8 -1
  25. package/data/skills/translation.md +8 -1
  26. package/data/templates/code-documentation.md +8 -1
  27. package/data/templates/email-professional.md +8 -1
  28. package/data/templates/meeting-notes.md +8 -1
  29. package/data/templates/penetration-test-report.md +8 -1
  30. package/data/templates/project-brief.md +8 -1
  31. package/data/templates/report-executive.md +8 -1
  32. package/data/templates/security-vulnerability-report.md +8 -1
  33. package/data/templates/threat-assessment-report.md +8 -1
  34. package/dist/auth/GitHubAuthManager.d.ts +6 -1
  35. package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
  36. package/dist/auth/GitHubAuthManager.js +45 -18
  37. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
  38. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
  39. package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
  40. package/dist/cache/CollectionCache.d.ts +65 -0
  41. package/dist/cache/CollectionCache.d.ts.map +1 -0
  42. package/dist/cache/CollectionCache.js +172 -0
  43. package/dist/cache/CollectionIndexCache.d.ts +77 -0
  44. package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
  45. package/dist/cache/CollectionIndexCache.js +349 -0
  46. package/dist/cache/LRUCache.d.ts +93 -0
  47. package/dist/cache/LRUCache.d.ts.map +1 -0
  48. package/dist/cache/LRUCache.js +299 -0
  49. package/dist/cache/index.d.ts +2 -0
  50. package/dist/cache/index.d.ts.map +1 -1
  51. package/dist/cache/index.js +3 -1
  52. package/dist/collection/CollectionBrowser.d.ts +44 -1
  53. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  54. package/dist/collection/CollectionBrowser.js +260 -28
  55. package/dist/collection/CollectionIndexManager.d.ts +151 -0
  56. package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
  57. package/dist/collection/CollectionIndexManager.js +499 -0
  58. package/dist/collection/CollectionSearch.d.ts +75 -1
  59. package/dist/collection/CollectionSearch.d.ts.map +1 -1
  60. package/dist/collection/CollectionSearch.js +435 -6
  61. package/dist/collection/CollectionSeeder.d.ts +36 -0
  62. package/dist/collection/CollectionSeeder.d.ts.map +1 -0
  63. package/dist/collection/CollectionSeeder.js +267 -0
  64. package/dist/collection/ElementInstaller.d.ts +31 -0
  65. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  66. package/dist/collection/ElementInstaller.js +77 -15
  67. package/dist/collection/PersonaSubmitter.d.ts +48 -1
  68. package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
  69. package/dist/collection/PersonaSubmitter.js +170 -34
  70. package/dist/collection/index.d.ts +2 -0
  71. package/dist/collection/index.d.ts.map +1 -1
  72. package/dist/collection/index.js +3 -1
  73. package/dist/config/ConfigManager.d.ts +78 -0
  74. package/dist/config/ConfigManager.d.ts.map +1 -0
  75. package/dist/config/ConfigManager.js +216 -0
  76. package/dist/config/element-types.d.ts +135 -0
  77. package/dist/config/element-types.d.ts.map +1 -0
  78. package/dist/config/element-types.js +108 -0
  79. package/dist/config/index.d.ts +2 -0
  80. package/dist/config/index.d.ts.map +1 -1
  81. package/dist/config/index.js +3 -1
  82. package/dist/config/portfolio-constants.d.ts +83 -0
  83. package/dist/config/portfolio-constants.d.ts.map +1 -0
  84. package/dist/config/portfolio-constants.js +99 -0
  85. package/dist/elements/BaseElement.d.ts +14 -2
  86. package/dist/elements/BaseElement.d.ts.map +1 -1
  87. package/dist/elements/BaseElement.js +88 -6
  88. package/dist/elements/agents/Agent.d.ts +10 -1
  89. package/dist/elements/agents/Agent.d.ts.map +1 -1
  90. package/dist/elements/agents/Agent.js +66 -19
  91. package/dist/elements/agents/AgentManager.d.ts +2 -0
  92. package/dist/elements/agents/AgentManager.d.ts.map +1 -1
  93. package/dist/elements/agents/AgentManager.js +12 -10
  94. package/dist/elements/skills/Skill.d.ts +10 -1
  95. package/dist/elements/skills/Skill.d.ts.map +1 -1
  96. package/dist/elements/skills/Skill.js +40 -3
  97. package/dist/elements/skills/SkillManager.d.ts +1 -0
  98. package/dist/elements/skills/SkillManager.d.ts.map +1 -1
  99. package/dist/elements/skills/SkillManager.js +10 -4
  100. package/dist/elements/templates/Template.d.ts +10 -1
  101. package/dist/elements/templates/Template.d.ts.map +1 -1
  102. package/dist/elements/templates/Template.js +35 -18
  103. package/dist/elements/templates/TemplateManager.d.ts +1 -1
  104. package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
  105. package/dist/elements/templates/TemplateManager.js +6 -5
  106. package/dist/generated/version.d.ts +2 -2
  107. package/dist/generated/version.js +3 -3
  108. package/dist/index.barrel.d.ts +1 -2
  109. package/dist/index.barrel.d.ts.map +1 -1
  110. package/dist/index.barrel.js +2 -4
  111. package/dist/index.d.ts +154 -25
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +1951 -264
  114. package/dist/persona/PersonaElement.d.ts +10 -0
  115. package/dist/persona/PersonaElement.d.ts.map +1 -1
  116. package/dist/persona/PersonaElement.js +55 -32
  117. package/dist/persona/PersonaElementManager.d.ts.map +1 -1
  118. package/dist/persona/PersonaElementManager.js +13 -11
  119. package/dist/persona/PersonaLoader.d.ts.map +1 -1
  120. package/dist/persona/PersonaLoader.js +8 -2
  121. package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
  122. package/dist/persona/export-import/PersonaImporter.js +24 -5
  123. package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
  124. package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
  125. package/dist/persona/export-import/PersonaSharer.js +198 -22
  126. package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
  127. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
  128. package/dist/portfolio/DefaultElementProvider.js +499 -7
  129. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
  130. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
  131. package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
  132. package/dist/portfolio/MigrationManager.d.ts.map +1 -1
  133. package/dist/portfolio/MigrationManager.js +136 -3
  134. package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
  135. package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
  136. package/dist/portfolio/PortfolioIndexManager.js +478 -0
  137. package/dist/portfolio/PortfolioManager.d.ts +5 -0
  138. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  139. package/dist/portfolio/PortfolioManager.js +61 -20
  140. package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
  141. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
  142. package/dist/portfolio/PortfolioRepoManager.js +337 -0
  143. package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
  144. package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
  145. package/dist/portfolio/UnifiedIndexManager.js +1434 -0
  146. package/dist/portfolio/index.d.ts +15 -0
  147. package/dist/portfolio/index.d.ts.map +1 -0
  148. package/dist/portfolio/index.js +15 -0
  149. package/dist/portfolio/types.d.ts +7 -0
  150. package/dist/portfolio/types.d.ts.map +1 -1
  151. package/dist/portfolio/types.js +6 -1
  152. package/dist/security/InputValidator.d.ts.map +1 -1
  153. package/dist/security/InputValidator.js +50 -48
  154. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  155. package/dist/security/audit/SecurityAuditor.js +17 -9
  156. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  157. package/dist/security/audit/config/suppressions.js +19 -3
  158. package/dist/security/contentValidator.d.ts +2 -0
  159. package/dist/security/contentValidator.d.ts.map +1 -1
  160. package/dist/security/contentValidator.js +115 -4
  161. package/dist/security/secureYamlParser.d.ts +1 -0
  162. package/dist/security/secureYamlParser.d.ts.map +1 -1
  163. package/dist/security/secureYamlParser.js +29 -7
  164. package/dist/security/securityMonitor.d.ts +1 -1
  165. package/dist/security/securityMonitor.d.ts.map +1 -1
  166. package/dist/security/securityMonitor.js +1 -1
  167. package/dist/security/tokenManager.d.ts +1 -1
  168. package/dist/security/tokenManager.d.ts.map +1 -1
  169. package/dist/security/tokenManager.js +30 -10
  170. package/dist/server/ServerSetup.d.ts +22 -2
  171. package/dist/server/ServerSetup.d.ts.map +1 -1
  172. package/dist/server/ServerSetup.js +77 -12
  173. package/dist/server/tools/AuthTools.d.ts.map +1 -1
  174. package/dist/server/tools/AuthTools.js +33 -1
  175. package/dist/server/tools/BuildInfoTools.d.ts +25 -0
  176. package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
  177. package/dist/server/tools/BuildInfoTools.js +36 -0
  178. package/dist/server/tools/CollectionTools.d.ts.map +1 -1
  179. package/dist/server/tools/CollectionTools.js +62 -42
  180. package/dist/server/tools/ConfigTools.d.ts.map +1 -1
  181. package/dist/server/tools/ConfigTools.js +29 -1
  182. package/dist/server/tools/PersonaTools.d.ts +4 -2
  183. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  184. package/dist/server/tools/PersonaTools.js +5 -152
  185. package/dist/server/tools/PortfolioTools.d.ts +12 -0
  186. package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
  187. package/dist/server/tools/PortfolioTools.js +221 -0
  188. package/dist/server/tools/index.d.ts +3 -1
  189. package/dist/server/tools/index.d.ts.map +1 -1
  190. package/dist/server/tools/index.js +4 -2
  191. package/dist/server/types.d.ts +41 -5
  192. package/dist/server/types.d.ts.map +1 -1
  193. package/dist/server/types.js +1 -1
  194. package/dist/services/BuildInfoService.d.ts +84 -0
  195. package/dist/services/BuildInfoService.d.ts.map +1 -0
  196. package/dist/services/BuildInfoService.js +271 -0
  197. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
  198. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
  199. package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
  200. package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
  201. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
  202. package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
  203. package/dist/tools/portfolio/types.d.ts +41 -0
  204. package/dist/tools/portfolio/types.d.ts.map +1 -0
  205. package/dist/tools/portfolio/types.js +15 -0
  206. package/dist/types/collection.d.ts +51 -0
  207. package/dist/types/collection.d.ts.map +1 -1
  208. package/dist/types/collection.js +1 -1
  209. package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
  210. package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
  211. package/dist/utils/EarlyTerminationSearch.js +164 -0
  212. package/dist/utils/ErrorHandler.d.ts +86 -0
  213. package/dist/utils/ErrorHandler.d.ts.map +1 -0
  214. package/dist/utils/ErrorHandler.js +201 -0
  215. package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
  216. package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
  217. package/dist/utils/FileDiscoveryUtil.js +169 -0
  218. package/dist/utils/GitHubRateLimiter.d.ts +88 -0
  219. package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
  220. package/dist/utils/GitHubRateLimiter.js +315 -0
  221. package/dist/utils/PerformanceMonitor.d.ts +134 -0
  222. package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
  223. package/dist/utils/PerformanceMonitor.js +347 -0
  224. package/dist/utils/RateLimiter.d.ts.map +1 -0
  225. package/dist/utils/RateLimiter.js +172 -0
  226. package/dist/utils/SecureDownloader.d.ts +241 -0
  227. package/dist/utils/SecureDownloader.d.ts.map +1 -0
  228. package/dist/utils/SecureDownloader.js +759 -0
  229. package/dist/utils/ToolCache.d.ts +82 -0
  230. package/dist/utils/ToolCache.d.ts.map +1 -0
  231. package/dist/utils/ToolCache.js +196 -0
  232. package/dist/utils/errorCodes.d.ts +136 -0
  233. package/dist/utils/errorCodes.d.ts.map +1 -0
  234. package/dist/utils/errorCodes.js +87 -0
  235. package/dist/utils/index.d.ts +3 -0
  236. package/dist/utils/index.d.ts.map +1 -1
  237. package/dist/utils/index.js +4 -1
  238. package/dist/utils/installation.d.ts +1 -1
  239. package/dist/utils/installation.d.ts.map +1 -1
  240. package/dist/utils/installation.js +9 -8
  241. package/dist/utils/searchUtils.d.ts +54 -0
  242. package/dist/utils/searchUtils.d.ts.map +1 -0
  243. package/dist/utils/searchUtils.js +118 -0
  244. package/package.json +17 -7
  245. package/dist/config/updateConfig.d.ts +0 -84
  246. package/dist/config/updateConfig.d.ts.map +0 -1
  247. package/dist/config/updateConfig.js +0 -148
  248. package/dist/server/tools/UpdateTools.d.ts +0 -10
  249. package/dist/server/tools/UpdateTools.d.ts.map +0 -1
  250. package/dist/server/tools/UpdateTools.js +0 -85
  251. package/dist/update/BackupManager.d.ts +0 -63
  252. package/dist/update/BackupManager.d.ts.map +0 -1
  253. package/dist/update/BackupManager.js +0 -370
  254. package/dist/update/DependencyChecker.d.ts +0 -41
  255. package/dist/update/DependencyChecker.d.ts.map +0 -1
  256. package/dist/update/DependencyChecker.js +0 -132
  257. package/dist/update/RateLimiter.d.ts.map +0 -1
  258. package/dist/update/RateLimiter.js +0 -172
  259. package/dist/update/SignatureVerifier.d.ts +0 -71
  260. package/dist/update/SignatureVerifier.d.ts.map +0 -1
  261. package/dist/update/SignatureVerifier.js +0 -214
  262. package/dist/update/UpdateChecker.d.ts +0 -132
  263. package/dist/update/UpdateChecker.d.ts.map +0 -1
  264. package/dist/update/UpdateChecker.js +0 -506
  265. package/dist/update/UpdateManager.d.ts +0 -60
  266. package/dist/update/UpdateManager.d.ts.map +0 -1
  267. package/dist/update/UpdateManager.js +0 -730
  268. package/dist/update/VersionManager.d.ts +0 -31
  269. package/dist/update/VersionManager.d.ts.map +0 -1
  270. package/dist/update/VersionManager.js +0 -181
  271. package/dist/update/index.d.ts +0 -9
  272. package/dist/update/index.d.ts.map +0 -1
  273. package/dist/update/index.js +0 -9
  274. /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
@@ -1,19 +1,66 @@
1
1
  /**
2
2
  * Submit personas to the collection
3
+ * Handles both authenticated and anonymous submission workflows
4
+ *
5
+ * Security Features:
6
+ * - Rate limiting to prevent spam (5 submissions per hour per session)
7
+ * - URL length validation for GitHub limits
8
+ * - No email submission pathway (GitHub account required)
3
9
  */
4
10
  import { Persona } from '../types/persona.js';
11
+ import { RateLimitStatus } from '../utils/RateLimiter.js';
5
12
  export declare class PersonaSubmitter {
13
+ private rateLimiter;
14
+ constructor();
6
15
  /**
7
16
  * Generate GitHub issue for persona submission
17
+ * Includes URL length validation to comply with GitHub's ~8KB limit
8
18
  */
9
19
  generateSubmissionIssue(persona: Persona): {
10
20
  issueTitle: string;
11
21
  issueBody: string;
12
22
  githubIssueUrl: string;
23
+ rateLimitStatus?: RateLimitStatus;
13
24
  };
14
25
  /**
15
- * Format submission response
26
+ * Format submission response for authenticated users
16
27
  */
17
28
  formatSubmissionResponse(persona: Persona, githubIssueUrl: string, personaIndicator?: string): string;
29
+ /**
30
+ * Format anonymous submission response for unauthenticated users
31
+ */
32
+ formatAnonymousSubmissionResponse(persona: Persona, githubIssueUrl: string, personaIndicator?: string): string;
33
+ /**
34
+ * Build the full issue body with all persona details
35
+ */
36
+ private buildIssueBody;
37
+ /**
38
+ * Build a truncated issue body to fit within URL limits
39
+ */
40
+ private buildTruncatedIssueBody;
41
+ /**
42
+ * Serialize persona metadata to YAML format
43
+ */
44
+ private serializeMetadata;
45
+ /**
46
+ * Build the GitHub issue URL
47
+ */
48
+ private buildGitHubIssueUrl;
49
+ /**
50
+ * Build common response header used by both authenticated and anonymous responses
51
+ */
52
+ private buildResponseHeader;
53
+ /**
54
+ * Build standard submission steps for authenticated users
55
+ */
56
+ private buildStandardSubmissionSteps;
57
+ /**
58
+ * Build anonymous submission process instructions
59
+ */
60
+ private buildAnonymousSubmissionProcess;
61
+ /**
62
+ * Build anonymous submission next steps and expectations
63
+ */
64
+ private buildAnonymousNextSteps;
18
65
  }
19
66
  //# sourceMappingURL=PersonaSubmitter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PersonaSubmitter.d.ts","sourceRoot":"","sources":["../../src/collection/PersonaSubmitter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG;QACzC,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAA;KACvB;IAqCD;;OAEG;IACH,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAW,GAAG,MAAM;CAW1G"}
1
+ {"version":3,"file":"PersonaSubmitter.d.ts","sourceRoot":"","sources":["../../src/collection/PersonaSubmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAe,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAgBvE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAc;;IAUjC;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG;QACzC,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,eAAe,CAAC;KACnC;IAsCD;;OAEG;IACH,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAW,GAAG,MAAM;IAczG;;OAEG;IACH,iCAAiC,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAW,GAAG,MAAM;IAiBlH;;OAEG;IACH,OAAO,CAAC,cAAc;IAqBtB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAyB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,4BAA4B;IASpC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IAYvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAOhC"}
@@ -1,57 +1,193 @@
1
1
  /**
2
2
  * Submit personas to the collection
3
+ * Handles both authenticated and anonymous submission workflows
4
+ *
5
+ * Security Features:
6
+ * - Rate limiting to prevent spam (5 submissions per hour per session)
7
+ * - URL length validation for GitHub limits
8
+ * - No email submission pathway (GitHub account required)
3
9
  */
10
+ import { RateLimiter } from '../utils/RateLimiter.js';
11
+ import { SecurityMonitor } from '../security/securityMonitor.js';
12
+ // Configuration constants
13
+ const GITHUB_URL_LIMIT = 8192; // GitHub's URL length limit (~8KB)
14
+ const COLLECTION_REPO_OWNER = 'DollhouseMCP';
15
+ const COLLECTION_REPO_NAME = 'collection';
16
+ // Common response components
17
+ const RESPONSE_COMPONENTS = {
18
+ SUBMISSION_ICON: '📤',
19
+ PERSONA_ICON: '🎭',
20
+ TIP_ICON: '⭐',
21
+ PRO_TIP_ICON: '💡'
22
+ };
4
23
  export class PersonaSubmitter {
24
+ rateLimiter;
25
+ constructor() {
26
+ // Initialize rate limiter: 5 submissions per hour
27
+ this.rateLimiter = new RateLimiter({
28
+ maxRequests: 5,
29
+ windowMs: 60 * 60 * 1000, // 1 hour
30
+ minDelayMs: 10000 // Minimum 10 seconds between submissions
31
+ });
32
+ }
5
33
  /**
6
34
  * Generate GitHub issue for persona submission
35
+ * Includes URL length validation to comply with GitHub's ~8KB limit
7
36
  */
8
37
  generateSubmissionIssue(persona) {
38
+ // Check rate limit
39
+ const rateLimitStatus = this.rateLimiter.checkLimit();
40
+ if (!rateLimitStatus.allowed) {
41
+ // Log potential abuse attempt
42
+ SecurityMonitor.logSecurityEvent({
43
+ type: 'RATE_LIMIT_EXCEEDED',
44
+ severity: 'MEDIUM',
45
+ source: 'PersonaSubmitter.generateSubmissionIssue',
46
+ details: `Submission rate limit exceeded. Retry after ${rateLimitStatus.retryAfterMs}ms`
47
+ });
48
+ throw new Error(`Submission rate limit exceeded. Please wait ${Math.ceil(rateLimitStatus.retryAfterMs / 1000)} seconds before submitting again. ` +
49
+ `This limit helps prevent spam and ensures quality submissions.`);
50
+ }
9
51
  const issueTitle = `New Persona Submission: ${persona.metadata.name}`;
10
- const issueBody = `## Persona Submission
11
-
12
- **Name:** ${persona.metadata.name}
13
- **Author:** ${persona.metadata.author || 'Unknown'}
14
- **Category:** ${persona.metadata.category || 'General'}
15
- **Description:** ${persona.metadata.description}
16
-
17
- ### Persona Content:
18
- \`\`\`markdown
19
- ---
20
- ${Object.entries(persona.metadata)
21
- .map(([key, value]) => `${key}: ${Array.isArray(value) ? JSON.stringify(value) : JSON.stringify(value)}`)
22
- .join('\n')}
23
- ---
24
-
25
- ${persona.content}
26
- \`\`\`
27
-
28
- ### Submission Details:
29
- - Submitted via DollhouseMCP client
30
- - Filename: ${persona.filename}
31
- - Unique ID: ${persona.unique_id}
32
-
33
- ---
34
- *Please review this persona for inclusion in the collection.*`;
35
- const githubIssueUrl = `https://github.com/DollhouseMCP/collection/issues/new?title=${encodeURIComponent(issueTitle)}&body=${encodeURIComponent(issueBody)}`;
52
+ let issueBody = this.buildIssueBody(persona);
53
+ // Check URL length and truncate if necessary
54
+ let githubIssueUrl = this.buildGitHubIssueUrl(issueTitle, issueBody);
55
+ // If URL exceeds GitHub's limit, truncate the content
56
+ if (githubIssueUrl.length >= GITHUB_URL_LIMIT) {
57
+ issueBody = this.buildTruncatedIssueBody(persona);
58
+ githubIssueUrl = this.buildGitHubIssueUrl(issueTitle, issueBody);
59
+ }
36
60
  return {
37
61
  issueTitle,
38
62
  issueBody,
39
- githubIssueUrl
63
+ githubIssueUrl,
64
+ rateLimitStatus
40
65
  };
41
66
  }
42
67
  /**
43
- * Format submission response
68
+ * Format submission response for authenticated users
44
69
  */
45
70
  formatSubmissionResponse(persona, githubIssueUrl, personaIndicator = '') {
46
- return `${personaIndicator}📤 **Persona Submission Prepared**\n\n` +
47
- `🎭 **${persona.metadata.name}** is ready for collection submission!\n\n` +
48
- `**Next Steps:**\n` +
71
+ const header = this.buildResponseHeader('Persona Submission Prepared', persona.metadata.name, 'is ready for collection submission!', personaIndicator);
72
+ const steps = this.buildStandardSubmissionSteps(githubIssueUrl);
73
+ const tip = `${RESPONSE_COMPONENTS.TIP_ICON} **Tip:** You can also submit via pull request if you're familiar with Git!`;
74
+ return `${header}\n\n${steps}\n\n${tip}`;
75
+ }
76
+ /**
77
+ * Format anonymous submission response for unauthenticated users
78
+ */
79
+ formatAnonymousSubmissionResponse(persona, githubIssueUrl, personaIndicator = '') {
80
+ const header = this.buildResponseHeader('Anonymous Submission Path Available', persona.metadata.name, 'can be submitted without GitHub authentication!', personaIndicator);
81
+ const process = this.buildAnonymousSubmissionProcess(githubIssueUrl);
82
+ const nextSteps = this.buildAnonymousNextSteps();
83
+ const proTip = `${RESPONSE_COMPONENTS.PRO_TIP_ICON} **Pro tip:** Creating a free GitHub account unlocks additional features, but it's completely optional for submissions!`;
84
+ return `${header}\n\n${process}\n\n${nextSteps}\n\n${proTip}`;
85
+ }
86
+ // Private helper methods for building response components
87
+ /**
88
+ * Build the full issue body with all persona details
89
+ */
90
+ buildIssueBody(persona) {
91
+ return `## Persona Submission\n\n` +
92
+ `**Name:** ${persona.metadata.name}\n` +
93
+ `**Author:** ${persona.metadata.author || 'Unknown'}\n` +
94
+ `**Category:** ${persona.metadata.category || 'General'}\n` +
95
+ `**Description:** ${persona.metadata.description}\n\n` +
96
+ `### Persona Content:\n` +
97
+ `\`\`\`markdown\n` +
98
+ `---\n` +
99
+ `${this.serializeMetadata(persona.metadata)}\n` +
100
+ `---\n\n` +
101
+ `${persona.content}\n` +
102
+ `\`\`\`\n\n` +
103
+ `### Submission Details:\n` +
104
+ `- Submitted via DollhouseMCP client\n` +
105
+ `- Filename: ${persona.filename}\n` +
106
+ `- Unique ID: ${persona.unique_id}\n\n` +
107
+ `---\n` +
108
+ `*Please review this persona for inclusion in the collection.*`;
109
+ }
110
+ /**
111
+ * Build a truncated issue body to fit within URL limits
112
+ */
113
+ buildTruncatedIssueBody(persona) {
114
+ const truncatedContent = persona.content.length > 500
115
+ ? `${persona.content.substring(0, 500)}...\n\n[Content truncated due to length]`
116
+ : persona.content;
117
+ return `## Persona Submission\n\n` +
118
+ `**Name:** ${persona.metadata.name}\n` +
119
+ `**Author:** ${persona.metadata.author || 'Unknown'}\n` +
120
+ `**Category:** ${persona.metadata.category || 'General'}\n` +
121
+ `**Description:** ${persona.metadata.description}\n\n` +
122
+ `### Persona Content (Truncated):\n` +
123
+ `\`\`\`markdown\n` +
124
+ `---\n` +
125
+ `${this.serializeMetadata(persona.metadata)}\n` +
126
+ `---\n\n` +
127
+ `${truncatedContent}\n` +
128
+ `\`\`\`\n\n` +
129
+ `### Submission Details:\n` +
130
+ `- Submitted via DollhouseMCP client\n` +
131
+ `- Filename: ${persona.filename}\n` +
132
+ `- Unique ID: ${persona.unique_id}\n\n` +
133
+ `---\n` +
134
+ `*Please review this persona for inclusion in the collection.*`;
135
+ }
136
+ /**
137
+ * Serialize persona metadata to YAML format
138
+ */
139
+ serializeMetadata(metadata) {
140
+ return Object.entries(metadata)
141
+ .map(([key, value]) => `${key}: ${Array.isArray(value) ? JSON.stringify(value) : JSON.stringify(value)}`)
142
+ .join('\n');
143
+ }
144
+ /**
145
+ * Build the GitHub issue URL
146
+ */
147
+ buildGitHubIssueUrl(title, body) {
148
+ return `https://github.com/${COLLECTION_REPO_OWNER}/${COLLECTION_REPO_NAME}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`;
149
+ }
150
+ /**
151
+ * Build common response header used by both authenticated and anonymous responses
152
+ */
153
+ buildResponseHeader(title, personaName, subtitle, personaIndicator) {
154
+ return `${personaIndicator}${RESPONSE_COMPONENTS.SUBMISSION_ICON} **${title}**\n\n` +
155
+ `${RESPONSE_COMPONENTS.PERSONA_ICON} **${personaName}** ${subtitle}`;
156
+ }
157
+ /**
158
+ * Build standard submission steps for authenticated users
159
+ */
160
+ buildStandardSubmissionSteps(githubIssueUrl) {
161
+ return `**Next Steps:**\n` +
49
162
  `1. Click this link to create a GitHub issue: \n` +
50
163
  ` ${githubIssueUrl}\n\n` +
51
164
  `2. Review the pre-filled content\n` +
52
165
  `3. Click "Submit new issue"\n` +
53
- `4. The maintainers will review your submission\n\n` +
54
- `⭐ **Tip:** You can also submit via pull request if you're familiar with Git!`;
166
+ `4. The maintainers will review your submission`;
167
+ }
168
+ /**
169
+ * Build anonymous submission process instructions
170
+ */
171
+ buildAnonymousSubmissionProcess(githubIssueUrl) {
172
+ return `**Anonymous Submission Process:**\n` +
173
+ `1. Click this link to create a GitHub issue:\n` +
174
+ ` ${githubIssueUrl}\n\n` +
175
+ `2. **To submit your persona:**\n` +
176
+ ` • You'll need a GitHub account (free to create)\n` +
177
+ ` • Click "Submit new issue" to submit directly\n` +
178
+ ` • The form is pre-filled with all your persona details\n\n` +
179
+ `**Note:** GitHub account is required for submission to prevent spam and maintain quality.\n` +
180
+ `Creating an account is free and takes less than a minute: https://github.com/signup`;
181
+ }
182
+ /**
183
+ * Build anonymous submission next steps and expectations
184
+ */
185
+ buildAnonymousNextSteps() {
186
+ return `**What happens next:**\n` +
187
+ `• Community maintainers review all submissions\n` +
188
+ `• Anonymous submissions get the same consideration as authenticated ones\n` +
189
+ `• If accepted, your persona joins the collection with attribution to "Community Contributor"\n` +
190
+ `• The review typically takes 2-3 business days`;
55
191
  }
56
192
  }
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYVN1Ym1pdHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL1BlcnNvbmFTdWJtaXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFJSCxNQUFNLE9BQU8sZ0JBQWdCO0lBQzNCOztPQUVHO0lBQ0gsdUJBQXVCLENBQUMsT0FBZ0I7UUFLdEMsTUFBTSxVQUFVLEdBQUcsMkJBQTJCLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEUsTUFBTSxTQUFTLEdBQUc7O1lBRVYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJO2NBQ25CLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxJQUFJLFNBQVM7Z0JBQ2xDLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxJQUFJLFNBQVM7bUJBQ25DLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVzs7Ozs7RUFLN0MsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO2FBQy9CLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsS0FBSyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7YUFDeEcsSUFBSSxDQUFDLElBQUksQ0FBQzs7O0VBR1gsT0FBTyxDQUFDLE9BQU87Ozs7O2NBS0gsT0FBTyxDQUFDLFFBQVE7ZUFDZixPQUFPLENBQUMsU0FBUzs7OzhEQUc4QixDQUFDO1FBRTNELE1BQU0sY0FBYyxHQUFHLCtEQUErRCxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsU0FBUyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBRTdKLE9BQU87WUFDTCxVQUFVO1lBQ1YsU0FBUztZQUNULGNBQWM7U0FDZixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0gsd0JBQXdCLENBQUMsT0FBZ0IsRUFBRSxjQUFzQixFQUFFLG1CQUEyQixFQUFFO1FBQzlGLE9BQU8sR0FBRyxnQkFBZ0Isd0NBQXdDO1lBQ2hFLFFBQVEsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLDRDQUE0QztZQUN6RSxtQkFBbUI7WUFDbkIsaURBQWlEO1lBQ2pELE1BQU0sY0FBYyxNQUFNO1lBQzFCLG9DQUFvQztZQUNwQywrQkFBK0I7WUFDL0Isb0RBQW9EO1lBQ3BELDhFQUE4RSxDQUFDO0lBQ25GLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3VibWl0IHBlcnNvbmFzIHRvIHRoZSBjb2xsZWN0aW9uXG4gKi9cblxuaW1wb3J0IHsgUGVyc29uYSB9IGZyb20gJy4uL3R5cGVzL3BlcnNvbmEuanMnO1xuXG5leHBvcnQgY2xhc3MgUGVyc29uYVN1Ym1pdHRlciB7XG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBHaXRIdWIgaXNzdWUgZm9yIHBlcnNvbmEgc3VibWlzc2lvblxuICAgKi9cbiAgZ2VuZXJhdGVTdWJtaXNzaW9uSXNzdWUocGVyc29uYTogUGVyc29uYSk6IHsgXG4gICAgaXNzdWVUaXRsZTogc3RyaW5nOyBcbiAgICBpc3N1ZUJvZHk6IHN0cmluZzsgXG4gICAgZ2l0aHViSXNzdWVVcmw6IHN0cmluZyBcbiAgfSB7XG4gICAgY29uc3QgaXNzdWVUaXRsZSA9IGBOZXcgUGVyc29uYSBTdWJtaXNzaW9uOiAke3BlcnNvbmEubWV0YWRhdGEubmFtZX1gO1xuICAgIGNvbnN0IGlzc3VlQm9keSA9IGAjIyBQZXJzb25hIFN1Ym1pc3Npb25cblxuKipOYW1lOioqICR7cGVyc29uYS5tZXRhZGF0YS5uYW1lfVxuKipBdXRob3I6KiogJHtwZXJzb25hLm1ldGFkYXRhLmF1dGhvciB8fCAnVW5rbm93bid9XG4qKkNhdGVnb3J5OioqICR7cGVyc29uYS5tZXRhZGF0YS5jYXRlZ29yeSB8fCAnR2VuZXJhbCd9XG4qKkRlc2NyaXB0aW9uOioqICR7cGVyc29uYS5tZXRhZGF0YS5kZXNjcmlwdGlvbn1cblxuIyMjIFBlcnNvbmEgQ29udGVudDpcblxcYFxcYFxcYG1hcmtkb3duXG4tLS1cbiR7T2JqZWN0LmVudHJpZXMocGVyc29uYS5tZXRhZGF0YSlcbiAgLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBgJHtrZXl9OiAke0FycmF5LmlzQXJyYXkodmFsdWUpID8gSlNPTi5zdHJpbmdpZnkodmFsdWUpIDogSlNPTi5zdHJpbmdpZnkodmFsdWUpfWApXG4gIC5qb2luKCdcXG4nKX1cbi0tLVxuXG4ke3BlcnNvbmEuY29udGVudH1cblxcYFxcYFxcYFxuXG4jIyMgU3VibWlzc2lvbiBEZXRhaWxzOlxuLSBTdWJtaXR0ZWQgdmlhIERvbGxob3VzZU1DUCBjbGllbnRcbi0gRmlsZW5hbWU6ICR7cGVyc29uYS5maWxlbmFtZX1cbi0gVW5pcXVlIElEOiAke3BlcnNvbmEudW5pcXVlX2lkfVxuXG4tLS1cbipQbGVhc2UgcmV2aWV3IHRoaXMgcGVyc29uYSBmb3IgaW5jbHVzaW9uIGluIHRoZSBjb2xsZWN0aW9uLipgO1xuICAgIFxuICAgIGNvbnN0IGdpdGh1Yklzc3VlVXJsID0gYGh0dHBzOi8vZ2l0aHViLmNvbS9Eb2xsaG91c2VNQ1AvY29sbGVjdGlvbi9pc3N1ZXMvbmV3P3RpdGxlPSR7ZW5jb2RlVVJJQ29tcG9uZW50KGlzc3VlVGl0bGUpfSZib2R5PSR7ZW5jb2RlVVJJQ29tcG9uZW50KGlzc3VlQm9keSl9YDtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgaXNzdWVUaXRsZSxcbiAgICAgIGlzc3VlQm9keSxcbiAgICAgIGdpdGh1Yklzc3VlVXJsXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEZvcm1hdCBzdWJtaXNzaW9uIHJlc3BvbnNlXG4gICAqL1xuICBmb3JtYXRTdWJtaXNzaW9uUmVzcG9uc2UocGVyc29uYTogUGVyc29uYSwgZ2l0aHViSXNzdWVVcmw6IHN0cmluZywgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHtwZXJzb25hSW5kaWNhdG9yffCfk6QgKipQZXJzb25hIFN1Ym1pc3Npb24gUHJlcGFyZWQqKlxcblxcbmAgK1xuICAgICAgYPCfjq0gKioke3BlcnNvbmEubWV0YWRhdGEubmFtZX0qKiBpcyByZWFkeSBmb3IgY29sbGVjdGlvbiBzdWJtaXNzaW9uIVxcblxcbmAgK1xuICAgICAgYCoqTmV4dCBTdGVwczoqKlxcbmAgK1xuICAgICAgYDEuIENsaWNrIHRoaXMgbGluayB0byBjcmVhdGUgYSBHaXRIdWIgaXNzdWU6IFxcbmAgK1xuICAgICAgYCAgICR7Z2l0aHViSXNzdWVVcmx9XFxuXFxuYCArXG4gICAgICBgMi4gUmV2aWV3IHRoZSBwcmUtZmlsbGVkIGNvbnRlbnRcXG5gICtcbiAgICAgIGAzLiBDbGljayBcIlN1Ym1pdCBuZXcgaXNzdWVcIlxcbmAgK1xuICAgICAgYDQuIFRoZSBtYWludGFpbmVycyB3aWxsIHJldmlldyB5b3VyIHN1Ym1pc3Npb25cXG5cXG5gICtcbiAgICAgIGDirZAgKipUaXA6KiogWW91IGNhbiBhbHNvIHN1Ym1pdCB2aWEgcHVsbCByZXF1ZXN0IGlmIHlvdSdyZSBmYW1pbGlhciB3aXRoIEdpdCFgO1xuICB9XG59Il19
193
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyc29uYVN1Ym1pdHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsZWN0aW9uL1BlcnNvbmFTdWJtaXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0dBUUc7QUFHSCxPQUFPLEVBQUUsV0FBVyxFQUFtQixNQUFNLHlCQUF5QixDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVqRSwwQkFBMEI7QUFDMUIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsQ0FBQyxtQ0FBbUM7QUFDbEUsTUFBTSxxQkFBcUIsR0FBRyxjQUFjLENBQUM7QUFDN0MsTUFBTSxvQkFBb0IsR0FBRyxZQUFZLENBQUM7QUFFMUMsNkJBQTZCO0FBQzdCLE1BQU0sbUJBQW1CLEdBQUc7SUFDMUIsZUFBZSxFQUFFLElBQUk7SUFDckIsWUFBWSxFQUFFLElBQUk7SUFDbEIsUUFBUSxFQUFFLEdBQUc7SUFDYixZQUFZLEVBQUUsSUFBSTtDQUNWLENBQUM7QUFFWCxNQUFNLE9BQU8sZ0JBQWdCO0lBQ25CLFdBQVcsQ0FBYztJQUVqQztRQUNFLGtEQUFrRDtRQUNsRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksV0FBVyxDQUFDO1lBQ2pDLFdBQVcsRUFBRSxDQUFDO1lBQ2QsUUFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxFQUFFLFNBQVM7WUFDbkMsVUFBVSxFQUFFLEtBQUssQ0FBQyx5Q0FBeUM7U0FDNUQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNEOzs7T0FHRztJQUNILHVCQUF1QixDQUFDLE9BQWdCO1FBTXRDLG1CQUFtQjtRQUNuQixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRXRELElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDN0IsOEJBQThCO1lBQzlCLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDL0IsSUFBSSxFQUFFLHFCQUFxQjtnQkFDM0IsUUFBUSxFQUFFLFFBQVE7Z0JBQ2xCLE1BQU0sRUFBRSwwQ0FBMEM7Z0JBQ2xELE9BQU8sRUFBRSwrQ0FBK0MsZUFBZSxDQUFDLFlBQVksSUFBSTthQUN6RixDQUFDLENBQUM7WUFFSCxNQUFNLElBQUksS0FBSyxDQUNiLCtDQUErQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFhLEdBQUcsSUFBSSxDQUFDLG9DQUFvQztnQkFDbEksZ0VBQWdFLENBQ2pFLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxVQUFVLEdBQUcsMkJBQTJCLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEUsSUFBSSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3Qyw2Q0FBNkM7UUFDN0MsSUFBSSxjQUFjLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUVyRSxzREFBc0Q7UUFDdEQsSUFBSSxjQUFjLENBQUMsTUFBTSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDOUMsU0FBUyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsRCxjQUFjLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBRUQsT0FBTztZQUNMLFVBQVU7WUFDVixTQUFTO1lBQ1QsY0FBYztZQUNkLGVBQWU7U0FDaEIsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILHdCQUF3QixDQUFDLE9BQWdCLEVBQUUsY0FBc0IsRUFBRSxtQkFBMkIsRUFBRTtRQUM5RixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQ3JDLDZCQUE2QixFQUM3QixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksRUFDckIscUNBQXFDLEVBQ3JDLGdCQUFnQixDQUNqQixDQUFDO1FBRUYsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLDRCQUE0QixDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2hFLE1BQU0sR0FBRyxHQUFHLEdBQUcsbUJBQW1CLENBQUMsUUFBUSw2RUFBNkUsQ0FBQztRQUV6SCxPQUFPLEdBQUcsTUFBTSxPQUFPLEtBQUssT0FBTyxHQUFHLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxpQ0FBaUMsQ0FBQyxPQUFnQixFQUFFLGNBQXNCLEVBQUUsbUJBQTJCLEVBQUU7UUFDdkcsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUNyQyxxQ0FBcUMsRUFDckMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQ3JCLGlEQUFpRCxFQUNqRCxnQkFBZ0IsQ0FDakIsQ0FBQztRQUVGLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUNyRSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUNqRCxNQUFNLE1BQU0sR0FBRyxHQUFHLG1CQUFtQixDQUFDLFlBQVkseUhBQXlILENBQUM7UUFFNUssT0FBTyxHQUFHLE1BQU0sT0FBTyxPQUFPLE9BQU8sU0FBUyxPQUFPLE1BQU0sRUFBRSxDQUFDO0lBQ2hFLENBQUM7SUFFRCwwREFBMEQ7SUFFMUQ7O09BRUc7SUFDSyxjQUFjLENBQUMsT0FBZ0I7UUFDckMsT0FBTywyQkFBMkI7WUFDaEMsYUFBYSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksSUFBSTtZQUN0QyxlQUFlLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxJQUFJLFNBQVMsSUFBSTtZQUN2RCxpQkFBaUIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLElBQUksU0FBUyxJQUFJO1lBQzNELG9CQUFvQixPQUFPLENBQUMsUUFBUSxDQUFDLFdBQVcsTUFBTTtZQUN0RCx3QkFBd0I7WUFDeEIsa0JBQWtCO1lBQ2xCLE9BQU87WUFDUCxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7WUFDL0MsU0FBUztZQUNULEdBQUcsT0FBTyxDQUFDLE9BQU8sSUFBSTtZQUN0QixZQUFZO1lBQ1osMkJBQTJCO1lBQzNCLHVDQUF1QztZQUN2QyxlQUFlLE9BQU8sQ0FBQyxRQUFRLElBQUk7WUFDbkMsZ0JBQWdCLE9BQU8sQ0FBQyxTQUFTLE1BQU07WUFDdkMsT0FBTztZQUNQLCtEQUErRCxDQUFDO0lBQ3BFLENBQUM7SUFFRDs7T0FFRztJQUNLLHVCQUF1QixDQUFDLE9BQWdCO1FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsR0FBRztZQUNuRCxDQUFDLENBQUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLDBDQUEwQztZQUNoRixDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUVwQixPQUFPLDJCQUEyQjtZQUNoQyxhQUFhLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJO1lBQ3RDLGVBQWUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksU0FBUyxJQUFJO1lBQ3ZELGlCQUFpQixPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsSUFBSSxTQUFTLElBQUk7WUFDM0Qsb0JBQW9CLE9BQU8sQ0FBQyxRQUFRLENBQUMsV0FBVyxNQUFNO1lBQ3RELG9DQUFvQztZQUNwQyxrQkFBa0I7WUFDbEIsT0FBTztZQUNQLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSTtZQUMvQyxTQUFTO1lBQ1QsR0FBRyxnQkFBZ0IsSUFBSTtZQUN2QixZQUFZO1lBQ1osMkJBQTJCO1lBQzNCLHVDQUF1QztZQUN2QyxlQUFlLE9BQU8sQ0FBQyxRQUFRLElBQUk7WUFDbkMsZ0JBQWdCLE9BQU8sQ0FBQyxTQUFTLE1BQU07WUFDdkMsT0FBTztZQUNQLCtEQUErRCxDQUFDO0lBQ3BFLENBQUM7SUFFRDs7T0FFRztJQUNLLGlCQUFpQixDQUFDLFFBQWE7UUFDckMsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQzthQUM1QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEtBQUssS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ3hHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxtQkFBbUIsQ0FBQyxLQUFhLEVBQUUsSUFBWTtRQUNyRCxPQUFPLHNCQUFzQixxQkFBcUIsSUFBSSxvQkFBb0IscUJBQXFCLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxTQUFTLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDOUosQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQUMsS0FBYSxFQUFFLFdBQW1CLEVBQUUsUUFBZ0IsRUFBRSxnQkFBd0I7UUFDeEcsT0FBTyxHQUFHLGdCQUFnQixHQUFHLG1CQUFtQixDQUFDLGVBQWUsTUFBTSxLQUFLLFFBQVE7WUFDakYsR0FBRyxtQkFBbUIsQ0FBQyxZQUFZLE1BQU0sV0FBVyxNQUFNLFFBQVEsRUFBRSxDQUFDO0lBQ3pFLENBQUM7SUFFRDs7T0FFRztJQUNLLDRCQUE0QixDQUFDLGNBQXNCO1FBQ3pELE9BQU8sbUJBQW1CO1lBQ3hCLGlEQUFpRDtZQUNqRCxNQUFNLGNBQWMsTUFBTTtZQUMxQixvQ0FBb0M7WUFDcEMsK0JBQStCO1lBQy9CLGdEQUFnRCxDQUFDO0lBQ3JELENBQUM7SUFFRDs7T0FFRztJQUNLLCtCQUErQixDQUFDLGNBQXNCO1FBQzVELE9BQU8scUNBQXFDO1lBQzFDLGdEQUFnRDtZQUNoRCxNQUFNLGNBQWMsTUFBTTtZQUMxQixrQ0FBa0M7WUFDbEMsc0RBQXNEO1lBQ3RELG9EQUFvRDtZQUNwRCwrREFBK0Q7WUFDL0QsNkZBQTZGO1lBQzdGLHFGQUFxRixDQUFDO0lBQzFGLENBQUM7SUFFRDs7T0FFRztJQUNLLHVCQUF1QjtRQUM3QixPQUFPLDBCQUEwQjtZQUMvQixrREFBa0Q7WUFDbEQsNEVBQTRFO1lBQzVFLGdHQUFnRztZQUNoRyxnREFBZ0QsQ0FBQztJQUNyRCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFN1Ym1pdCBwZXJzb25hcyB0byB0aGUgY29sbGVjdGlvblxuICogSGFuZGxlcyBib3RoIGF1dGhlbnRpY2F0ZWQgYW5kIGFub255bW91cyBzdWJtaXNzaW9uIHdvcmtmbG93c1xuICogXG4gKiBTZWN1cml0eSBGZWF0dXJlczpcbiAqIC0gUmF0ZSBsaW1pdGluZyB0byBwcmV2ZW50IHNwYW0gKDUgc3VibWlzc2lvbnMgcGVyIGhvdXIgcGVyIHNlc3Npb24pXG4gKiAtIFVSTCBsZW5ndGggdmFsaWRhdGlvbiBmb3IgR2l0SHViIGxpbWl0c1xuICogLSBObyBlbWFpbCBzdWJtaXNzaW9uIHBhdGh3YXkgKEdpdEh1YiBhY2NvdW50IHJlcXVpcmVkKVxuICovXG5cbmltcG9ydCB7IFBlcnNvbmEgfSBmcm9tICcuLi90eXBlcy9wZXJzb25hLmpzJztcbmltcG9ydCB7IFJhdGVMaW1pdGVyLCBSYXRlTGltaXRTdGF0dXMgfSBmcm9tICcuLi91dGlscy9SYXRlTGltaXRlci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuXG4vLyBDb25maWd1cmF0aW9uIGNvbnN0YW50c1xuY29uc3QgR0lUSFVCX1VSTF9MSU1JVCA9IDgxOTI7IC8vIEdpdEh1YidzIFVSTCBsZW5ndGggbGltaXQgKH44S0IpXG5jb25zdCBDT0xMRUNUSU9OX1JFUE9fT1dORVIgPSAnRG9sbGhvdXNlTUNQJztcbmNvbnN0IENPTExFQ1RJT05fUkVQT19OQU1FID0gJ2NvbGxlY3Rpb24nO1xuXG4vLyBDb21tb24gcmVzcG9uc2UgY29tcG9uZW50c1xuY29uc3QgUkVTUE9OU0VfQ09NUE9ORU5UUyA9IHtcbiAgU1VCTUlTU0lPTl9JQ09OOiAn8J+TpCcsXG4gIFBFUlNPTkFfSUNPTjogJ/Cfjq0nLFxuICBUSVBfSUNPTjogJ+KtkCcsXG4gIFBST19USVBfSUNPTjogJ/CfkqEnXG59IGFzIGNvbnN0O1xuXG5leHBvcnQgY2xhc3MgUGVyc29uYVN1Ym1pdHRlciB7XG4gIHByaXZhdGUgcmF0ZUxpbWl0ZXI6IFJhdGVMaW1pdGVyO1xuICBcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gSW5pdGlhbGl6ZSByYXRlIGxpbWl0ZXI6IDUgc3VibWlzc2lvbnMgcGVyIGhvdXJcbiAgICB0aGlzLnJhdGVMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKHtcbiAgICAgIG1heFJlcXVlc3RzOiA1LFxuICAgICAgd2luZG93TXM6IDYwICogNjAgKiAxMDAwLCAvLyAxIGhvdXJcbiAgICAgIG1pbkRlbGF5TXM6IDEwMDAwIC8vIE1pbmltdW0gMTAgc2Vjb25kcyBiZXR3ZWVuIHN1Ym1pc3Npb25zXG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIEdlbmVyYXRlIEdpdEh1YiBpc3N1ZSBmb3IgcGVyc29uYSBzdWJtaXNzaW9uXG4gICAqIEluY2x1ZGVzIFVSTCBsZW5ndGggdmFsaWRhdGlvbiB0byBjb21wbHkgd2l0aCBHaXRIdWIncyB+OEtCIGxpbWl0XG4gICAqL1xuICBnZW5lcmF0ZVN1Ym1pc3Npb25Jc3N1ZShwZXJzb25hOiBQZXJzb25hKTogeyBcbiAgICBpc3N1ZVRpdGxlOiBzdHJpbmc7IFxuICAgIGlzc3VlQm9keTogc3RyaW5nOyBcbiAgICBnaXRodWJJc3N1ZVVybDogc3RyaW5nO1xuICAgIHJhdGVMaW1pdFN0YXR1cz86IFJhdGVMaW1pdFN0YXR1cztcbiAgfSB7XG4gICAgLy8gQ2hlY2sgcmF0ZSBsaW1pdFxuICAgIGNvbnN0IHJhdGVMaW1pdFN0YXR1cyA9IHRoaXMucmF0ZUxpbWl0ZXIuY2hlY2tMaW1pdCgpO1xuICAgIFxuICAgIGlmICghcmF0ZUxpbWl0U3RhdHVzLmFsbG93ZWQpIHtcbiAgICAgIC8vIExvZyBwb3RlbnRpYWwgYWJ1c2UgYXR0ZW1wdFxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUkFURV9MSU1JVF9FWENFRURFRCcsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnUGVyc29uYVN1Ym1pdHRlci5nZW5lcmF0ZVN1Ym1pc3Npb25Jc3N1ZScsXG4gICAgICAgIGRldGFpbHM6IGBTdWJtaXNzaW9uIHJhdGUgbGltaXQgZXhjZWVkZWQuIFJldHJ5IGFmdGVyICR7cmF0ZUxpbWl0U3RhdHVzLnJldHJ5QWZ0ZXJNc31tc2BcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBTdWJtaXNzaW9uIHJhdGUgbGltaXQgZXhjZWVkZWQuIFBsZWFzZSB3YWl0ICR7TWF0aC5jZWlsKHJhdGVMaW1pdFN0YXR1cy5yZXRyeUFmdGVyTXMhIC8gMTAwMCl9IHNlY29uZHMgYmVmb3JlIHN1Ym1pdHRpbmcgYWdhaW4uIGAgK1xuICAgICAgICBgVGhpcyBsaW1pdCBoZWxwcyBwcmV2ZW50IHNwYW0gYW5kIGVuc3VyZXMgcXVhbGl0eSBzdWJtaXNzaW9ucy5gXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBpc3N1ZVRpdGxlID0gYE5ldyBQZXJzb25hIFN1Ym1pc3Npb246ICR7cGVyc29uYS5tZXRhZGF0YS5uYW1lfWA7XG4gICAgbGV0IGlzc3VlQm9keSA9IHRoaXMuYnVpbGRJc3N1ZUJvZHkocGVyc29uYSk7XG4gICAgXG4gICAgLy8gQ2hlY2sgVVJMIGxlbmd0aCBhbmQgdHJ1bmNhdGUgaWYgbmVjZXNzYXJ5XG4gICAgbGV0IGdpdGh1Yklzc3VlVXJsID0gdGhpcy5idWlsZEdpdEh1Yklzc3VlVXJsKGlzc3VlVGl0bGUsIGlzc3VlQm9keSk7XG4gICAgXG4gICAgLy8gSWYgVVJMIGV4Y2VlZHMgR2l0SHViJ3MgbGltaXQsIHRydW5jYXRlIHRoZSBjb250ZW50XG4gICAgaWYgKGdpdGh1Yklzc3VlVXJsLmxlbmd0aCA+PSBHSVRIVUJfVVJMX0xJTUlUKSB7XG4gICAgICBpc3N1ZUJvZHkgPSB0aGlzLmJ1aWxkVHJ1bmNhdGVkSXNzdWVCb2R5KHBlcnNvbmEpO1xuICAgICAgZ2l0aHViSXNzdWVVcmwgPSB0aGlzLmJ1aWxkR2l0SHViSXNzdWVVcmwoaXNzdWVUaXRsZSwgaXNzdWVCb2R5KTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIGlzc3VlVGl0bGUsXG4gICAgICBpc3N1ZUJvZHksXG4gICAgICBnaXRodWJJc3N1ZVVybCxcbiAgICAgIHJhdGVMaW1pdFN0YXR1c1xuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGb3JtYXQgc3VibWlzc2lvbiByZXNwb25zZSBmb3IgYXV0aGVudGljYXRlZCB1c2Vyc1xuICAgKi9cbiAgZm9ybWF0U3VibWlzc2lvblJlc3BvbnNlKHBlcnNvbmE6IFBlcnNvbmEsIGdpdGh1Yklzc3VlVXJsOiBzdHJpbmcsIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyA9ICcnKTogc3RyaW5nIHtcbiAgICBjb25zdCBoZWFkZXIgPSB0aGlzLmJ1aWxkUmVzcG9uc2VIZWFkZXIoXG4gICAgICAnUGVyc29uYSBTdWJtaXNzaW9uIFByZXBhcmVkJyxcbiAgICAgIHBlcnNvbmEubWV0YWRhdGEubmFtZSxcbiAgICAgICdpcyByZWFkeSBmb3IgY29sbGVjdGlvbiBzdWJtaXNzaW9uIScsXG4gICAgICBwZXJzb25hSW5kaWNhdG9yXG4gICAgKTtcbiAgICBcbiAgICBjb25zdCBzdGVwcyA9IHRoaXMuYnVpbGRTdGFuZGFyZFN1Ym1pc3Npb25TdGVwcyhnaXRodWJJc3N1ZVVybCk7XG4gICAgY29uc3QgdGlwID0gYCR7UkVTUE9OU0VfQ09NUE9ORU5UUy5USVBfSUNPTn0gKipUaXA6KiogWW91IGNhbiBhbHNvIHN1Ym1pdCB2aWEgcHVsbCByZXF1ZXN0IGlmIHlvdSdyZSBmYW1pbGlhciB3aXRoIEdpdCFgO1xuICAgIFxuICAgIHJldHVybiBgJHtoZWFkZXJ9XFxuXFxuJHtzdGVwc31cXG5cXG4ke3RpcH1gO1xuICB9XG4gIFxuICAvKipcbiAgICogRm9ybWF0IGFub255bW91cyBzdWJtaXNzaW9uIHJlc3BvbnNlIGZvciB1bmF1dGhlbnRpY2F0ZWQgdXNlcnNcbiAgICovXG4gIGZvcm1hdEFub255bW91c1N1Ym1pc3Npb25SZXNwb25zZShwZXJzb25hOiBQZXJzb25hLCBnaXRodWJJc3N1ZVVybDogc3RyaW5nLCBwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmcgPSAnJyk6IHN0cmluZyB7XG4gICAgY29uc3QgaGVhZGVyID0gdGhpcy5idWlsZFJlc3BvbnNlSGVhZGVyKFxuICAgICAgJ0Fub255bW91cyBTdWJtaXNzaW9uIFBhdGggQXZhaWxhYmxlJyxcbiAgICAgIHBlcnNvbmEubWV0YWRhdGEubmFtZSxcbiAgICAgICdjYW4gYmUgc3VibWl0dGVkIHdpdGhvdXQgR2l0SHViIGF1dGhlbnRpY2F0aW9uIScsXG4gICAgICBwZXJzb25hSW5kaWNhdG9yXG4gICAgKTtcbiAgICBcbiAgICBjb25zdCBwcm9jZXNzID0gdGhpcy5idWlsZEFub255bW91c1N1Ym1pc3Npb25Qcm9jZXNzKGdpdGh1Yklzc3VlVXJsKTtcbiAgICBjb25zdCBuZXh0U3RlcHMgPSB0aGlzLmJ1aWxkQW5vbnltb3VzTmV4dFN0ZXBzKCk7XG4gICAgY29uc3QgcHJvVGlwID0gYCR7UkVTUE9OU0VfQ09NUE9ORU5UUy5QUk9fVElQX0lDT059ICoqUHJvIHRpcDoqKiBDcmVhdGluZyBhIGZyZWUgR2l0SHViIGFjY291bnQgdW5sb2NrcyBhZGRpdGlvbmFsIGZlYXR1cmVzLCBidXQgaXQncyBjb21wbGV0ZWx5IG9wdGlvbmFsIGZvciBzdWJtaXNzaW9ucyFgO1xuICAgIFxuICAgIHJldHVybiBgJHtoZWFkZXJ9XFxuXFxuJHtwcm9jZXNzfVxcblxcbiR7bmV4dFN0ZXBzfVxcblxcbiR7cHJvVGlwfWA7XG4gIH1cblxuICAvLyBQcml2YXRlIGhlbHBlciBtZXRob2RzIGZvciBidWlsZGluZyByZXNwb25zZSBjb21wb25lbnRzXG5cbiAgLyoqXG4gICAqIEJ1aWxkIHRoZSBmdWxsIGlzc3VlIGJvZHkgd2l0aCBhbGwgcGVyc29uYSBkZXRhaWxzXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkSXNzdWVCb2R5KHBlcnNvbmE6IFBlcnNvbmEpOiBzdHJpbmcge1xuICAgIHJldHVybiBgIyMgUGVyc29uYSBTdWJtaXNzaW9uXFxuXFxuYCArXG4gICAgICBgKipOYW1lOioqICR7cGVyc29uYS5tZXRhZGF0YS5uYW1lfVxcbmAgK1xuICAgICAgYCoqQXV0aG9yOioqICR7cGVyc29uYS5tZXRhZGF0YS5hdXRob3IgfHwgJ1Vua25vd24nfVxcbmAgK1xuICAgICAgYCoqQ2F0ZWdvcnk6KiogJHtwZXJzb25hLm1ldGFkYXRhLmNhdGVnb3J5IHx8ICdHZW5lcmFsJ31cXG5gICtcbiAgICAgIGAqKkRlc2NyaXB0aW9uOioqICR7cGVyc29uYS5tZXRhZGF0YS5kZXNjcmlwdGlvbn1cXG5cXG5gICtcbiAgICAgIGAjIyMgUGVyc29uYSBDb250ZW50OlxcbmAgK1xuICAgICAgYFxcYFxcYFxcYG1hcmtkb3duXFxuYCArXG4gICAgICBgLS0tXFxuYCArXG4gICAgICBgJHt0aGlzLnNlcmlhbGl6ZU1ldGFkYXRhKHBlcnNvbmEubWV0YWRhdGEpfVxcbmAgK1xuICAgICAgYC0tLVxcblxcbmAgK1xuICAgICAgYCR7cGVyc29uYS5jb250ZW50fVxcbmAgK1xuICAgICAgYFxcYFxcYFxcYFxcblxcbmAgK1xuICAgICAgYCMjIyBTdWJtaXNzaW9uIERldGFpbHM6XFxuYCArXG4gICAgICBgLSBTdWJtaXR0ZWQgdmlhIERvbGxob3VzZU1DUCBjbGllbnRcXG5gICtcbiAgICAgIGAtIEZpbGVuYW1lOiAke3BlcnNvbmEuZmlsZW5hbWV9XFxuYCArXG4gICAgICBgLSBVbmlxdWUgSUQ6ICR7cGVyc29uYS51bmlxdWVfaWR9XFxuXFxuYCArXG4gICAgICBgLS0tXFxuYCArXG4gICAgICBgKlBsZWFzZSByZXZpZXcgdGhpcyBwZXJzb25hIGZvciBpbmNsdXNpb24gaW4gdGhlIGNvbGxlY3Rpb24uKmA7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgYSB0cnVuY2F0ZWQgaXNzdWUgYm9keSB0byBmaXQgd2l0aGluIFVSTCBsaW1pdHNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRUcnVuY2F0ZWRJc3N1ZUJvZHkocGVyc29uYTogUGVyc29uYSk6IHN0cmluZyB7XG4gICAgY29uc3QgdHJ1bmNhdGVkQ29udGVudCA9IHBlcnNvbmEuY29udGVudC5sZW5ndGggPiA1MDAgXG4gICAgICA/IGAke3BlcnNvbmEuY29udGVudC5zdWJzdHJpbmcoMCwgNTAwKX0uLi5cXG5cXG5bQ29udGVudCB0cnVuY2F0ZWQgZHVlIHRvIGxlbmd0aF1gXG4gICAgICA6IHBlcnNvbmEuY29udGVudDtcbiAgICBcbiAgICByZXR1cm4gYCMjIFBlcnNvbmEgU3VibWlzc2lvblxcblxcbmAgK1xuICAgICAgYCoqTmFtZToqKiAke3BlcnNvbmEubWV0YWRhdGEubmFtZX1cXG5gICtcbiAgICAgIGAqKkF1dGhvcjoqKiAke3BlcnNvbmEubWV0YWRhdGEuYXV0aG9yIHx8ICdVbmtub3duJ31cXG5gICtcbiAgICAgIGAqKkNhdGVnb3J5OioqICR7cGVyc29uYS5tZXRhZGF0YS5jYXRlZ29yeSB8fCAnR2VuZXJhbCd9XFxuYCArXG4gICAgICBgKipEZXNjcmlwdGlvbjoqKiAke3BlcnNvbmEubWV0YWRhdGEuZGVzY3JpcHRpb259XFxuXFxuYCArXG4gICAgICBgIyMjIFBlcnNvbmEgQ29udGVudCAoVHJ1bmNhdGVkKTpcXG5gICtcbiAgICAgIGBcXGBcXGBcXGBtYXJrZG93blxcbmAgK1xuICAgICAgYC0tLVxcbmAgK1xuICAgICAgYCR7dGhpcy5zZXJpYWxpemVNZXRhZGF0YShwZXJzb25hLm1ldGFkYXRhKX1cXG5gICtcbiAgICAgIGAtLS1cXG5cXG5gICtcbiAgICAgIGAke3RydW5jYXRlZENvbnRlbnR9XFxuYCArXG4gICAgICBgXFxgXFxgXFxgXFxuXFxuYCArXG4gICAgICBgIyMjIFN1Ym1pc3Npb24gRGV0YWlsczpcXG5gICtcbiAgICAgIGAtIFN1Ym1pdHRlZCB2aWEgRG9sbGhvdXNlTUNQIGNsaWVudFxcbmAgK1xuICAgICAgYC0gRmlsZW5hbWU6ICR7cGVyc29uYS5maWxlbmFtZX1cXG5gICtcbiAgICAgIGAtIFVuaXF1ZSBJRDogJHtwZXJzb25hLnVuaXF1ZV9pZH1cXG5cXG5gICtcbiAgICAgIGAtLS1cXG5gICtcbiAgICAgIGAqUGxlYXNlIHJldmlldyB0aGlzIHBlcnNvbmEgZm9yIGluY2x1c2lvbiBpbiB0aGUgY29sbGVjdGlvbi4qYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJpYWxpemUgcGVyc29uYSBtZXRhZGF0YSB0byBZQU1MIGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSBzZXJpYWxpemVNZXRhZGF0YShtZXRhZGF0YTogYW55KTogc3RyaW5nIHtcbiAgICByZXR1cm4gT2JqZWN0LmVudHJpZXMobWV0YWRhdGEpXG4gICAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IGAke2tleX06ICR7QXJyYXkuaXNBcnJheSh2YWx1ZSkgPyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiBKU09OLnN0cmluZ2lmeSh2YWx1ZSl9YClcbiAgICAgIC5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCB0aGUgR2l0SHViIGlzc3VlIFVSTFxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZEdpdEh1Yklzc3VlVXJsKHRpdGxlOiBzdHJpbmcsIGJvZHk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGBodHRwczovL2dpdGh1Yi5jb20vJHtDT0xMRUNUSU9OX1JFUE9fT1dORVJ9LyR7Q09MTEVDVElPTl9SRVBPX05BTUV9L2lzc3Vlcy9uZXc/dGl0bGU9JHtlbmNvZGVVUklDb21wb25lbnQodGl0bGUpfSZib2R5PSR7ZW5jb2RlVVJJQ29tcG9uZW50KGJvZHkpfWA7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgY29tbW9uIHJlc3BvbnNlIGhlYWRlciB1c2VkIGJ5IGJvdGggYXV0aGVudGljYXRlZCBhbmQgYW5vbnltb3VzIHJlc3BvbnNlc1xuICAgKi9cbiAgcHJpdmF0ZSBidWlsZFJlc3BvbnNlSGVhZGVyKHRpdGxlOiBzdHJpbmcsIHBlcnNvbmFOYW1lOiBzdHJpbmcsIHN1YnRpdGxlOiBzdHJpbmcsIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke3BlcnNvbmFJbmRpY2F0b3J9JHtSRVNQT05TRV9DT01QT05FTlRTLlNVQk1JU1NJT05fSUNPTn0gKioke3RpdGxlfSoqXFxuXFxuYCArXG4gICAgICBgJHtSRVNQT05TRV9DT01QT05FTlRTLlBFUlNPTkFfSUNPTn0gKioke3BlcnNvbmFOYW1lfSoqICR7c3VidGl0bGV9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBzdGFuZGFyZCBzdWJtaXNzaW9uIHN0ZXBzIGZvciBhdXRoZW50aWNhdGVkIHVzZXJzXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkU3RhbmRhcmRTdWJtaXNzaW9uU3RlcHMoZ2l0aHViSXNzdWVVcmw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAqKk5leHQgU3RlcHM6KipcXG5gICtcbiAgICAgIGAxLiBDbGljayB0aGlzIGxpbmsgdG8gY3JlYXRlIGEgR2l0SHViIGlzc3VlOiBcXG5gICtcbiAgICAgIGAgICAke2dpdGh1Yklzc3VlVXJsfVxcblxcbmAgK1xuICAgICAgYDIuIFJldmlldyB0aGUgcHJlLWZpbGxlZCBjb250ZW50XFxuYCArXG4gICAgICBgMy4gQ2xpY2sgXCJTdWJtaXQgbmV3IGlzc3VlXCJcXG5gICtcbiAgICAgIGA0LiBUaGUgbWFpbnRhaW5lcnMgd2lsbCByZXZpZXcgeW91ciBzdWJtaXNzaW9uYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhbm9ueW1vdXMgc3VibWlzc2lvbiBwcm9jZXNzIGluc3RydWN0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBidWlsZEFub255bW91c1N1Ym1pc3Npb25Qcm9jZXNzKGdpdGh1Yklzc3VlVXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBgKipBbm9ueW1vdXMgU3VibWlzc2lvbiBQcm9jZXNzOioqXFxuYCArXG4gICAgICBgMS4gQ2xpY2sgdGhpcyBsaW5rIHRvIGNyZWF0ZSBhIEdpdEh1YiBpc3N1ZTpcXG5gICtcbiAgICAgIGAgICAke2dpdGh1Yklzc3VlVXJsfVxcblxcbmAgK1xuICAgICAgYDIuICoqVG8gc3VibWl0IHlvdXIgcGVyc29uYToqKlxcbmAgK1xuICAgICAgYCAgIOKAoiBZb3UnbGwgbmVlZCBhIEdpdEh1YiBhY2NvdW50IChmcmVlIHRvIGNyZWF0ZSlcXG5gICtcbiAgICAgIGAgICDigKIgQ2xpY2sgXCJTdWJtaXQgbmV3IGlzc3VlXCIgdG8gc3VibWl0IGRpcmVjdGx5XFxuYCArXG4gICAgICBgICAg4oCiIFRoZSBmb3JtIGlzIHByZS1maWxsZWQgd2l0aCBhbGwgeW91ciBwZXJzb25hIGRldGFpbHNcXG5cXG5gICtcbiAgICAgIGAqKk5vdGU6KiogR2l0SHViIGFjY291bnQgaXMgcmVxdWlyZWQgZm9yIHN1Ym1pc3Npb24gdG8gcHJldmVudCBzcGFtIGFuZCBtYWludGFpbiBxdWFsaXR5LlxcbmAgK1xuICAgICAgYENyZWF0aW5nIGFuIGFjY291bnQgaXMgZnJlZSBhbmQgdGFrZXMgbGVzcyB0aGFuIGEgbWludXRlOiBodHRwczovL2dpdGh1Yi5jb20vc2lnbnVwYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhbm9ueW1vdXMgc3VibWlzc2lvbiBuZXh0IHN0ZXBzIGFuZCBleHBlY3RhdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRBbm9ueW1vdXNOZXh0U3RlcHMoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCoqV2hhdCBoYXBwZW5zIG5leHQ6KipcXG5gICtcbiAgICAgIGDigKIgQ29tbXVuaXR5IG1haW50YWluZXJzIHJldmlldyBhbGwgc3VibWlzc2lvbnNcXG5gICtcbiAgICAgIGDigKIgQW5vbnltb3VzIHN1Ym1pc3Npb25zIGdldCB0aGUgc2FtZSBjb25zaWRlcmF0aW9uIGFzIGF1dGhlbnRpY2F0ZWQgb25lc1xcbmAgK1xuICAgICAgYOKAoiBJZiBhY2NlcHRlZCwgeW91ciBwZXJzb25hIGpvaW5zIHRoZSBjb2xsZWN0aW9uIHdpdGggYXR0cmlidXRpb24gdG8gXCJDb21tdW5pdHkgQ29udHJpYnV0b3JcIlxcbmAgK1xuICAgICAgYOKAoiBUaGUgcmV2aWV3IHR5cGljYWxseSB0YWtlcyAyLTMgYnVzaW5lc3MgZGF5c2A7XG4gIH1cbn0iXX0=
@@ -3,7 +3,9 @@
3
3
  */
4
4
  export * from './GitHubClient.js';
5
5
  export * from './CollectionBrowser.js';
6
+ export * from './CollectionIndexManager.js';
6
7
  export * from './CollectionSearch.js';
8
+ export * from './CollectionSeeder.js';
7
9
  export * from './PersonaDetails.js';
8
10
  export * from './ElementInstaller.js';
9
11
  export * from './PersonaSubmitter.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collection/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collection/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC"}
@@ -3,8 +3,10 @@
3
3
  */
4
4
  export * from './GitHubClient.js';
5
5
  export * from './CollectionBrowser.js';
6
+ export * from './CollectionIndexManager.js';
6
7
  export * from './CollectionSearch.js';
8
+ export * from './CollectionSeeder.js';
7
9
  export * from './PersonaDetails.js';
8
10
  export * from './ElementInstaller.js';
9
11
  export * from './PersonaSubmitter.js';
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29sbGVjdGlvbi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHVCQUF1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb2xsZWN0aW9uIG1vZHVsZSBleHBvcnRzXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9HaXRIdWJDbGllbnQuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9Db2xsZWN0aW9uQnJvd3Nlci5qcyc7XG5leHBvcnQgKiBmcm9tICcuL0NvbGxlY3Rpb25TZWFyY2guanMnO1xuZXhwb3J0ICogZnJvbSAnLi9QZXJzb25hRGV0YWlscy5qcyc7XG5leHBvcnQgKiBmcm9tICcuL0VsZW1lbnRJbnN0YWxsZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9QZXJzb25hU3VibWl0dGVyLmpzJzsiXX0=
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29sbGVjdGlvbi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyx1QkFBdUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29sbGVjdGlvbiBtb2R1bGUgZXhwb3J0c1xuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vR2l0SHViQ2xpZW50LmpzJztcbmV4cG9ydCAqIGZyb20gJy4vQ29sbGVjdGlvbkJyb3dzZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9Db2xsZWN0aW9uSW5kZXhNYW5hZ2VyLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vQ29sbGVjdGlvblNlYXJjaC5qcyc7XG5leHBvcnQgKiBmcm9tICcuL0NvbGxlY3Rpb25TZWVkZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9QZXJzb25hRGV0YWlscy5qcyc7XG5leHBvcnQgKiBmcm9tICcuL0VsZW1lbnRJbnN0YWxsZXIuanMnO1xuZXhwb3J0ICogZnJvbSAnLi9QZXJzb25hU3VibWl0dGVyLmpzJzsiXX0=
@@ -0,0 +1,78 @@
1
+ /**
2
+ * ConfigManager - Thread-safe singleton for persistent configuration
3
+ *
4
+ * Handles OAuth client ID storage for Claude Desktop integration.
5
+ * Stores config in ~/.dollhouse/config.json with proper permissions.
6
+ * Prefers environment variables over config file values.
7
+ */
8
+ interface ConfigData {
9
+ version: string;
10
+ oauth?: {
11
+ githubClientId?: string;
12
+ };
13
+ [key: string]: any;
14
+ }
15
+ export declare class ConfigManager {
16
+ private static instance;
17
+ private static instanceLock;
18
+ private configDir;
19
+ private configPath;
20
+ private config;
21
+ private constructor();
22
+ /**
23
+ * Thread-safe singleton instance getter
24
+ */
25
+ static getInstance(): ConfigManager;
26
+ /**
27
+ * Attempt to repair file permissions if they're incorrect
28
+ * This helps with error recovery in permission-related issues
29
+ */
30
+ private repairPermissions;
31
+ /**
32
+ * Load configuration from file system
33
+ */
34
+ loadConfig(): Promise<void>;
35
+ /**
36
+ * Get GitHub OAuth client ID
37
+ * Environment variable takes precedence over config file
38
+ */
39
+ getGitHubClientId(): string | null;
40
+ /**
41
+ * Set GitHub OAuth client ID in config file
42
+ */
43
+ setGitHubClientId(clientId: string): Promise<void>;
44
+ /**
45
+ * Get a copy of the current configuration
46
+ * @returns A defensive copy of the configuration object
47
+ */
48
+ getConfig(): ConfigData;
49
+ /**
50
+ * Update the entire configuration
51
+ * @param newConfig The new configuration to set
52
+ */
53
+ updateConfig(newConfig: ConfigData): Promise<void>;
54
+ /**
55
+ * Validate GitHub OAuth client ID format
56
+ * Client IDs start with "Ov23li" followed by at least 14 alphanumeric characters
57
+ *
58
+ * @param clientId - The client ID to validate
59
+ * @returns true if valid, false otherwise
60
+ *
61
+ * @example
62
+ * ConfigManager.validateClientId("Ov23liABCDEFGHIJKLMN123456") // true
63
+ * ConfigManager.validateClientId("invalid") // false
64
+ * ConfigManager.validateClientId("Ov23li") // false (too short)
65
+ * ConfigManager.validateClientId("Xv23liABCDEFGHIJKLMN") // false (wrong prefix)
66
+ */
67
+ static validateClientId(clientId: any): boolean;
68
+ /**
69
+ * Ensure config directory exists with proper permissions
70
+ */
71
+ private ensureConfigDirectory;
72
+ /**
73
+ * Save config using atomic file writes
74
+ */
75
+ private saveConfig;
76
+ }
77
+ export {};
78
+ //# sourceMappingURL=ConfigManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigManager.d.ts","sourceRoot":"","sources":["../../src/config/ConfigManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QACN,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IACrD,OAAO,CAAC,MAAM,CAAC,YAAY,CAAkB;IAE7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAa;IAE3B,OAAO;IAWP;;OAEG;WACW,WAAW,IAAI,aAAa;IAyB1C;;;OAGG;YACW,iBAAiB;IAkB/B;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCxC;;;OAGG;IACI,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAWzC;;OAEG;IACU,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB/D;;;OAGG;IACI,SAAS,IAAI,UAAU;IAI9B;;;OAGG;IACU,YAAY,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D;;;;;;;;;;;;OAYG;WACW,gBAAgB,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO;IAUtD;;OAEG;YACW,qBAAqB;IAWnC;;OAEG;YACW,UAAU;CAuBzB"}