bitwrench 2.0.22 → 2.0.24

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 (88) hide show
  1. package/LICENSE.txt +1 -1
  2. package/README.md +4 -3
  3. package/bin/bwmcp.js +3 -0
  4. package/dist/bitwrench-bccl.cjs.js +1 -1
  5. package/dist/bitwrench-bccl.cjs.min.js +1 -1
  6. package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
  7. package/dist/bitwrench-bccl.esm.js +1 -1
  8. package/dist/bitwrench-bccl.esm.min.js +1 -1
  9. package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
  10. package/dist/bitwrench-bccl.umd.js +1 -1
  11. package/dist/bitwrench-bccl.umd.min.js +1 -1
  12. package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
  13. package/dist/bitwrench-code-edit.cjs.js +1 -1
  14. package/dist/bitwrench-code-edit.cjs.min.js +1 -1
  15. package/dist/bitwrench-code-edit.es5.js +1 -1
  16. package/dist/bitwrench-code-edit.es5.min.js +1 -1
  17. package/dist/bitwrench-code-edit.esm.js +1 -1
  18. package/dist/bitwrench-code-edit.esm.min.js +1 -1
  19. package/dist/bitwrench-code-edit.umd.js +1 -1
  20. package/dist/bitwrench-code-edit.umd.min.js +1 -1
  21. package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
  22. package/dist/bitwrench-debug.js +1 -1
  23. package/dist/bitwrench-debug.min.js +1 -1
  24. package/dist/bitwrench-lean.cjs.js +3 -3
  25. package/dist/bitwrench-lean.cjs.min.js +2 -2
  26. package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
  27. package/dist/bitwrench-lean.es5.js +3 -3
  28. package/dist/bitwrench-lean.es5.min.js +2 -2
  29. package/dist/bitwrench-lean.es5.min.js.gz +0 -0
  30. package/dist/bitwrench-lean.esm.js +3 -3
  31. package/dist/bitwrench-lean.esm.min.js +2 -2
  32. package/dist/bitwrench-lean.esm.min.js.gz +0 -0
  33. package/dist/bitwrench-lean.umd.js +3 -3
  34. package/dist/bitwrench-lean.umd.min.js +2 -2
  35. package/dist/bitwrench-lean.umd.min.js.gz +0 -0
  36. package/dist/bitwrench-util-css.cjs.js +1 -1
  37. package/dist/bitwrench-util-css.cjs.min.js +1 -1
  38. package/dist/bitwrench-util-css.es5.js +1 -1
  39. package/dist/bitwrench-util-css.es5.min.js +1 -1
  40. package/dist/bitwrench-util-css.esm.js +1 -1
  41. package/dist/bitwrench-util-css.esm.min.js +1 -1
  42. package/dist/bitwrench-util-css.umd.js +1 -1
  43. package/dist/bitwrench-util-css.umd.min.js +1 -1
  44. package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
  45. package/dist/bitwrench.cjs.js +3 -3
  46. package/dist/bitwrench.cjs.min.js +2 -2
  47. package/dist/bitwrench.cjs.min.js.gz +0 -0
  48. package/dist/bitwrench.css +1 -1
  49. package/dist/bitwrench.es5.js +3 -3
  50. package/dist/bitwrench.es5.min.js +2 -2
  51. package/dist/bitwrench.es5.min.js.gz +0 -0
  52. package/dist/bitwrench.esm.js +3 -3
  53. package/dist/bitwrench.esm.min.js +2 -2
  54. package/dist/bitwrench.esm.min.js.gz +0 -0
  55. package/dist/bitwrench.umd.js +3 -3
  56. package/dist/bitwrench.umd.min.js +2 -2
  57. package/dist/bitwrench.umd.min.js.gz +0 -0
  58. package/dist/builds.json +65 -65
  59. package/dist/bwserve.cjs.js +2 -2
  60. package/dist/bwserve.esm.js +2 -2
  61. package/dist/sri.json +45 -45
  62. package/docs/README.md +76 -0
  63. package/docs/app-patterns.md +264 -0
  64. package/docs/bitwrench-mcp.md +426 -0
  65. package/docs/bitwrench_api.md +2232 -0
  66. package/docs/bw-attach.md +399 -0
  67. package/docs/bwserve.md +841 -0
  68. package/docs/cli.md +307 -0
  69. package/docs/component-cheatsheet.md +144 -0
  70. package/docs/component-library.md +1099 -0
  71. package/docs/framework-translation-table.md +33 -0
  72. package/docs/llm-bitwrench-guide.md +672 -0
  73. package/docs/routing.md +562 -0
  74. package/docs/state-management.md +767 -0
  75. package/docs/taco-format.md +373 -0
  76. package/docs/theming.md +309 -0
  77. package/docs/thinking-in-bitwrench.md +1457 -0
  78. package/docs/tutorial-bwserve.md +297 -0
  79. package/docs/tutorial-embedded.md +314 -0
  80. package/docs/tutorial-website.md +255 -0
  81. package/package.json +11 -3
  82. package/readme.html +5 -4
  83. package/src/mcp/knowledge.js +231 -0
  84. package/src/mcp/live.js +226 -0
  85. package/src/mcp/server.js +216 -0
  86. package/src/mcp/tools.js +369 -0
  87. package/src/mcp/transport.js +55 -0
  88. package/src/version.js +3 -3
