@dreamtree-org/twreact-ui 1.3.0 → 1.3.2

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 (234) hide show
  1. package/DESIGN.md +2 -2
  2. package/README.md +258 -10
  3. package/ai-skills/dreamtree-ui.md +111 -15
  4. package/charts/package.json +5 -0
  5. package/dist/_shared/cn-DPPQUJu1.js +138 -0
  6. package/dist/ai-schema.json +1252 -179
  7. package/dist/charts/index.d.ts +9 -0
  8. package/dist/charts/index.d.ts.map +1 -0
  9. package/dist/charts/index.js +769 -0
  10. package/dist/components/charts/AreaChart.d.ts +4 -0
  11. package/dist/components/charts/AreaChart.d.ts.map +1 -0
  12. package/dist/components/charts/BarChart.d.ts +4 -0
  13. package/dist/components/charts/BarChart.d.ts.map +1 -0
  14. package/dist/components/charts/CartesianChart.d.ts +5 -0
  15. package/dist/components/charts/CartesianChart.d.ts.map +1 -0
  16. package/dist/components/charts/ChartFrame.d.ts +18 -0
  17. package/dist/components/charts/ChartFrame.d.ts.map +1 -0
  18. package/dist/components/charts/DonutChart.d.ts +4 -0
  19. package/dist/components/charts/DonutChart.d.ts.map +1 -0
  20. package/dist/components/charts/LineChart.d.ts +4 -0
  21. package/dist/components/charts/LineChart.d.ts.map +1 -0
  22. package/dist/components/charts/Sparkline.d.ts +5 -0
  23. package/dist/components/charts/Sparkline.d.ts.map +1 -0
  24. package/dist/components/charts/chartTheme.d.ts +26 -0
  25. package/dist/components/charts/chartTheme.d.ts.map +1 -0
  26. package/dist/components/core/Accordion.d.ts.map +1 -1
  27. package/dist/components/core/Button.d.ts.map +1 -1
  28. package/dist/components/core/Checkbox.d.ts.map +1 -1
  29. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  30. package/dist/components/core/DatePicker.d.ts.map +1 -1
  31. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  32. package/dist/components/core/Form.d.ts.map +1 -1
  33. package/dist/components/core/Input.d.ts.map +1 -1
  34. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  35. package/dist/components/core/Popover.d.ts +4 -0
  36. package/dist/components/core/Popover.d.ts.map +1 -0
  37. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  38. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  39. package/dist/components/core/Radio.d.ts.map +1 -1
  40. package/dist/components/core/Rate.d.ts.map +1 -1
  41. package/dist/components/core/Select.d.ts.map +1 -1
  42. package/dist/components/core/Skeleton.d.ts.map +1 -1
  43. package/dist/components/core/Slider.d.ts +4 -0
  44. package/dist/components/core/Slider.d.ts.map +1 -0
  45. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  46. package/dist/components/core/Switch.d.ts.map +1 -1
  47. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  48. package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
  49. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  50. package/dist/components/core/Table/MobileCard.d.ts +2 -2
  51. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  52. package/dist/components/core/Table/Table.d.ts.map +1 -1
  53. package/dist/components/core/Table/TableRow.d.ts +4 -2
  54. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  55. package/dist/components/core/Tabs.d.ts.map +1 -1
  56. package/dist/components/core/Textarea.d.ts +4 -0
  57. package/dist/components/core/Textarea.d.ts.map +1 -0
  58. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  59. package/dist/components/core/Tooltip.d.ts.map +1 -1
  60. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  61. package/dist/components/feedback/Drawer.d.ts +4 -0
  62. package/dist/components/feedback/Drawer.d.ts.map +1 -0
  63. package/dist/components/feedback/Toast.d.ts +14 -5
  64. package/dist/components/feedback/Toast.d.ts.map +1 -1
  65. package/dist/components/feedback/Tour.d.ts +4 -0
  66. package/dist/components/feedback/Tour.d.ts.map +1 -0
  67. package/dist/components/feedback/TourSpotlight.d.ts +9 -0
  68. package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
  69. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  70. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  71. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  72. package/dist/components/navigation/Sidebar.d.ts +8 -2
  73. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  74. package/dist/components/rich-text/RichTextEditor.d.ts +4 -0
  75. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -0
  76. package/dist/components/rich-text/RichTextToolbar.d.ts +219 -0
  77. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -0
  78. package/dist/components/utility/Badge.d.ts.map +1 -1
  79. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  80. package/dist/components/utility/Sortable.d.ts +4 -0
  81. package/dist/components/utility/Sortable.d.ts.map +1 -0
  82. package/dist/esm/_vendor/object-assign/index.js +99 -0
  83. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
  84. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
  85. package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
  86. package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
  87. package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
  88. package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
  89. package/dist/esm/_vendor/prop-types/index.js +30 -0
  90. package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
  91. package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
  92. package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
  93. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  94. package/dist/esm/_virtual/index.js +3 -0
  95. package/dist/esm/_virtual/index2.js +3 -0
  96. package/dist/esm/_virtual/react-is.development.js +3 -0
  97. package/dist/esm/_virtual/react-is.production.min.js +3 -0
  98. package/dist/esm/charts/index.js +5 -0
  99. package/dist/esm/components/blocks/AppShell.js +205 -0
  100. package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
  101. package/dist/esm/components/blocks/EmptyState.js +44 -0
  102. package/dist/esm/components/blocks/ErrorState.js +53 -0
  103. package/dist/esm/components/blocks/LoadingState.js +134 -0
  104. package/dist/esm/components/blocks/PageHeader.js +51 -0
  105. package/dist/esm/components/blocks/StatCard.js +79 -0
  106. package/dist/esm/components/blocks/StatusPill.js +55 -0
  107. package/dist/esm/components/charts/AreaChart.js +16 -0
  108. package/dist/esm/components/charts/BarChart.js +16 -0
  109. package/dist/esm/components/charts/CartesianChart.js +250 -0
  110. package/dist/esm/components/charts/ChartFrame.js +170 -0
  111. package/dist/esm/components/charts/DonutChart.js +119 -0
  112. package/dist/esm/components/charts/LineChart.js +16 -0
  113. package/dist/esm/components/charts/Sparkline.js +110 -0
  114. package/dist/esm/components/charts/chartTheme.js +109 -0
  115. package/dist/esm/components/core/Accordion.js +260 -0
  116. package/dist/esm/components/core/Button.js +59 -0
  117. package/dist/esm/components/core/Checkbox.js +188 -0
  118. package/dist/esm/components/core/ColorPicker.js +348 -0
  119. package/dist/esm/components/core/DatePicker.js +436 -0
  120. package/dist/esm/components/core/DateRangePicker.js +494 -0
  121. package/dist/esm/components/core/Form.js +522 -0
  122. package/dist/esm/components/core/Input.js +179 -0
  123. package/dist/esm/components/core/Loader.js +141 -0
  124. package/dist/esm/components/core/LocationPicker.js +161 -0
  125. package/dist/esm/components/core/Popover.js +171 -0
  126. package/dist/esm/components/core/PriceRangePicker.js +376 -0
  127. package/dist/esm/components/core/ProgressBar.js +152 -0
  128. package/dist/esm/components/core/Radio.js +156 -0
  129. package/dist/esm/components/core/Rate.js +197 -0
  130. package/dist/esm/components/core/RoundedTag.js +118 -0
  131. package/dist/esm/components/core/Select.js +857 -0
  132. package/dist/esm/components/core/Skeleton.js +100 -0
  133. package/dist/esm/components/core/Slider.js +134 -0
  134. package/dist/esm/components/core/SpeechToText.js +226 -0
  135. package/dist/esm/components/core/Switch.js +207 -0
  136. package/dist/esm/components/core/Table/ActionMenu.js +251 -0
  137. package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
  138. package/dist/esm/components/core/Table/FieldInput.js +157 -0
  139. package/dist/esm/components/core/Table/MobileCard.js +187 -0
  140. package/dist/esm/components/core/Table/MobileFilters.js +72 -0
  141. package/dist/esm/components/core/Table/Pagination.js +157 -0
  142. package/dist/esm/components/core/Table/Table.js +1533 -0
  143. package/dist/esm/components/core/Table/TableRow.js +254 -0
  144. package/dist/esm/components/core/Table/constants.js +35 -0
  145. package/dist/esm/components/core/Table/helpers.js +124 -0
  146. package/dist/esm/components/core/Table/useClickOutside.js +26 -0
  147. package/dist/esm/components/core/Tabs.js +289 -0
  148. package/dist/esm/components/core/TextToSpeech.js +52 -0
  149. package/dist/esm/components/core/Textarea.js +125 -0
  150. package/dist/esm/components/core/ThreeDotPopover.js +160 -0
  151. package/dist/esm/components/core/Tooltip.js +372 -0
  152. package/dist/esm/components/feedback/Alert.js +96 -0
  153. package/dist/esm/components/feedback/Dialog.js +200 -0
  154. package/dist/esm/components/feedback/Drawer.js +171 -0
  155. package/dist/esm/components/feedback/Toast.js +362 -0
  156. package/dist/esm/components/feedback/Tour.js +214 -0
  157. package/dist/esm/components/feedback/TourSpotlight.js +71 -0
  158. package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
  159. package/dist/esm/components/navigation/Dropdown.js +53 -0
  160. package/dist/esm/components/navigation/FootNav.js +51 -0
  161. package/dist/esm/components/navigation/Navbar.js +437 -0
  162. package/dist/esm/components/navigation/Sidebar.js +567 -0
  163. package/dist/esm/components/rich-text/RichTextEditor.js +244 -0
  164. package/dist/esm/components/rich-text/RichTextToolbar.js +397 -0
  165. package/dist/esm/components/utility/Avatar.js +89 -0
  166. package/dist/esm/components/utility/Badge.js +47 -0
  167. package/dist/esm/components/utility/Card.js +85 -0
  168. package/dist/esm/components/utility/Carousel.js +97 -0
  169. package/dist/esm/components/utility/Condition.js +9 -0
  170. package/dist/esm/components/utility/FileUpload.js +177 -0
  171. package/dist/esm/components/utility/Pagination.js +111 -0
  172. package/dist/esm/components/utility/Sortable.js +190 -0
  173. package/dist/esm/components/utility/Stepper.js +101 -0
  174. package/dist/esm/hooks/useApi.js +169 -0
  175. package/dist/esm/hooks/useControllableState.js +32 -0
  176. package/dist/esm/hooks/useFocusTrap.js +85 -0
  177. package/dist/esm/hooks/useLatestRef.js +20 -0
  178. package/dist/esm/hooks/useMixins.js +100 -0
  179. package/dist/esm/hooks/useScrollLock.js +26 -0
  180. package/dist/esm/hooks/useSliderValues.js +135 -0
  181. package/dist/esm/hooks/useSortable.js +188 -0
  182. package/dist/esm/hooks/useTheme.js +53 -0
  183. package/dist/esm/hooks/useTourTarget.js +92 -0
  184. package/dist/esm/index.js +65 -0
  185. package/dist/esm/rich-text/index.js +1 -0
  186. package/dist/esm/store/index.js +26 -0
  187. package/dist/esm/store/store.js +107 -0
  188. package/dist/esm/store/storeSlice.js +45 -0
  189. package/dist/esm/utils/cn.js +11 -0
  190. package/dist/esm/utils/emitter.js +169 -0
  191. package/dist/esm/utils/helpers.js +161 -0
  192. package/dist/esm/utils/position.js +134 -0
  193. package/dist/hooks/useApi.d.ts +2 -1
  194. package/dist/hooks/useApi.d.ts.map +1 -1
  195. package/dist/hooks/useControllableState.d.ts +11 -0
  196. package/dist/hooks/useControllableState.d.ts.map +1 -0
  197. package/dist/hooks/useFocusTrap.d.ts +15 -0
  198. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  199. package/dist/hooks/useLatestRef.d.ts +8 -0
  200. package/dist/hooks/useLatestRef.d.ts.map +1 -0
  201. package/dist/hooks/useMixins.d.ts.map +1 -1
  202. package/dist/hooks/useScrollLock.d.ts +2 -0
  203. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  204. package/dist/hooks/useSliderValues.d.ts +43 -0
  205. package/dist/hooks/useSliderValues.d.ts.map +1 -0
  206. package/dist/hooks/useSortable.d.ts +32 -0
  207. package/dist/hooks/useSortable.d.ts.map +1 -0
  208. package/dist/hooks/useTheme.d.ts.map +1 -1
  209. package/dist/hooks/useTourTarget.d.ts +15 -0
  210. package/dist/hooks/useTourTarget.d.ts.map +1 -0
  211. package/dist/index.css +1 -1
  212. package/dist/index.d.ts +8 -2
  213. package/dist/index.esm.css +1 -1
  214. package/dist/index.esm.js +4817 -2216
  215. package/dist/index.js +4822 -2214
  216. package/dist/rich-text/index.d.ts +5 -0
  217. package/dist/rich-text/index.d.ts.map +1 -0
  218. package/dist/rich-text/index.js +654 -0
  219. package/dist/tokens/brands/studio.css +14 -0
  220. package/dist/tokens/brands/studio.json +20 -0
  221. package/dist/types/charts.d.ts +97 -0
  222. package/dist/types/charts.d.ts.map +1 -0
  223. package/dist/types/index.d.ts +193 -5
  224. package/dist/types/index.d.ts.map +1 -1
  225. package/dist/types/rich-text.d.ts +50 -0
  226. package/dist/types/rich-text.d.ts.map +1 -0
  227. package/dist/utils/position.d.ts +30 -0
  228. package/dist/utils/position.d.ts.map +1 -0
  229. package/doc/README.md +20 -1
  230. package/mcp/catalog.snapshot.json +2505 -800
  231. package/mcp/server-core.mjs +30 -1
  232. package/package.json +51 -3
  233. package/rich-text/package.json +5 -0
  234. package/tokens/brands/studio.json +20 -0
