algokit-mcp 1.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 (195) hide show
  1. package/README.md +137 -0
  2. package/dist/api/boj-scraper.d.ts +68 -0
  3. package/dist/api/boj-scraper.d.ts.map +1 -0
  4. package/dist/api/boj-scraper.js +197 -0
  5. package/dist/api/boj-scraper.js.map +1 -0
  6. package/dist/api/programmers-scraper.d.ts +70 -0
  7. package/dist/api/programmers-scraper.d.ts.map +1 -0
  8. package/dist/api/programmers-scraper.js +303 -0
  9. package/dist/api/programmers-scraper.js.map +1 -0
  10. package/dist/api/solvedac-client.d.ts +67 -0
  11. package/dist/api/solvedac-client.d.ts.map +1 -0
  12. package/dist/api/solvedac-client.js +220 -0
  13. package/dist/api/solvedac-client.js.map +1 -0
  14. package/dist/api/types.d.ts +125 -0
  15. package/dist/api/types.d.ts.map +1 -0
  16. package/dist/api/types.js +110 -0
  17. package/dist/api/types.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +594 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/prompts/hint-guide.d.ts +73 -0
  23. package/dist/prompts/hint-guide.d.ts.map +1 -0
  24. package/dist/prompts/hint-guide.js +174 -0
  25. package/dist/prompts/hint-guide.js.map +1 -0
  26. package/dist/prompts/programmers-hint-guide.d.ts +38 -0
  27. package/dist/prompts/programmers-hint-guide.d.ts.map +1 -0
  28. package/dist/prompts/programmers-hint-guide.js +134 -0
  29. package/dist/prompts/programmers-hint-guide.js.map +1 -0
  30. package/dist/services/code-analyzer.d.ts +46 -0
  31. package/dist/services/code-analyzer.d.ts.map +1 -0
  32. package/dist/services/code-analyzer.js +177 -0
  33. package/dist/services/code-analyzer.js.map +1 -0
  34. package/dist/services/hint-generator.d.ts +60 -0
  35. package/dist/services/hint-generator.d.ts.map +1 -0
  36. package/dist/services/hint-generator.js +222 -0
  37. package/dist/services/hint-generator.js.map +1 -0
  38. package/dist/services/problem-analyzer.d.ts +38 -0
  39. package/dist/services/problem-analyzer.d.ts.map +1 -0
  40. package/dist/services/problem-analyzer.js +114 -0
  41. package/dist/services/problem-analyzer.js.map +1 -0
  42. package/dist/services/programmers-problem-analyzer.d.ts +26 -0
  43. package/dist/services/programmers-problem-analyzer.d.ts.map +1 -0
  44. package/dist/services/programmers-problem-analyzer.js +64 -0
  45. package/dist/services/programmers-problem-analyzer.js.map +1 -0
  46. package/dist/services/programmers-review-template-generator.d.ts +27 -0
  47. package/dist/services/programmers-review-template-generator.d.ts.map +1 -0
  48. package/dist/services/programmers-review-template-generator.js +153 -0
  49. package/dist/services/programmers-review-template-generator.js.map +1 -0
  50. package/dist/services/review-generator.d.ts +51 -0
  51. package/dist/services/review-generator.d.ts.map +1 -0
  52. package/dist/services/review-generator.js +149 -0
  53. package/dist/services/review-generator.js.map +1 -0
  54. package/dist/services/review-template-generator.d.ts +27 -0
  55. package/dist/services/review-template-generator.d.ts.map +1 -0
  56. package/dist/services/review-template-generator.js +163 -0
  57. package/dist/services/review-template-generator.js.map +1 -0
  58. package/dist/templates/review-guideline.md +89 -0
  59. package/dist/tools/analyze-code-submission-boj.d.ts +67 -0
  60. package/dist/tools/analyze-code-submission-boj.d.ts.map +1 -0
  61. package/dist/tools/analyze-code-submission-boj.js +89 -0
  62. package/dist/tools/analyze-code-submission-boj.js.map +1 -0
  63. package/dist/tools/analyze-code-submission-programmers.d.ts +60 -0
  64. package/dist/tools/analyze-code-submission-programmers.d.ts.map +1 -0
  65. package/dist/tools/analyze-code-submission-programmers.js +83 -0
  66. package/dist/tools/analyze-code-submission-programmers.js.map +1 -0
  67. package/dist/tools/analyze-code-submission.d.ts +67 -0
  68. package/dist/tools/analyze-code-submission.d.ts.map +1 -0
  69. package/dist/tools/analyze-code-submission.js +89 -0
  70. package/dist/tools/analyze-code-submission.js.map +1 -0
  71. package/dist/tools/analyze-problem-boj.d.ts +48 -0
  72. package/dist/tools/analyze-problem-boj.d.ts.map +1 -0
  73. package/dist/tools/analyze-problem-boj.js +52 -0
  74. package/dist/tools/analyze-problem-boj.js.map +1 -0
  75. package/dist/tools/analyze-problem-programmers.d.ts +48 -0
  76. package/dist/tools/analyze-problem-programmers.d.ts.map +1 -0
  77. package/dist/tools/analyze-problem-programmers.js +53 -0
  78. package/dist/tools/analyze-problem-programmers.js.map +1 -0
  79. package/dist/tools/analyze-problem.d.ts +48 -0
  80. package/dist/tools/analyze-problem.d.ts.map +1 -0
  81. package/dist/tools/analyze-problem.js +52 -0
  82. package/dist/tools/analyze-problem.js.map +1 -0
  83. package/dist/tools/create-review.d.ts +47 -0
  84. package/dist/tools/create-review.d.ts.map +1 -0
  85. package/dist/tools/create-review.js +122 -0
  86. package/dist/tools/create-review.js.map +1 -0
  87. package/dist/tools/fetch-problem-content-boj.d.ts +49 -0
  88. package/dist/tools/fetch-problem-content-boj.d.ts.map +1 -0
  89. package/dist/tools/fetch-problem-content-boj.js +93 -0
  90. package/dist/tools/fetch-problem-content-boj.js.map +1 -0
  91. package/dist/tools/fetch-problem-content-programmers.d.ts +46 -0
  92. package/dist/tools/fetch-problem-content-programmers.d.ts.map +1 -0
  93. package/dist/tools/fetch-problem-content-programmers.js +74 -0
  94. package/dist/tools/fetch-problem-content-programmers.js.map +1 -0
  95. package/dist/tools/fetch-problem-content.d.ts +49 -0
  96. package/dist/tools/fetch-problem-content.d.ts.map +1 -0
  97. package/dist/tools/fetch-problem-content.js +93 -0
  98. package/dist/tools/fetch-problem-content.js.map +1 -0
  99. package/dist/tools/generate-hint-boj.d.ts +42 -0
  100. package/dist/tools/generate-hint-boj.d.ts.map +1 -0
  101. package/dist/tools/generate-hint-boj.js +80 -0
  102. package/dist/tools/generate-hint-boj.js.map +1 -0
  103. package/dist/tools/generate-hint-programmers.d.ts +42 -0
  104. package/dist/tools/generate-hint-programmers.d.ts.map +1 -0
  105. package/dist/tools/generate-hint-programmers.js +78 -0
  106. package/dist/tools/generate-hint-programmers.js.map +1 -0
  107. package/dist/tools/generate-hint.d.ts +42 -0
  108. package/dist/tools/generate-hint.d.ts.map +1 -0
  109. package/dist/tools/generate-hint.js +80 -0
  110. package/dist/tools/generate-hint.js.map +1 -0
  111. package/dist/tools/generate-review-template-boj.d.ts +48 -0
  112. package/dist/tools/generate-review-template-boj.d.ts.map +1 -0
  113. package/dist/tools/generate-review-template-boj.js +52 -0
  114. package/dist/tools/generate-review-template-boj.js.map +1 -0
  115. package/dist/tools/generate-review-template-programmers.d.ts +48 -0
  116. package/dist/tools/generate-review-template-programmers.d.ts.map +1 -0
  117. package/dist/tools/generate-review-template-programmers.js +53 -0
  118. package/dist/tools/generate-review-template-programmers.js.map +1 -0
  119. package/dist/tools/generate-review-template.d.ts +48 -0
  120. package/dist/tools/generate-review-template.d.ts.map +1 -0
  121. package/dist/tools/generate-review-template.js +52 -0
  122. package/dist/tools/generate-review-template.js.map +1 -0
  123. package/dist/tools/get-hint.d.ts +41 -0
  124. package/dist/tools/get-hint.d.ts.map +1 -0
  125. package/dist/tools/get-hint.js +108 -0
  126. package/dist/tools/get-hint.js.map +1 -0
  127. package/dist/tools/get-problem.d.ts +22 -0
  128. package/dist/tools/get-problem.d.ts.map +1 -0
  129. package/dist/tools/get-problem.js +89 -0
  130. package/dist/tools/get-problem.js.map +1 -0
  131. package/dist/tools/get-programmers-problem.d.ts +53 -0
  132. package/dist/tools/get-programmers-problem.d.ts.map +1 -0
  133. package/dist/tools/get-programmers-problem.js +161 -0
  134. package/dist/tools/get-programmers-problem.js.map +1 -0
  135. package/dist/tools/search-problems.d.ts +42 -0
  136. package/dist/tools/search-problems.d.ts.map +1 -0
  137. package/dist/tools/search-problems.js +123 -0
  138. package/dist/tools/search-problems.js.map +1 -0
  139. package/dist/tools/search-programmers-problems.d.ts +73 -0
  140. package/dist/tools/search-programmers-problems.d.ts.map +1 -0
  141. package/dist/tools/search-programmers-problems.js +171 -0
  142. package/dist/tools/search-programmers-problems.js.map +1 -0
  143. package/dist/tools/search-tags.d.ts +22 -0
  144. package/dist/tools/search-tags.d.ts.map +1 -0
  145. package/dist/tools/search-tags.js +70 -0
  146. package/dist/tools/search-tags.js.map +1 -0
  147. package/dist/types/analysis.d.ts +211 -0
  148. package/dist/types/analysis.d.ts.map +1 -0
  149. package/dist/types/analysis.js +11 -0
  150. package/dist/types/analysis.js.map +1 -0
  151. package/dist/types/problem-content.d.ts +110 -0
  152. package/dist/types/problem-content.d.ts.map +1 -0
  153. package/dist/types/problem-content.js +7 -0
  154. package/dist/types/problem-content.js.map +1 -0
  155. package/dist/types/programmers.d.ts +72 -0
  156. package/dist/types/programmers.d.ts.map +1 -0
  157. package/dist/types/programmers.js +5 -0
  158. package/dist/types/programmers.js.map +1 -0
  159. package/dist/utils/browser-pool.d.ts +93 -0
  160. package/dist/utils/browser-pool.d.ts.map +1 -0
  161. package/dist/utils/browser-pool.js +193 -0
  162. package/dist/utils/browser-pool.js.map +1 -0
  163. package/dist/utils/cache-stats.d.ts +60 -0
  164. package/dist/utils/cache-stats.d.ts.map +1 -0
  165. package/dist/utils/cache-stats.js +78 -0
  166. package/dist/utils/cache-stats.js.map +1 -0
  167. package/dist/utils/cache.d.ts +72 -0
  168. package/dist/utils/cache.d.ts.map +1 -0
  169. package/dist/utils/cache.js +99 -0
  170. package/dist/utils/cache.js.map +1 -0
  171. package/dist/utils/html-parser.d.ts +57 -0
  172. package/dist/utils/html-parser.d.ts.map +1 -0
  173. package/dist/utils/html-parser.js +383 -0
  174. package/dist/utils/html-parser.js.map +1 -0
  175. package/dist/utils/lru-cache.d.ts +124 -0
  176. package/dist/utils/lru-cache.d.ts.map +1 -0
  177. package/dist/utils/lru-cache.js +259 -0
  178. package/dist/utils/lru-cache.js.map +1 -0
  179. package/dist/utils/programmers-converter.d.ts +15 -0
  180. package/dist/utils/programmers-converter.d.ts.map +1 -0
  181. package/dist/utils/programmers-converter.js +41 -0
  182. package/dist/utils/programmers-converter.js.map +1 -0
  183. package/dist/utils/rate-limiter.d.ts +145 -0
  184. package/dist/utils/rate-limiter.d.ts.map +1 -0
  185. package/dist/utils/rate-limiter.js +244 -0
  186. package/dist/utils/rate-limiter.js.map +1 -0
  187. package/dist/utils/tier-converter.d.ts +108 -0
  188. package/dist/utils/tier-converter.d.ts.map +1 -0
  189. package/dist/utils/tier-converter.js +198 -0
  190. package/dist/utils/tier-converter.js.map +1 -0
  191. package/dist/utils/url-parser.d.ts +25 -0
  192. package/dist/utils/url-parser.d.ts.map +1 -0
  193. package/dist/utils/url-parser.js +45 -0
  194. package/dist/utils/url-parser.js.map +1 -0
  195. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # AlgoKit-mcp