@@ -0,0 +1,369 @@
1
+ /**
2
+ * MCP tool definitions and handlers for bitwrench BCCL components
3
+ * and core utilities.
4
+ *
5
+ * Each tool accepts JSON args matching its inputSchema, calls the
6
+ * corresponding bw.make*() or bw.*() function, and returns an MCP
7
+ * result object.
8
+ *
9
+ * @module mcp/tools
10
+ */
11
+
12
+ import bw from '../bitwrench.js';
13
+
14
+ // -- JSON Schema helpers --
15
+
16
+ var STR = { type: 'string' };
17
+ var BOOL = { type: 'boolean' };
18
+ var OBJ = { type: 'object' };
19
+ var NUM = { type: 'number' };
20
+ var STR_OR_OBJ = { oneOf: [{ type: 'string' }, { type: 'object' }] };
21
+ var STR_OR_ARRAY = { oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'object' } }] };
22
+ var VARIANT_ENUM = {
23
+ type: 'string',
24
+ enum: ['primary', 'secondary', 'success', 'danger', 'warning', 'info'],
25
+ description: 'Color variant'
26
+ };
27
+ var SIZE_ENUM = {
28
+ type: 'string',
29
+ enum: ['sm', 'md', 'lg'],
30
+ description: 'Size variant'
31
+ };
32
+
33
+ // -- Component tool definitions (Phase 1: 10 most-used BCCL components) --
34
+
35
+ export var componentToolDefs = [
36
+ {
37
+ name: 'make_card',
38
+ title: 'Create Card Component',
39
+ description: 'Create a bitwrench card component. Returns a TACO object (JSON) that can be rendered to HTML using render_taco, or composed into larger layouts.',
40
+ inputSchema: {
41
+ type: 'object',
42
+ properties: {
43
+ title: { ...STR, description: 'Card title text' },
44
+ subtitle: { ...STR, description: 'Card subtitle text' },
45
+ content: { ...STR_OR_OBJ, description: 'Card body content. String or TACO object.' },
46
+ footer: { ...STR_OR_OBJ, description: 'Card footer content. String or TACO object.' },
47
+ header: { ...STR_OR_OBJ, description: 'Custom card header content' },
48
+ image: { ...STR, description: 'URL for card header image' },
49
+ imagePosition: { type: 'string', enum: ['top', 'bottom', 'left', 'right'], description: 'Image position (default: top)' },
50
+ variant: VARIANT_ENUM,
51
+ bordered: { ...BOOL, description: 'Show border (default: true)' },
52
+ shadow: { ...BOOL, description: 'Show shadow' },
53
+ hoverable: { ...BOOL, description: 'Hover effect (default: false)' },
54
+ className: { ...STR, description: 'Additional CSS class' }
55
+ }
56
+ }
57
+ },
58
+ {
59
+ name: 'make_button',
60
+ title: 'Create Button Component',
61
+ description: 'Create a bitwrench button. Returns a TACO object.',
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ text: { ...STR, description: 'Button text' },
66
+ variant: { ...VARIANT_ENUM, description: 'Color variant (default: primary)' },
67
+ size: SIZE_ENUM,
68
+ disabled: { ...BOOL, description: 'Disabled state' },
69
+ type: { type: 'string', enum: ['button', 'submit', 'reset'], description: 'Button type (default: button)' },
70
+ className: { ...STR, description: 'Additional CSS class' }
71
+ }
72
+ }
73
+ },
74
+ {
75
+ name: 'make_table',
76
+ title: 'Create Data Table',
77
+ description: 'Create a sortable data table. Pass data as array of objects and columns config. Returns a TACO object.',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ data: { type: 'array', items: OBJ, description: 'Array of row objects' },
82
+ columns: { type: 'array', items: OBJ, description: 'Column config: [{key, label, sortable}]' },
83
+ striped: { ...BOOL, description: 'Striped rows (default: false)' },
84
+ hover: { ...BOOL, description: 'Hover highlight (default: false)' },
85
+ sortable: { ...BOOL, description: 'Enable sorting (default: true)' },
86
+ className: { ...STR, description: 'Additional CSS class' }
87
+ }
88
+ }
89
+ },
90
+ {
91
+ name: 'make_tabs',
92
+ title: 'Create Tabs Component',
93
+ description: 'Create a tabbed interface. Each tab has a label and content. Returns a TACO object.',
94
+ inputSchema: {
95
+ type: 'object',
96
+ properties: {
97
+ tabs: {
98
+ type: 'array',
99
+ items: {
100
+ type: 'object',
101
+ properties: {
102
+ label: { ...STR, description: 'Tab label' },
103
+ content: { ...STR_OR_OBJ, description: 'Tab content (string or TACO)' }
104
+ }
105
+ },
106
+ description: 'Array of {label, content} tab objects'
107
+ },
108
+ activeIndex: { ...NUM, description: 'Initially active tab index (default: 0)' }
109
+ }
110
+ }
111
+ },
112
+ {
113
+ name: 'make_accordion',
114
+ title: 'Create Accordion Component',
115
+ description: 'Create collapsible sections. Each item has a title and content. Returns a TACO object.',
116
+ inputSchema: {
117
+ type: 'object',
118
+ properties: {
119
+ items: {
120
+ type: 'array',
121
+ items: {
122
+ type: 'object',
123
+ properties: {
124
+ title: { ...STR, description: 'Section title' },
125
+ content: { ...STR_OR_OBJ, description: 'Section content (string or TACO)' }
126
+ }
127
+ },
128
+ description: 'Array of {title, content} items'
129
+ },
130
+ multiOpen: { ...BOOL, description: 'Allow multiple sections open (default: false)' },
131
+ className: { ...STR, description: 'Additional CSS class' }
132
+ }
133
+ }
134
+ },
135
+ {
136
+ name: 'make_alert',
137
+ title: 'Create Alert Component',
138
+ description: 'Create an alert/notification box. Returns a TACO object.',
139
+ inputSchema: {
140
+ type: 'object',
141
+ properties: {
142
+ content: { ...STR_OR_OBJ, description: 'Alert message (string or TACO)' },
143
+ variant: { ...VARIANT_ENUM, description: 'Color variant (default: info)' },
144
+ dismissible: { ...BOOL, description: 'Show dismiss button (default: false)' },
145
+ className: { ...STR, description: 'Additional CSS class' }
146
+ }
147
+ }
148
+ },
149
+ {
150
+ name: 'make_nav',
151
+ title: 'Create Navigation Component',
152
+ description: 'Create horizontal or vertical navigation. Returns a TACO object.',
153
+ inputSchema: {
154
+ type: 'object',
155
+ properties: {
156
+ items: {
157
+ type: 'array',
158
+ items: {
159
+ type: 'object',
160
+ properties: {
161
+ text: { ...STR, description: 'Nav item text' },
162
+ href: { ...STR, description: 'Link URL' },
163
+ active: { ...BOOL, description: 'Active state' }
164
+ }
165
+ },
166
+ description: 'Array of {text, href, active} nav items'
167
+ },
168
+ pills: { ...BOOL, description: 'Pill style (default: false)' },
169
+ vertical: { ...BOOL, description: 'Vertical layout (default: false)' },
170
+ className: { ...STR, description: 'Additional CSS class' }
171
+ }
172
+ }
173
+ },
174
+ {
175
+ name: 'make_hero',
176
+ title: 'Create Hero Section',
177
+ description: 'Create a full-width hero section with title, subtitle, and optional call-to-action. Returns a TACO object.',
178
+ inputSchema: {
179
+ type: 'object',
180
+ properties: {
181
+ title: { ...STR, description: 'Hero title' },
182
+ subtitle: { ...STR, description: 'Hero subtitle' },
183
+ content: { ...STR_OR_OBJ, description: 'Additional content below subtitle' },
184
+ variant: { ...VARIANT_ENUM, description: 'Color variant (default: primary)' },
185
+ size: { type: 'string', enum: ['sm', 'md', 'lg', 'xl'], description: 'Size (default: lg)' },
186
+ centered: { ...BOOL, description: 'Center text (default: true)' },
187
+ overlay: { ...BOOL, description: 'Dark overlay for readability' },
188
+ backgroundImage: { ...STR, description: 'Background image URL' },
189
+ actions: { oneOf: [OBJ, { type: 'array', items: OBJ }], description: 'CTA buttons (TACO or array of TACOs)' },
190
+ className: { ...STR, description: 'Additional CSS class' }
191
+ }
192
+ }
193
+ },
194
+ {
195
+ name: 'make_stat_card',
196
+ title: 'Create Stat Card',
197
+ description: 'Create a statistic display card (KPI). Returns a TACO object.',
198
+ inputSchema: {
199
+ type: 'object',
200
+ properties: {
201
+ label: { ...STR, description: 'Stat label (e.g. "Revenue")' },
202
+ value: { ...STR_OR_OBJ, description: 'Stat value (e.g. "$12,345" or 12345)' },
203
+ change: { ...STR, description: 'Change indicator (e.g. "+5.2%")' },
204
+ prefix: { ...STR, description: 'Value prefix (e.g. "$")' },
205
+ suffix: { ...STR, description: 'Value suffix (e.g. "%")' },
206
+ icon: { ...STR, description: 'Icon text or emoji' },
207
+ variant: VARIANT_ENUM,
208
+ className: { ...STR, description: 'Additional CSS class' }
209
+ }
210
+ }
211
+ },
212
+ {
213
+ name: 'make_form_group',
214
+ title: 'Create Form Group',
215
+ description: 'Create a label + input wrapper for forms. Returns a TACO object.',
216
+ inputSchema: {
217
+ type: 'object',
218
+ properties: {
219
+ label: { ...STR, description: 'Field label text' },
220
+ input: { ...OBJ, description: 'Input TACO (e.g. from make_input)' },
221
+ help: { ...STR, description: 'Help text below input' },
222
+ id: { ...STR, description: 'Input id attribute' },
223
+ required: { ...BOOL, description: 'Mark as required' },
224
+ validation: { ...STR, description: 'Validation state: valid, invalid' },
225
+ feedback: { ...STR, description: 'Validation feedback message' }
226
+ }
227
+ }
228
+ }
229
+ ];
230
+
231
+ // -- Core utility tool definitions --
232
+
233
+ export var utilityToolDefs = [
234
+ {
235
+ name: 'render_taco',
236
+ title: 'Render TACO to HTML',
237
+ description: 'Convert a TACO object to an HTML string. Use this to preview or save the output of any TACO-producing tool.',
238
+ inputSchema: {
239
+ type: 'object',
240
+ properties: {
241
+ taco: {
242
+ type: 'object',
243
+ description: 'TACO object with fields: t (tag), a (attributes), c (content), o (options).',
244
+ properties: {
245
+ t: { ...STR, description: 'HTML tag name (div, p, h1, etc.)' },
246
+ a: { ...OBJ, description: 'HTML attributes (class, id, style, etc.)' },
247
+ c: { description: 'Content: string, TACO, or array of strings/TACOs' }
248
+ },
249
+ required: ['t']
250
+ },
251
+ indent: { ...BOOL, description: 'Pretty-print with indentation (default: false)' }
252
+ },
253
+ required: ['taco']
254
+ }
255
+ },
256
+ {
257
+ name: 'build_page',
258
+ title: 'Build Complete HTML Page',
259
+ description: 'Generate a complete, standalone HTML page with bitwrench styles and scripts inlined. The output is a single .html file that works offline. Use this as the final step after composing your TACO layout.',
260
+ inputSchema: {
261
+ type: 'object',
262
+ properties: {
263
+ title: { ...STR, description: 'Page title (shown in browser tab)' },
264
+ content: {
265
+ description: 'Page body content as TACO object or array of TACOs',
266
+ oneOf: [OBJ, { type: 'array', items: OBJ }]
267
+ },
268
+ theme: { ...STR, description: 'Theme preset name (ocean, forest, sunset, midnight, slate, rose, indigo, amber, emerald, nord, coral, teal) or hex color for primary seed' },
269
+ description: { ...STR, description: 'Meta description for SEO' },
270
+ runtime: { type: 'string', enum: ['inline', 'cdn', 'shim', 'none'], description: 'How to include bitwrench runtime (default: inline for standalone pages)' }
271
+ },
272
+ required: ['title', 'content']
273
+ }
274
+ },
275
+ {
276
+ name: 'make_styles',
277
+ title: 'Generate CSS from Theme Config',
278
+ description: 'Generate CSS stylesheet from seed colors. Returns CSS text that can be included in pages. Use this for custom theming beyond the built-in presets.',
279
+ inputSchema: {
280
+ type: 'object',
281
+ properties: {
282
+ primary: { ...STR, description: 'Primary color hex (e.g. "#4f46e5")' },
283
+ secondary: { ...STR, description: 'Secondary color hex' },
284
+ background: { ...STR, description: 'Background color hex' },
285
+ surface: { ...STR, description: 'Surface color hex' }
286
+ },
287
+ required: ['primary']
288
+ }
289
+ }
290
+ ];
291
+
292
+ // -- Tool handlers --
293
+
294
+ /**
295
+ * Call a BCCL make*() function. Maps tool name (snake_case) to bw method (camelCase).
296
+ */
297
+ function callBCCL(toolName, args) {
298
+ // make_card -> makeCard, make_stat_card -> makeStatCard
299
+ var methodName = toolName.replace(/_([a-z])/g, function(_, c) { return c.toUpperCase(); });
300
+ var fn = bw[methodName];
301
+ if (typeof fn !== 'function') {
302
+ return { content: [{ type: 'text', text: 'Internal error: bw.' + methodName + ' not found' }], isError: true };
303
+ }
304
+ try {
305
+ var taco = fn(args || {});
306
+ return {
307
+ content: [{ type: 'text', text: JSON.stringify(taco) }],
308
+ structuredContent: taco
309
+ };
310
+ } catch (e) {
311
+ return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
312
+ }
313
+ }
314
+
315
+ export var toolHandlers = {
316
+ // Component tools
317
+ make_card: function(args) { return callBCCL('make_card', args); },
318
+ make_button: function(args) { return callBCCL('make_button', args); },
319
+ make_table: function(args) { return callBCCL('make_table', args); },
320
+ make_tabs: function(args) { return callBCCL('make_tabs', args); },
321
+ make_accordion: function(args) { return callBCCL('make_accordion', args); },
322
+ make_alert: function(args) { return callBCCL('make_alert', args); },
323
+ make_nav: function(args) { return callBCCL('make_nav', args); },
324
+ make_hero: function(args) { return callBCCL('make_hero', args); },
325
+ make_stat_card: function(args) { return callBCCL('make_stat_card', args); },
326
+ make_form_group: function(args) { return callBCCL('make_form_group', args); },
327
+
328
+ // Core utilities
329
+ render_taco: function(args) {
330
+ try {
331
+ var opts = {};
332
+ if (args.indent) opts.indent = true;
333
+ var html = bw.html(args.taco, opts);
334
+ return { content: [{ type: 'text', text: html }] };
335
+ } catch (e) {
336
+ return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
337
+ }
338
+ },
339
+
340
+ build_page: function(args) {
341
+ try {
342
+ var html = bw.htmlPage({
343
+ title: args.title,
344
+ body: args.content,
345
+ theme: args.theme || null,
346
+ runtime: args.runtime || 'inline',
347
+ description: args.description || ''
348
+ });
349
+ return { content: [{ type: 'text', text: html }] };
350
+ } catch (e) {
351
+ return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
352
+ }
353
+ },
354
+
355
+ make_styles: function(args) {
356
+ try {
357
+ var styles = bw.makeStyles(args);
358
+ return {
359
+ content: [{ type: 'text', text: styles.css }],
360
+ structuredContent: {
361
+ css: styles.css,
362
+ isLightPrimary: styles.isLightPrimary
363
+ }
364
+ };
365
+ } catch (e) {
366
+ return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
367
+ }
368
+ }
369
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * MCP stdio transport -- newline-delimited JSON-RPC over stdin/stdout.
3
+ *
4
+ * stdout is reserved for MCP protocol messages only.
5
+ * All logging goes to stderr.
6
+ *
7
+ * @module mcp/transport
8
+ */
9
+
10
+ /**
11
+ * Create a stdio transport that reads JSON-RPC messages from an input
12
+ * stream and writes responses to an output stream.
13
+ *
14
+ * @param {Function} onMessage - Called with each parsed JSON-RPC message
15
+ * @param {Object} [opts]
16
+ * @param {NodeJS.ReadableStream} [opts.input=process.stdin]
17
+ * @param {NodeJS.WritableStream} [opts.output=process.stdout]
18
+ * @returns {{ send: Function, close: Function }}
19
+ */
20
+ export function createStdioTransport(onMessage, opts) {
21
+ opts = opts || {};
22
+ var input = opts.input || process.stdin;
23
+ var output = opts.output || process.stdout;
24
+ var buffer = '';
25
+
26
+ input.setEncoding('utf8');
27
+
28
+ function onData(chunk) {
29
+ buffer += chunk;
30
+ var lines = buffer.split('\n');
31
+ buffer = lines.pop(); // keep incomplete line in buffer
32
+ for (var i = 0; i < lines.length; i++) {
33
+ var line = lines[i].trim();
34
+ if (!line) continue;
35
+ try {
36
+ var msg = JSON.parse(line);
37
+ onMessage(msg);
38
+ } catch (e) {
39
+ process.stderr.write('[bwmcp] Invalid JSON: ' + e.message + '\n');
40
+ }
41
+ }
42
+ }
43
+
44
+ input.on('data', onData);
45
+
46
+ function send(msg) {
47
+ output.write(JSON.stringify(msg) + '\n');
48
+ }
49
+
50
+ function close() {
51
+ input.removeListener('data', onData);
52
+ }
53
+
54
+ return { send: send, close: close };
55
+ }
package/src/version.js CHANGED
@@ -3,14 +3,14 @@
3
3
  * DO NOT EDIT DIRECTLY - Use npm run generate-version
4
4
  */
5
5
 
6
- export const VERSION = '2.0.22';
6
+ export const VERSION = '2.0.24';
7
7
  export const VERSION_INFO = {
8
- version: '2.0.22',
8
+ version: '2.0.24',
9
9
  name: 'bitwrench',
10
10
  description: 'A library for javascript UI functions.',
11
11
  license: 'BSD-2-Clause',
12
12
  homepage: 'https://deftio.github.com/bitwrench/pages',
13
13
  repository: 'git+https://github.com/deftio/bitwrench.git',
14
14
  author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
15
- buildDate: '2026-03-24T05:38:12.852Z'
15
+ buildDate: '2026-03-28T09:12:50.073Z'
16
16
  };