@@ -38,10 +38,15 @@ function asText(obj) {
38
38
  return { content: [{ type: "text", text: typeof obj === "string" ? obj : JSON.stringify(obj, null, 2) }] };
39
39
  }
40
40
 
41
+ // The module a catalog entry is imported from: the root package, or an
42
+ // optional-peer subpath such as "@dreamtree-org/twreact-ui/charts".
43
+ const importFrom = (c) => c.importFrom || PKG;
44
+
41
45
  function componentSummary(c) {
42
46
  return {
43
47
  name: c.name,
44
48
  group: c.group,
49
+ importFrom: importFrom(c),
45
50
  familyExports: c.familyExports,
46
51
  hasDoc: c.hasDoc,
47
52
  description: c.description,
@@ -53,7 +58,13 @@ function fullComponent(c) {
53
58
  name: c.name,
54
59
  group: c.group,
55
60
  familyExports: c.familyExports,
56
- import: `import { ${[c.name, ...c.familyExports].join(", ")} } from "${PKG}";`,
61
+ import: `import { ${[c.name, ...c.familyExports].join(", ")} } from "${importFrom(c)}";`,
62
+ ...(c.peerDependencies && c.peerDependencies.length
63
+ ? {
64
+ peerDependencies: c.peerDependencies,
65
+ install: `npm install ${c.peerDependencies.join(" ")}`,
66
+ }
67
+ : {}),
57
68
  description: c.description,
58
69
  props: c.props,
59
70
  examples: c.examples,
@@ -106,6 +117,23 @@ const TOOLS = [
106
117
  },
107
118
  ];
108
119
 
120
+ // One prompt line per optional-peer subpath, derived from the catalog so it
121
+ // cannot drift from the real entry points.
122
+ function subpathRules(c) {
123
+ const bySubpath = new Map();
124
+ for (const x of c.components) {
125
+ if (importFrom(x) === PKG) continue;
126
+ if (!bySubpath.has(x.importFrom)) bySubpath.set(x.importFrom, { names: [], peers: x.peerDependencies || [] });
127
+ bySubpath.get(x.importFrom).names.push(x.name);
128
+ }
129
+ return [...bySubpath]
130
+ .map(
131
+ ([from, { names, peers }]) =>
132
+ `- ${names.join(", ")} must be imported from "${from}" (never the root); it needs the optional peer(s) ${peers.join(" ")}.\n`
133
+ )
134
+ .join("");
135
+ }
136
+
109
137
  const SKILL_URI = "dreamtree://skill";
110
138
  const docName = (name) => `dreamtree://docs/${name}`;
111
139
 
@@ -223,6 +251,7 @@ export function createServer({ version, catalog }) {
223
251
  `- Use the shared vocabulary: variant = primary|secondary|outline|ghost|destructive|success|warning; size = xs|sm|md|lg|xl. Never pass a raw color prop.\n` +
224
252
  `- Wrap the tree in <ThemeProvider> when using dark mode or useTheme; <StoreProvider> only if using useMixins.\n` +
225
253
  `- The consumer's tailwind.config.js content[] must include ./node_modules/${PKG}/dist/**/*.{js,mjs}.\n` +
254
+ subpathRules(c) +
226
255
  `- Read the dreamtree://skill resource for full wiring + examples.\n` +
227
256
  (task ? `\nTask: ${task}\n` : "");
228
257
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamtree-org/twreact-ui",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "A comprehensive React + Tailwind components library for building modern web apps",
5
5
  "author": {
6
6
  "name": "Partha Preetham Krishna",
@@ -8,14 +8,38 @@
8
8
  "url": "https://www.linkedin.com/in/partha-preetham-krishna-68ba00197/"
9
9
  },
10
10
  "main": "dist/index.js",
11
- "module": "dist/index.esm.js",
11
+ "module": "dist/esm/index.js",
12
12
  "types": "dist/index.d.ts",
13
13
  "typings": "dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "module": "./dist/esm/index.js",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./charts": {
21
+ "types": "./dist/charts/index.d.ts",
22
+ "module": "./dist/esm/charts/index.js",
23
+ "default": "./dist/charts/index.js"
24
+ },
25
+ "./rich-text": {
26
+ "types": "./dist/rich-text/index.d.ts",
27
+ "module": "./dist/esm/rich-text/index.js",
28
+ "default": "./dist/rich-text/index.js"
29
+ },
30
+ "./package.json": "./package.json",
31
+ "./*": "./*"
32
+ },
33
+ "sideEffects": [
34
+ "**/*.css"
35
+ ],
14
36
  "bin": {
15
37
  "twreact-ui": "./bin/cli.mjs"
16
38
  },
17
39
  "files": [
18
40
  "dist",
41
+ "charts/package.json",
42
+ "rich-text/package.json",
19
43
  "bin/cli.mjs",
20
44
  "mcp/server-core.mjs",
21
45
  "mcp/catalog-core.mjs",
@@ -100,7 +124,25 @@
100
124
  },
101
125
  "peerDependencies": {
102
126
  "react": "^18.3.1 || ^19.0.0",
103
- "react-dom": "^18.3.1 || ^19.0.0"
127
+ "react-dom": "^18.3.1 || ^19.0.0",
128
+ "@tiptap/pm": "^3.0.0",
129
+ "@tiptap/react": "^3.0.0",
130
+ "@tiptap/starter-kit": "^3.0.0",
131
+ "recharts": "^2.15.0 || ^3.0.0"
132
+ },
133
+ "peerDependenciesMeta": {
134
+ "@tiptap/pm": {
135
+ "optional": true
136
+ },
137
+ "@tiptap/react": {
138
+ "optional": true
139
+ },
140
+ "@tiptap/starter-kit": {
141
+ "optional": true
142
+ },
143
+ "recharts": {
144
+ "optional": true
145
+ }
104
146
  },
105
147
  "dependencies": {
106
148
  "@hookform/resolvers": "^3.10.0",
@@ -132,6 +174,10 @@
132
174
  "@storybook/react-vite": "8.6.15",
133
175
  "@testing-library/jest-dom": "^6.9.1",
134
176
  "@testing-library/react": "^13.4.0",
177
+ "@tiptap/core": "^3.32.0",
178
+ "@tiptap/pm": "^3.32.0",
179
+ "@tiptap/react": "^3.32.0",
180
+ "@tiptap/starter-kit": "^3.32.0",
135
181
  "@types/jest": "^29.5.14",
136
182
  "@types/node": "^22.10.2",
137
183
  "@types/react": "^18.3.18",
@@ -151,6 +197,8 @@
151
197
  "postcss": "^8.5.6",
152
198
  "react": "^18.3.1",
153
199
  "react-dom": "^18.3.1",
200
+ "react-is": "^18.3.1",
201
+ "recharts": "^3.10.1",
154
202
  "rollup": "^4.57.1",
155
203
  "rollup-plugin-peer-deps-external": "^2.2.4",
156
204
  "rollup-plugin-postcss": "^4.0.2",
@@ -0,0 +1,5 @@
1
+ {
2
+ "main": "../dist/rich-text/index.js",
3
+ "module": "../dist/esm/rich-text/index.js",
4
+ "types": "../dist/rich-text/index.d.ts"
5
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "studio",
3
+ "label": "Dreamtree Studio",
4
+ "$description": "Indigo primary for Dreamtree Studio, the MCP prototyping harness (its own app pages, not the prototypes it renders). The shell, background and text roles are the shared slate defaults, so only the primary scale changes. Indigo 600 (#4f46e5) is 6.3:1 on white and 600/700 pass WCAG AA for text on white.",
5
+ "color": {
6
+ "primary": {
7
+ "50": "#eef2ff",
8
+ "100": "#e0e7ff",
9
+ "200": "#c7d2fe",
10
+ "300": "#a5b4fc",
11
+ "400": "#818cf8",
12
+ "500": "#6366f1",
13
+ "600": "#4f46e5",
14
+ "700": "#4338ca",
15
+ "800": "#3730a3",
16
+ "900": "#312e81",
17
+ "950": "#1e1b4b"
18
+ }
19
+ }
20
+ }