2
+
3
+ **๋ฐฑ์ค€(BOJ)๊ณผ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ ํ•™์Šต์„ ๋•๋Š” MCP ์„œ๋ฒ„ + Skill**
4
+
5
+ AI ๊ธฐ๋ฐ˜ ํžŒํŠธ ์ƒ์„ฑ, ๋ฌธ์ œ ๋ถ„์„, ๋ณต์Šต ํ…œํ”Œ๋ฆฟ ์ œ๊ณต์œผ๋กœ ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•™์Šต์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
6
+
7
+ ## ์ฃผ์š” ๊ธฐ๋Šฅ
8
+
9
+ - ๐Ÿ” **๋ฌธ์ œ ๊ฒ€์ƒ‰**: ๋‚œ์ด๋„, ํƒœ๊ทธ, ํ‚ค์›Œ๋“œ๋กœ ๋ฌธ์ œ ๊ฒ€์ƒ‰
10
+ - ๐Ÿ’ก **๋‹จ๊ณ„๋ณ„ ํžŒํŠธ**: Level 1~3 ๋‹จ๊ณ„๋ณ„ ๋งž์ถค ํžŒํŠธ ์ƒ์„ฑ
11
+ - ๐Ÿ“Š **๋ฌธ์ œ ๋ถ„์„**: ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ถ„๋ฅ˜, ๋‚œ์ด๋„ ๋ถ„์„, ํ•™์Šต ๊ฐ€์ด๋“œ
12
+ - ๐Ÿ“ **๋ณต์Šต ํ…œํ”Œ๋ฆฟ**: ์ž๋™ ์ƒ์„ฑ๋˜๋Š” ๋งˆํฌ๋‹ค์šด ๋ณต์Šต ๋ฌธ์„œ
13
+ - ๐Ÿงช **์ฝ”๋“œ ๋ถ„์„**: ์ œ์ถœ ์ฝ”๋“œ์˜ ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„ ๋ฐ ๊ฐœ์„  ์ œ์•ˆ
14
+
15
+ ## ์„ค์น˜
16
+
17
+ ### Claude Code (์ถ”์ฒœ)
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "algokit": {
23
+ "command": "npx",
24
+ "args": ["-y", "algokit-mcp"]
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## MCP ๋„๊ตฌ
31
+
32
+ ### ๋ฐฑ์ค€ (BOJ)
33
+
34
+ | ๋„๊ตฌ | ์„ค๋ช… |
35
+ |------|------|
36
+ | `search_problems` | ๋ฌธ์ œ ๊ฒ€์ƒ‰ (ํ‹ฐ์–ด, ํƒœ๊ทธ, ํ‚ค์›Œ๋“œ) |
37
+ | `get_problem` | ๋ฌธ์ œ ์ƒ์„ธ ์กฐํšŒ |
38
+ | `search_tags` | ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํƒœ๊ทธ ๊ฒ€์ƒ‰ |
39
+ | `fetch_problem_content_boj` | ๋ฌธ์ œ ๋ณธ๋ฌธ ์Šคํฌ๋ž˜ํ•‘ |
40
+ | `analyze_problem_boj` | ๋ฌธ์ œ ๋ถ„์„ ๋ฐ ํžŒํŠธ ๊ฐ€์ด๋“œ |
41
+ | `generate_hint_boj` | 3๋‹จ๊ณ„ ํžŒํŠธ ์ƒ์„ฑ |
42
+ | `generate_review_template_boj` | ๋ณต์Šต ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ |
43
+ | `analyze_code_submission_boj` | ์ฝ”๋“œ ๋ถ„์„ ๋ฐ ํ”ผ๋“œ๋ฐฑ |
44
+
45
+ ### ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค (Programmers)
46
+
47
+ | ๋„๊ตฌ | ์„ค๋ช… |
48
+ |------|------|
49
+ | `search_programmers_problems` | ๋ฌธ์ œ ๊ฒ€์ƒ‰ (๋‚œ์ด๋„, ์นดํ…Œ๊ณ ๋ฆฌ) |
50
+ | `get_programmers_problem` | ๋ฌธ์ œ ์ƒ์„ธ ์กฐํšŒ |
51
+ | `fetch_problem_content_programmers` | ๋ฌธ์ œ ๋ณธ๋ฌธ ์Šคํฌ๋ž˜ํ•‘ |
52
+ | `analyze_problem_programmers` | ๋ฌธ์ œ ๋ถ„์„ |
53
+ | `generate_hint_programmers` | ํžŒํŠธ ์ƒ์„ฑ |
54
+ | `generate_review_template_programmers` | ๋ณต์Šต ํ…œํ”Œ๋ฆฟ |
55
+ | `analyze_code_submission_programmers` | ์ฝ”๋“œ ๋ถ„์„ |
56
+
57
+ ## MCP Skill (Claude Code ์ „์šฉ)
58
+
59
+ **Skill ์ด๋ฆ„**: `algo:`
60
+
61
+ ํ”Œ๋žซํผ(BOJ/ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค)์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•˜์—ฌ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ•™์Šต ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
62
+
63
+ ### ์„ค์น˜ ๋ฐฉ๋ฒ•
64
+
65
+ ```bash
66
+ # Skill ํŒŒ์ผ ๋ณต์‚ฌ (ํ”„๋กœ์ ํŠธ๋ณ„)
67
+ cp .claude/skills/algokit.md /your/project/.claude/skills/
68
+
69
+ # ๋˜๋Š” ์ „์—ญ ์„ค์ •
70
+ cp .claude/skills/algokit.md ~/.claude/skills/
71
+ ```
72
+
73
+ ### ์‚ฌ์šฉ ์˜ˆ์‹œ
74
+
75
+ ```
76
+ You: "๋ฐฑ์ค€ ๊ณจ๋“œ ๋‚œ์ด๋„ DP ๋ฌธ์ œ 3๊ฐœ ์ถ”์ฒœํ•ด์ค˜"
77
+ Claude: [์ž๋™์œผ๋กœ BOJ search_problems ํ˜ธ์ถœ]
78
+
79
+ You: "์ด ๋ฌธ์ œ ๋ถ„์„ํ•ด์ค˜: https://www.acmicpc.net/problem/1927"
80
+ Claude: [URL ํŒŒ์‹ฑ โ†’ analyze_problem_boj ์ž๋™ ํ˜ธ์ถœ]
81
+
82
+ You: "ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค Level 2 ๋ฌธ์ œ ์ฐพ์•„์ค˜"
83
+ Claude: [search_programmers_problems ์ž๋™ ํ˜ธ์ถœ]
84
+
85
+ You: "ํžŒํŠธ ๋” ์ค˜"
86
+ Claude: [์ด์ „ ๋Œ€ํ™” ๋ถ„์„ โ†’ ์ ์ ˆํ•œ Level ํžŒํŠธ ์ œ๊ณต]
87
+ ```
88
+
89
+ ## ๊ฐœ๋ฐœ
90
+
91
+ ### ๋นŒ๋“œ ๋ฐ ํ…Œ์ŠคํŠธ
92
+
93
+ ```bash
94
+ # ์˜์กด์„ฑ ์„ค์น˜
95
+ npm install
96
+
97
+ # ๋นŒ๋“œ
98
+ npm run build
99
+
100
+ # ํ…Œ์ŠคํŠธ
101
+ npm test
102
+
103
+ # ๊ฐœ๋ฐœ ๋ชจ๋“œ
104
+ npm run dev
105
+ ```
106
+
107
+ ### ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ
108
+
109
+ ```
110
+ src/
111
+ โ”œโ”€โ”€ api/ # solved.ac API, BOJ/ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค scrapping
112
+ โ”œโ”€โ”€ tools/ # MCP ๋„๊ตฌ (15๊ฐœ)
113
+ โ”œโ”€โ”€ services/ # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
114
+ โ”œโ”€โ”€ prompts/ # ํžŒํŠธ ๊ฐ€์ด๋“œ ํ”„๋กฌํ”„ํŠธ
115
+ โ””โ”€โ”€ utils/ # ์œ ํ‹ธ๋ฆฌํ‹ฐ (์บ์‹ฑ, Rate Limiting)
116
+ ```
117
+
118
+ ## ๊ธฐ์ˆ  ์Šคํƒ
119
+
120
+ - **Runtime**: Node.js (>=18.0.0)
121
+ - **Language**: TypeScript 5.9
122
+ - **MCP SDK**: @modelcontextprotocol/sdk v1.26.0
123
+ - **Validation**: Zod
124
+ - **Testing**: Vitest
125
+
126
+ ## ๋ผ์ด์„ ์Šค
127
+
128
+ MIT
129
+
130
+ ---
131
+
132
+ <div align="center">
133
+
134
+ **[GitHub](https://github.com/itsme-shawn/AlgoKit-mcp)** โ€ข **[Issues](https://github.com/itsme-shawn/algoKit-mcp/issues)** โ€ข **[NPM](https://www.npmjs.com/package/algokit-mcp-server)**
135
+
136
+
137
+ </div>
@@ -0,0 +1,68 @@
1
+ /**
2
+ * BOJ ๋ฌธ์ œ ํŽ˜์ด์ง€ ์Šคํฌ๋ž˜ํผ
3
+ *
4
+ * Phase 6 - P6-002: ๋ฌธ์ œ ๋ณธ๋ฌธ ์Šคํฌ๋ž˜ํผ ๊ตฌํ˜„
5
+ *
6
+ * fetch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ BOJ ํŽ˜์ด์ง€ HTML์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
7
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•ด ์š”์ฒญ ๊ฐ„ ์ตœ์†Œ 3์ดˆ ๊ฐ„๊ฒฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
8
+ */
9
+ /**
10
+ * BOJ ์Šคํฌ๋ž˜ํ•‘ ์—๋Ÿฌ
11
+ */
12
+ export declare class BojFetchError extends Error {
13
+ code: 'NOT_FOUND' | 'NETWORK_ERROR' | 'TIMEOUT' | 'PARSE_ERROR';
14
+ originalError?: unknown | undefined;
15
+ constructor(message: string, code: 'NOT_FOUND' | 'NETWORK_ERROR' | 'TIMEOUT' | 'PARSE_ERROR', originalError?: unknown | undefined);
16
+ }
17
+ /**
18
+ * BOJ ๋ฌธ์ œ ํŽ˜์ด์ง€ ์Šคํฌ๋ž˜ํผ
19
+ */
20
+ export declare class BOJScraper {
21
+ /** ๋งˆ์ง€๋ง‰ ์š”์ฒญ ์‹œ๊ฐ„ (์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•œ ๊ฐ„๊ฒฉ ์ œ์–ด) */
22
+ private lastRequestTime;
23
+ /** Rate Limiter (๋ฐฑ์—… ๋ณดํ˜ธ) */
24
+ private rateLimiter;
25
+ /** HTML ์บ์‹œ (30์ผ TTL) */
26
+ private cache;
27
+ constructor();
28
+ /**
29
+ * ์ง€์ •๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ์˜ HTML ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
30
+ *
31
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•ด ์š”์ฒญ ๊ฐ„ ์ตœ์†Œ 3์ดˆ ๊ฐ„๊ฒฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
32
+ *
33
+ * @param problemId - BOJ ๋ฌธ์ œ ๋ฒˆํ˜ธ (์˜ˆ: 1000)
34
+ * @returns HTML ๋ฌธ์ž์—ด
35
+ * @throws {BojFetchError} ์Šคํฌ๋ž˜ํ•‘ ์‹คํŒจ ์‹œ
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const scraper = new BOJScraper();
40
+ * const html = await scraper.fetchProblemPage(1000);
41
+ * console.log(html.length); // HTML ๊ธธ์ด ์ถœ๋ ฅ
42
+ * ```
43
+ */
44
+ fetchProblemPage(problemId: number): Promise<string>;
45
+ /**
46
+ * ํƒ€์ž„์•„์›ƒ ์ ์šฉ๋œ HTTP ์š”์ฒญ
47
+ */
48
+ private _fetchWithTimeout;
49
+ /**
50
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘: ๋งˆ์ง€๋ง‰ ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ ์ตœ์†Œ ๊ฐ„๊ฒฉ ๋ณด์žฅ
51
+ */
52
+ private _ensureRequestInterval;
53
+ /**
54
+ * ์ง€์—ฐ ํ•จ์ˆ˜ (์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ ๋ฐ ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘ ๊ฐ„๊ฒฉ)
55
+ */
56
+ private _delay;
57
+ /**
58
+ * ์บ์‹œ ํ†ต๊ณ„ ์กฐํšŒ
59
+ *
60
+ * @returns ์บ์‹œ ํ†ต๊ณ„
61
+ */
62
+ getCacheStats(): import("../utils/lru-cache.js").CacheStats;
63
+ /**
64
+ * ์บ์‹œ ์ดˆ๊ธฐํ™”
65
+ */
66
+ clearCache(): void;
67
+ }
68
+ //# sourceMappingURL=boj-scraper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boj-scraper.d.ts","sourceRoot":"","sources":["../../src/api/boj-scraper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqBH;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAG7B,IAAI,EAAE,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,aAAa;IAC/D,aAAa,CAAC,EAAE,OAAO;gBAF9B,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,aAAa,EAC/D,aAAa,CAAC,EAAE,OAAO,YAAA;CAKjC;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,qCAAqC;IACrC,OAAO,CAAC,eAAe,CAAK;IAE5B,2BAA2B;IAC3B,OAAO,CAAC,WAAW,CAAc;IAEjC,wBAAwB;IACxB,OAAO,CAAC,KAAK,CAA2B;;IAcxC;;;;;;;;;;;;;;;OAeG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4D1D;;OAEG;YACW,iBAAiB;IAqE/B;;OAEG;YACW,sBAAsB;IAcpC;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;;;OAIG;IACH,aAAa;IAIb;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * BOJ ๋ฌธ์ œ ํŽ˜์ด์ง€ ์Šคํฌ๋ž˜ํผ
3
+ *
4
+ * Phase 6 - P6-002: ๋ฌธ์ œ ๋ณธ๋ฌธ ์Šคํฌ๋ž˜ํผ ๊ตฌํ˜„
5
+ *
6
+ * fetch๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ BOJ ํŽ˜์ด์ง€ HTML์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
7
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•ด ์š”์ฒญ ๊ฐ„ ์ตœ์†Œ 3์ดˆ ๊ฐ„๊ฒฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
8
+ */
9
+ import { RateLimiter } from '../utils/rate-limiter.js';
10
+ import { LRUCache } from '../utils/lru-cache.js';
11
+ /**
12
+ * BOJ ์Šคํฌ๋ž˜ํผ ์„ค์ •
13
+ */
14
+ const BOJ_CONFIG = {
15
+ /** BOJ ๋ฌธ์ œ ํŽ˜์ด์ง€ URL ํ…œํ”Œ๋ฆฟ */
16
+ BASE_URL: 'https://www.acmicpc.net/problem',
17
+ /** User-Agent (Chrome ๋ธŒ๋ผ์šฐ์ € ํ˜•์‹ - BOJ ์š”๊ตฌ์‚ฌํ•ญ) */
18
+ USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
19
+ /** ํƒ€์ž„์•„์›ƒ (๋ฐ€๋ฆฌ์ดˆ) */
20
+ TIMEOUT: 10000,
21
+ /** ์žฌ์‹œ๋„ ํšŸ์ˆ˜ */
22
+ MAX_RETRIES: 2,
23
+ /** ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘: ์š”์ฒญ ๊ฐ„ ์ตœ์†Œ ๊ฐ„๊ฒฉ (๋ฐ€๋ฆฌ์ดˆ) */
24
+ REQUEST_INTERVAL: 3000,
25
+ };
26
+ /**
27
+ * BOJ ์Šคํฌ๋ž˜ํ•‘ ์—๋Ÿฌ
28
+ */
29
+ export class BojFetchError extends Error {
30
+ code;
31
+ originalError;
32
+ constructor(message, code, originalError) {
33
+ super(message);
34
+ this.code = code;
35
+ this.originalError = originalError;
36
+ this.name = 'BojFetchError';
37
+ }
38
+ }
39
+ /**
40
+ * BOJ ๋ฌธ์ œ ํŽ˜์ด์ง€ ์Šคํฌ๋ž˜ํผ
41
+ */
42
+ export class BOJScraper {
43
+ /** ๋งˆ์ง€๋ง‰ ์š”์ฒญ ์‹œ๊ฐ„ (์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•œ ๊ฐ„๊ฒฉ ์ œ์–ด) */
44
+ lastRequestTime = 0;
45
+ /** Rate Limiter (๋ฐฑ์—… ๋ณดํ˜ธ) */
46
+ rateLimiter;
47
+ /** HTML ์บ์‹œ (30์ผ TTL) */
48
+ cache;
49
+ constructor() {
50
+ // Rate Limiter: ์ดˆ๋‹น 5ํšŒ (3์ดˆ ๊ฐ„๊ฒฉ๋ณด๋‹ค ๊ด€๋Œ€, ๋ฐฑ์—… ์—ญํ• )
51
+ this.rateLimiter = new RateLimiter({
52
+ capacity: 5,
53
+ refillRate: 5,
54
+ maxWaitTime: 15000,
55
+ });
56
+ // HTML ์บ์‹œ: 50๊ฐœ ํ•ญ๋ชฉ, 30์ผ TTL
57
+ this.cache = new LRUCache(50, 30 * 24 * 60 * 60 * 1000);
58
+ }
59
+ /**
60
+ * ์ง€์ •๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ์˜ HTML ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
61
+ *
62
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘์„ ์œ„ํ•ด ์š”์ฒญ ๊ฐ„ ์ตœ์†Œ 3์ดˆ ๊ฐ„๊ฒฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
63
+ *
64
+ * @param problemId - BOJ ๋ฌธ์ œ ๋ฒˆํ˜ธ (์˜ˆ: 1000)
65
+ * @returns HTML ๋ฌธ์ž์—ด
66
+ * @throws {BojFetchError} ์Šคํฌ๋ž˜ํ•‘ ์‹คํŒจ ์‹œ
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const scraper = new BOJScraper();
71
+ * const html = await scraper.fetchProblemPage(1000);
72
+ * console.log(html.length); // HTML ๊ธธ์ด ์ถœ๋ ฅ
73
+ * ```
74
+ */
75
+ async fetchProblemPage(problemId) {
76
+ if (!Number.isInteger(problemId) || problemId <= 0) {
77
+ throw new BojFetchError(`์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ ๋ฒˆํ˜ธ: ${problemId}`, 'PARSE_ERROR');
78
+ }
79
+ // ์บ์‹œ ํ™•์ธ
80
+ const cached = this.cache.get(problemId);
81
+ if (cached !== undefined) {
82
+ console.log(`[BOJScraper] ์บ์‹œ ํžˆํŠธ: ๋ฌธ์ œ ${problemId}`);
83
+ return cached;
84
+ }
85
+ // Rate Limiting (๋ฐฑ์—… ๋ณดํ˜ธ, ์บ์‹œ ๋ฏธ์Šค ์‹œ์—๋งŒ)
86
+ await this.rateLimiter.acquire();
87
+ // ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘: ๋งˆ์ง€๋ง‰ ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ ์ตœ์†Œ 3์ดˆ ๊ฒฝ๊ณผ ๋ณด์žฅ
88
+ await this._ensureRequestInterval();
89
+ const url = `${BOJ_CONFIG.BASE_URL}/${problemId}`;
90
+ let lastError;
91
+ // ์žฌ์‹œ๋„ ๋กœ์ง
92
+ for (let attempt = 0; attempt <= BOJ_CONFIG.MAX_RETRIES; attempt++) {
93
+ try {
94
+ const html = await this._fetchWithTimeout(url);
95
+ // ์š”์ฒญ ์„ฑ๊ณต ์‹œ ํ˜„์žฌ ์‹œ๊ฐ„ ๊ธฐ๋ก
96
+ this.lastRequestTime = Date.now();
97
+ // ์บ์‹œ์— ์ €์žฅ
98
+ this.cache.set(problemId, html);
99
+ return html;
100
+ }
101
+ catch (error) {
102
+ lastError = error;
103
+ // 404๋Š” ์žฌ์‹œ๋„ ๋ถˆํ•„์š”
104
+ if (error instanceof BojFetchError && error.code === 'NOT_FOUND') {
105
+ throw error;
106
+ }
107
+ // ๋งˆ์ง€๋ง‰ ์‹œ๋„๊ฐ€ ์•„๋‹ˆ๋ฉด ์žฌ์‹œ๋„
108
+ if (attempt < BOJ_CONFIG.MAX_RETRIES) {
109
+ await this._delay(BOJ_CONFIG.REQUEST_INTERVAL); // ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘: ์žฌ์‹œ๋„๋„ 3์ดˆ ๊ฐ„๊ฒฉ
110
+ continue;
111
+ }
112
+ }
113
+ }
114
+ // ๋ชจ๋“  ์žฌ์‹œ๋„ ์‹คํŒจ
115
+ throw new BojFetchError(`๋ฌธ์ œ ${problemId}๋ฒˆ์„ ${BOJ_CONFIG.MAX_RETRIES + 1}๋ฒˆ ์‹œ๋„ํ–ˆ์œผ๋‚˜ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.`, 'NETWORK_ERROR', lastError);
116
+ }
117
+ /**
118
+ * ํƒ€์ž„์•„์›ƒ ์ ์šฉ๋œ HTTP ์š”์ฒญ
119
+ */
120
+ async _fetchWithTimeout(url) {
121
+ const controller = new AbortController();
122
+ const timeoutId = setTimeout(() => controller.abort(), BOJ_CONFIG.TIMEOUT);
123
+ try {
124
+ const response = await fetch(url, {
125
+ signal: controller.signal,
126
+ headers: {
127
+ 'User-Agent': BOJ_CONFIG.USER_AGENT,
128
+ 'Accept': 'text/html',
129
+ 'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
130
+ },
131
+ });
132
+ clearTimeout(timeoutId);
133
+ // 404 ์ฒ˜๋ฆฌ
134
+ if (response.status === 404) {
135
+ throw new BojFetchError(`๋ฌธ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: ${url}`, 'NOT_FOUND');
136
+ }
137
+ // ๊ธฐํƒ€ HTTP ์—๋Ÿฌ
138
+ if (!response.ok) {
139
+ throw new BojFetchError(`HTTP ์—๋Ÿฌ ${response.status}: ${response.statusText}`, 'NETWORK_ERROR');
140
+ }
141
+ const html = await response.text();
142
+ // HTML ๊ฒ€์ฆ
143
+ if (!html || html.length < 100) {
144
+ throw new BojFetchError('๋นˆ HTML ์‘๋‹ต์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.', 'PARSE_ERROR');
145
+ }
146
+ return html;
147
+ }
148
+ catch (error) {
149
+ clearTimeout(timeoutId);
150
+ // ์ด๋ฏธ BojFetchError๋ฉด ๊ทธ๋Œ€๋กœ throw
151
+ if (error instanceof BojFetchError) {
152
+ throw error;
153
+ }
154
+ // AbortError๋Š” ํƒ€์ž„์•„์›ƒ
155
+ if (error.name === 'AbortError') {
156
+ throw new BojFetchError(`์š”์ฒญ์ด ํƒ€์ž„์•„์›ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค (${BOJ_CONFIG.TIMEOUT}ms ์ดˆ๊ณผ)`, 'TIMEOUT', error);
157
+ }
158
+ // ๊ธฐํƒ€ ๋„คํŠธ์›Œํฌ ์—๋Ÿฌ
159
+ throw new BojFetchError(`๋„คํŠธ์›Œํฌ ์š”์ฒญ ์‹คํŒจ: ${error.message}`, 'NETWORK_ERROR', error);
160
+ }
161
+ }
162
+ /**
163
+ * ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘: ๋งˆ์ง€๋ง‰ ์š”์ฒญ์œผ๋กœ๋ถ€ํ„ฐ ์ตœ์†Œ ๊ฐ„๊ฒฉ ๋ณด์žฅ
164
+ */
165
+ async _ensureRequestInterval() {
166
+ if (this.lastRequestTime === 0) {
167
+ // ์ฒซ ์š”์ฒญ์€ ์ฆ‰์‹œ ์‹คํ–‰
168
+ return;
169
+ }
170
+ const elapsed = Date.now() - this.lastRequestTime;
171
+ const remaining = BOJ_CONFIG.REQUEST_INTERVAL - elapsed;
172
+ if (remaining > 0) {
173
+ await this._delay(remaining);
174
+ }
175
+ }
176
+ /**
177
+ * ์ง€์—ฐ ํ•จ์ˆ˜ (์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ ๋ฐ ์œค๋ฆฌ์  ์Šคํฌ๋ž˜ํ•‘ ๊ฐ„๊ฒฉ)
178
+ */
179
+ _delay(ms) {
180
+ return new Promise((resolve) => setTimeout(resolve, ms));
181
+ }
182
+ /**
183
+ * ์บ์‹œ ํ†ต๊ณ„ ์กฐํšŒ
184
+ *
185
+ * @returns ์บ์‹œ ํ†ต๊ณ„
186
+ */
187
+ getCacheStats() {
188
+ return this.cache.getStats();
189
+ }
190
+ /**
191
+ * ์บ์‹œ ์ดˆ๊ธฐํ™”
192
+ */
193
+ clearCache() {
194
+ this.cache.clear();
195
+ }
196
+ }
197
+ //# sourceMappingURL=boj-scraper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boj-scraper.js","sourceRoot":"","sources":["../../src/api/boj-scraper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { ProgrammersSearchOptions, ProgrammersProblemSummary, ProgrammersProblemDetail } from '../types/programmers.js';
2
+ /**
3
+ * ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ์Šคํฌ๋ž˜ํ•‘ ์—๋Ÿฌ
4
+ */
5
+ export declare class ProgrammersScrapeError extends Error {
6
+ code: 'TIMEOUT' | 'SELECTOR_NOT_FOUND' | 'NAVIGATION_ERROR' | 'PARSE_ERROR';
7
+ originalError?: unknown | undefined;
8
+ constructor(message: string, code: 'TIMEOUT' | 'SELECTOR_NOT_FOUND' | 'NAVIGATION_ERROR' | 'PARSE_ERROR', originalError?: unknown | undefined);
9
+ }
10
+ /**
11
+ * ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ์Šคํฌ๋ž˜ํผ
12
+ */
13
+ export declare class ProgrammersScraper {
14
+ private browserPool;
15
+ private rateLimiter;
16
+ private searchCache;
17
+ private problemCache;
18
+ private readonly baseUrl;
19
+ constructor();
20
+ /**
21
+ * ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ๋ฌธ์ œ ๊ฒ€์ƒ‰
22
+ *
23
+ * @param options ๊ฒ€์ƒ‰ ์˜ต์…˜
24
+ * @returns ๋ฌธ์ œ ๋ชฉ๋ก
25
+ * @throws {ProgrammersScrapeError}
26
+ */
27
+ searchProblems(options?: ProgrammersSearchOptions): Promise<ProgrammersProblemSummary[]>;
28
+ /**
29
+ * ๊ฒ€์ƒ‰ URL ์ƒ์„ฑ
30
+ */
31
+ private buildSearchUrl;
32
+ /**
33
+ * ๋ฌธ์ œ ์ƒ์„ธ ํŽ˜์ด์ง€ HTML ๊ฐ€์ ธ์˜ค๊ธฐ (fetch ๊ธฐ๋ฐ˜, BOJScraper ํŒจํ„ด)
34
+ *
35
+ * @param problemId ๋ฌธ์ œ ID
36
+ * @returns HTML ๋ฌธ์ž์—ด
37
+ * @throws {ProgrammersScrapeError}
38
+ */
39
+ fetchProblemPage(problemId: string): Promise<string>;
40
+ /**
41
+ * ํƒ€์ž„์•„์›ƒ ์ ์šฉ๋œ HTTP ์š”์ฒญ (fetch ๊ธฐ๋ฐ˜, BOJScraper ํŒจํ„ด)
42
+ */
43
+ private _fetchWithTimeout;
44
+ /**
45
+ * ์ง€์—ฐ ํ•จ์ˆ˜ (์žฌ์‹œ๋„ ๊ฐ„๊ฒฉ)
46
+ */
47
+ private _delay;
48
+ /**
49
+ * ์บ์‹œ ํ†ต๊ณ„ ์กฐํšŒ
50
+ *
51
+ * @returns ๊ฒ€์ƒ‰ ๋ฐ ๋ฌธ์ œ ์บ์‹œ ํ†ต๊ณ„
52
+ */
53
+ getCacheStats(): {
54
+ search: import("../utils/lru-cache.js").CacheStats;
55
+ problem: import("../utils/lru-cache.js").CacheStats;
56
+ };
57
+ /**
58
+ * ์บ์‹œ ์ดˆ๊ธฐํ™”
59
+ */
60
+ clearCache(): void;
61
+ /**
62
+ * ๋ฌธ์ œ ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ (fetch + cheerio ๊ธฐ๋ฐ˜)
63
+ *
64
+ * @param problemId ๋ฌธ์ œ ID
65
+ * @returns ๋ฌธ์ œ ์ƒ์„ธ ์ •๋ณด
66
+ * @throws {ProgrammersScrapeError}
67
+ */
68
+ getProblem(problemId: string): Promise<ProgrammersProblemDetail>;
69
+ }
70
+ //# sourceMappingURL=programmers-scraper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"programmers-scraper.d.ts","sourceRoot":"","sources":["../../src/api/programmers-scraper.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAGjC;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAGtC,IAAI,EACP,SAAS,GACT,oBAAoB,GACpB,kBAAkB,GAClB,aAAa;IACV,aAAa,CAAC,EAAE,OAAO;gBAN9B,OAAO,EAAE,MAAM,EACR,IAAI,EACP,SAAS,GACT,oBAAoB,GACpB,kBAAkB,GAClB,aAAa,EACV,aAAa,CAAC,EAAE,OAAO,YAAA;CAKjC;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAgD;IACnE,OAAO,CAAC,YAAY,CAA6C;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;;IAe9D;;;;;;OAMG;IACG,cAAc,CAClB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,yBAAyB,EAAE,CAAC;IA4JvC;;OAEG;IACH,OAAO,CAAC,cAAc;IAsBtB;;;;;;OAMG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA8C1D;;OAEG;YACW,iBAAiB;IAsE/B;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;;;OAIG;IACH,aAAa;;;;IAOb;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;;;;;OAMG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;CA2BvE"}