@devtron-labs/devtron-fe-common-lib 1.22.0-beta-9 → 1.22.0-beta-11

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.
@@ -0,0 +1,592 @@
1
+ import { j as n, be as $, bf as W, bg as J, bh as K, bi as B, bj as V, aP as v, bk as q, bl as Y, aR as G, aQ as z, bm as Q, bn as X, b as Z, bo as ee } from "./@vendor-CIlxgD4r.js";
2
+ import te, { useState as ne, useEffect as se, forwardRef as ae, useMemo as E } from "react";
3
+ import { T as O, j as w, c as T, b as N, S as re, i as oe, g as le, a as ie, d as R, e as ce } from "./@code-editor-3oNEo5OH.js";
4
+ import { ReactComponent as de } from "./assets/ic-add.cfaa779b.svg";
5
+ import { ReactComponent as ue } from "./assets/ic-warning.ecf7ff97.svg";
6
+ import { ReactComponent as me } from "./assets/ic-cross.01e03666.svg";
7
+ import './assets/@common-rjsf.css';const F = {
8
+ SELECT: "Please select an option",
9
+ INPUT: "Please enter an input",
10
+ OBJECT_KEY: "Please enter a value for the key"
11
+ }, pe = "Key not available", Me = {
12
+ "ui:submitButtonOptions": {
13
+ norender: !0
14
+ }
15
+ }, L = "rjsf-form-select-portal-target", fe = ({
16
+ children: e,
17
+ disabled: t,
18
+ hasToolbar: a,
19
+ hasRemove: s,
20
+ onRemoveItem: r,
21
+ readonly: i,
22
+ registry: o,
23
+ uiSchema: l
24
+ }) => {
25
+ const { RemoveButton: c } = o.templates.ButtonTemplates;
26
+ return /* @__PURE__ */ n.jsxs("div", { className: "dc__position-rel display-grid rjsf-form-template__array-field-item flex-align-center", children: [
27
+ e,
28
+ /* @__PURE__ */ n.jsx("div", { className: "dc__position-abs remove-btn__container", style: { right: "-28px", top: "9px" }, children: a && s && /* @__PURE__ */ n.jsx(
29
+ c,
30
+ {
31
+ disabled: t || i,
32
+ onClick: r,
33
+ uiSchema: l,
34
+ registry: o
35
+ }
36
+ ) })
37
+ ] });
38
+ }, S = ({
39
+ showLabel: e,
40
+ label: t,
41
+ required: a,
42
+ children: s,
43
+ id: r,
44
+ rawDescription: i,
45
+ shouldAlignCenter: o = !0
46
+ }) => /* @__PURE__ */ n.jsxs(
47
+ "div",
48
+ {
49
+ className: e ? `display-grid dc__gap-12 rjsf-form-template__field ${o ? "" : "rjsf-form-template__field--align-top"}` : "",
50
+ children: [
51
+ e && /* @__PURE__ */ n.jsxs("label", { className: "cn-7 fs-13 lh-20 fw-4 flexbox mb-0", htmlFor: r, children: [
52
+ /* @__PURE__ */ n.jsx(O, { alwaysShowTippyOnHover: !!i, content: i, children: /* @__PURE__ */ n.jsx("span", { className: `dc__ellipsis-right ${i ? "dc__underline-dotted" : ""}`, children: t || pe }) }),
53
+ a && /* @__PURE__ */ n.jsx("span", { className: "cr-5", children: " *" })
54
+ ] }),
55
+ s
56
+ ]
57
+ }
58
+ ), A = ({ label: e, canAdd: t, onAddClick: a, disabled: s, readonly: r, uiSchema: i, registry: o }) => {
59
+ const {
60
+ ButtonTemplates: { AddButton: l }
61
+ } = o.templates;
62
+ return t && /* @__PURE__ */ n.jsx(
63
+ l,
64
+ {
65
+ label: e,
66
+ onClick: a,
67
+ disabled: s || r,
68
+ uiSchema: i,
69
+ registry: o
70
+ }
71
+ );
72
+ }, he = ({
73
+ canAdd: e,
74
+ className: t,
75
+ disabled: a,
76
+ fieldPathId: s,
77
+ uiSchema: r,
78
+ items: i,
79
+ onAddClick: o,
80
+ readonly: l,
81
+ registry: c,
82
+ required: d,
83
+ title: p
84
+ }) => {
85
+ const u = $(r).title || p;
86
+ return /* @__PURE__ */ n.jsx("fieldset", { className: t, id: s.$id, children: i.length ? /* @__PURE__ */ n.jsxs(n.Fragment, { children: [
87
+ i,
88
+ /* @__PURE__ */ n.jsx(
89
+ A,
90
+ {
91
+ label: u,
92
+ canAdd: e,
93
+ onAddClick: o,
94
+ disabled: a,
95
+ readonly: l,
96
+ uiSchema: r,
97
+ registry: c
98
+ }
99
+ )
100
+ ] }) : /* @__PURE__ */ n.jsx(S, { label: u, required: d, showLabel: !0, id: s.$id, children: /* @__PURE__ */ n.jsx(
101
+ A,
102
+ {
103
+ label: u,
104
+ canAdd: e,
105
+ onAddClick: o,
106
+ disabled: a,
107
+ readonly: l,
108
+ uiSchema: r,
109
+ registry: c
110
+ }
111
+ ) }) });
112
+ }, {
113
+ templates: { BaseInputTemplate: _e }
114
+ } = W(), xe = ({ placeholder: e, ...t }) => {
115
+ const { schema: a } = t;
116
+ return /* @__PURE__ */ n.jsx(
117
+ _e,
118
+ {
119
+ placeholder: a.placeholder || e || F.INPUT,
120
+ ...t,
121
+ className: "form__input cn-9 fs-13 lh-20 fw-4"
122
+ }
123
+ );
124
+ }, U = ({
125
+ label: e,
126
+ icon: t,
127
+ iconType: a,
128
+ registry: s,
129
+ uiSchema: r,
130
+ ...i
131
+ }) => {
132
+ const o = `Add ${e}`;
133
+ return /* @__PURE__ */ n.jsx("div", { className: "flexbox flex-justify-start", children: /* @__PURE__ */ n.jsxs(
134
+ "button",
135
+ {
136
+ ...i,
137
+ type: "button",
138
+ className: "dc__outline-none-imp p-0 dc__transparent flex dc__gap-4 cursor dc__mxw-250",
139
+ title: "Add",
140
+ children: [
141
+ /* @__PURE__ */ n.jsx(de, { className: "icon-dim-16 fcb-5" }),
142
+ /* @__PURE__ */ n.jsx(O, { placement: "right", content: o, children: /* @__PURE__ */ n.jsx("span", { className: "cb-5 fs-13 lh-34 dc__truncate", children: o }) })
143
+ ]
144
+ }
145
+ ) });
146
+ }, je = ({ icon: e, iconType: t, registry: a, uiSchema: s, ...r }) => /* @__PURE__ */ n.jsx("button", { ...r, type: "button", className: "dc__outline-none-imp p-0 dc__transparent flex cursor", title: "Remove", children: /* @__PURE__ */ n.jsx(me, { className: "icon-dim-16 fcn-6" }) }), be = ({ uiSchema: e }) => {
147
+ const { submitText: t, norender: a, props: s = {} } = J(e);
148
+ return a ? null : /* @__PURE__ */ n.jsx("div", { className: "flexbox flex-justify-end", children: /* @__PURE__ */ n.jsx("button", { type: "submit", ...s, className: `cta ${s.className || ""}`, children: t }) });
149
+ }, P = ({
150
+ id: e,
151
+ title: t,
152
+ required: a,
153
+ description: s
154
+ }) => /* @__PURE__ */ n.jsxs("legend", { className: "fs-13 fw-6 cn-9 lh-20 dc__no-border pb-9 mb-0", id: e, children: [
155
+ /* @__PURE__ */ n.jsx(O, { alwaysShowTippyOnHover: !!s, content: s, children: /* @__PURE__ */ n.jsx("span", { className: `${s ? "dc__underline-dotted" : ""}`, children: t }) }),
156
+ a && /* @__PURE__ */ n.jsx("span", { className: "cr-5", children: " *" })
157
+ ] }), ge = (e) => {
158
+ const {
159
+ id: t,
160
+ label: a,
161
+ children: s,
162
+ errors: r,
163
+ hidden: i,
164
+ required: o,
165
+ displayLabel: l,
166
+ registry: c,
167
+ uiSchema: d,
168
+ classNames: p,
169
+ schema: m,
170
+ rawDescription: u
171
+ } = e, f = $(d), h = K(
172
+ "WrapIfAdditionalTemplate",
173
+ c,
174
+ f
175
+ ), x = B in m, _ = (l || m.type === "boolean") && !x, j = m.type === "array";
176
+ return i ? /* @__PURE__ */ n.jsx("div", { className: "hidden", children: s }) : (
177
+ // NOTE: need to override the margins of default rjsf css
178
+ /* @__PURE__ */ n.jsxs("div", { className: `${p} mb-0`, children: [
179
+ j && /* @__PURE__ */ n.jsx(
180
+ P,
181
+ {
182
+ id: t,
183
+ title: a,
184
+ required: o,
185
+ registry: c,
186
+ uiSchema: d,
187
+ schema: m,
188
+ description: u
189
+ }
190
+ ),
191
+ /* @__PURE__ */ n.jsx(
192
+ S,
193
+ {
194
+ label: a,
195
+ showLabel: _,
196
+ id: t,
197
+ required: o,
198
+ rawDescription: u,
199
+ children: /* @__PURE__ */ n.jsx(h, { ...e, children: s })
200
+ }
201
+ ),
202
+ r
203
+ ] })
204
+ );
205
+ }, ye = ({ errors: e = [], fieldPathId: t }) => {
206
+ const a = V(t);
207
+ return e.length > 0 && /* @__PURE__ */ n.jsx("span", { className: "display-grid rjsf-form-template__field--error dc__gap-12", id: a, children: e.filter((s) => !!s).map((s, r) => /* @__PURE__ */ n.jsxs(te.Fragment, { children: [
208
+ /* @__PURE__ */ n.jsx("span", {}),
209
+ /* @__PURE__ */ n.jsxs("span", { className: "form__error", children: [
210
+ /* @__PURE__ */ n.jsx(ue, { className: "form__icon form__icon--error" }),
211
+ s
212
+ ] })
213
+ ] }, r)) });
214
+ }, ve = (e, t) => {
215
+ switch (e) {
216
+ case Y.NewStringDefault:
217
+ return "";
218
+ default:
219
+ return q(e, t);
220
+ }
221
+ }, We = (e) => {
222
+ try {
223
+ const t = new URL(e).origin === window.location.origin;
224
+ return {
225
+ href: e,
226
+ target: t ? "_self" : "_blank",
227
+ rel: t ? void 0 : "external noreferrer",
228
+ url: e
229
+ };
230
+ } catch {
231
+ return {
232
+ href: e,
233
+ target: "_blank",
234
+ url: `${e} (Invalid URL)`
235
+ };
236
+ }
237
+ }, Je = (e) => {
238
+ const t = typeof e;
239
+ switch (t) {
240
+ case "boolean":
241
+ case "string":
242
+ case "number":
243
+ return t;
244
+ case "object":
245
+ return Array.isArray(e) ? "array" : e === null ? "null" : t;
246
+ default:
247
+ return "null";
248
+ }
249
+ }, y = (e) => {
250
+ if (!e)
251
+ return "";
252
+ const t = e.trim(), s = (/^\/.+$/g.test(t) ? t : `/${t}`).replaceAll(/\./g, "/");
253
+ return /(\/(([^/~])|(~[01]))*)/g.test(s) ? s : "";
254
+ }, I = {
255
+ value: !1,
256
+ path: ""
257
+ }, Te = (e) => {
258
+ if (!e)
259
+ return null;
260
+ const t = structuredClone(e);
261
+ return typeof t == "string" ? {
262
+ value: !0,
263
+ path: y(t)
264
+ } : typeof t != "object" ? structuredClone(I) : Object.hasOwn(t, "condition") && "condition" in t && Object.hasOwn(t, "value") && "value" in t ? {
265
+ value: t.condition,
266
+ path: y(t.value)
267
+ } : Object.hasOwn(t, "value") && "value" in t && Object.hasOwn(t, "path") && "path" in t ? {
268
+ value: t.value,
269
+ path: y(t.path)
270
+ } : structuredClone(I);
271
+ }, k = (e, t, a) => {
272
+ e && (e.type === "object" && e.properties && typeof e.properties == "object" && Object.entries(e.properties).forEach(([s, r]) => {
273
+ k(r, `${t}/${s}`, a);
274
+ }), (e.type === "boolean" || e.type === "string" || e.type === "number" || e.type === "integer") && (a[t] = y(e.updatePath ?? t)));
275
+ }, Se = (e) => {
276
+ const t = {};
277
+ return k(e, "", t), t;
278
+ }, H = (e, t, a) => {
279
+ if (t >= a.length)
280
+ return e;
281
+ const s = a[t];
282
+ if (t === a.length - 1) {
283
+ const r = structuredClone(e);
284
+ return delete r[s], r;
285
+ }
286
+ if (e[s] && (e[s] = H(e[s], t + 1, a)), Object.keys(e[s] ?? {}).length === 0) {
287
+ const r = structuredClone(e);
288
+ return delete r[s], r;
289
+ }
290
+ return e;
291
+ }, we = (e, t) => {
292
+ if (!e || typeof e != "object" || Array.isArray(e))
293
+ throw new Error("Invalid object");
294
+ if (!t || !t.startsWith("/"))
295
+ throw new Error("Invalid path");
296
+ const a = t.split("/").slice(1);
297
+ return H(e, 0, a);
298
+ }, D = ({
299
+ formState: e,
300
+ formData: t,
301
+ schemaPathToUpdatePathMap: a
302
+ }) => {
303
+ let s = structuredClone(e);
304
+ return s && (Object.entries(a).forEach(([r, i]) => {
305
+ if (r === i || !i)
306
+ return;
307
+ const o = v({
308
+ json: t,
309
+ path: T(r),
310
+ resultType: "value",
311
+ wrap: !1
312
+ });
313
+ o === void 0 ? s = we(s, r) : s = w([N(r, o), s]);
314
+ const l = v({
315
+ json: e,
316
+ path: T(r),
317
+ resultType: "value",
318
+ wrap: !1
319
+ });
320
+ l !== void 0 && (s = w([N(i, l), s]));
321
+ }), t && s ? G(t, z(t, s), !1, !1).newDocument : s);
322
+ }, Ne = ({ formData: e, schemaPathToUpdatePathMap: t }) => w([
323
+ ...Object.entries(t).map(([a, s]) => {
324
+ if (a === s || !s)
325
+ return {};
326
+ const r = v({
327
+ json: e,
328
+ path: T(s),
329
+ resultType: "value",
330
+ wrap: !1
331
+ });
332
+ return r === void 0 ? {} : N(a, r);
333
+ }),
334
+ structuredClone(e)
335
+ ]), Oe = ({
336
+ disabled: e,
337
+ formData: t,
338
+ fieldPathId: a,
339
+ onAddProperty: s,
340
+ properties: r,
341
+ readonly: i,
342
+ registry: o,
343
+ required: l,
344
+ schema: c,
345
+ title: d,
346
+ uiSchema: p
347
+ }) => {
348
+ const m = !!c.additionalProperties, u = X(c, p, t) && /* @__PURE__ */ n.jsx(
349
+ U,
350
+ {
351
+ label: d,
352
+ className: "object-property-expand",
353
+ onClick: s,
354
+ disabled: e || i,
355
+ uiSchema: p,
356
+ registry: o
357
+ }
358
+ ), f = r.filter((h) => {
359
+ const x = c.properties?.[h.name]?.hidden;
360
+ if (!x)
361
+ return !0;
362
+ try {
363
+ const _ = Te(x);
364
+ if (!_.path)
365
+ throw new Error("Empty path property of hidden descriptor field");
366
+ const j = v({
367
+ path: T(_.path),
368
+ json: o.formContext,
369
+ resultType: "value",
370
+ wrap: !1
371
+ });
372
+ return !(j === void 0 || Z(_.value, j));
373
+ } catch {
374
+ return !0;
375
+ }
376
+ }).map((h) => h.content);
377
+ return m ? r.length ? /* @__PURE__ */ n.jsxs(n.Fragment, { children: [
378
+ /* @__PURE__ */ n.jsx(
379
+ S,
380
+ {
381
+ label: d,
382
+ required: l,
383
+ showLabel: !0,
384
+ id: a.$id,
385
+ shouldAlignCenter: !1,
386
+ children: /* @__PURE__ */ n.jsx("div", { children: f })
387
+ }
388
+ ),
389
+ u
390
+ ] }) : /* @__PURE__ */ n.jsx(S, { label: d, required: l, showLabel: !0, id: a.$id, children: u }) : /* @__PURE__ */ n.jsxs(n.Fragment, { children: [
391
+ f,
392
+ u
393
+ ] });
394
+ }, Fe = (e) => {
395
+ const { fieldPathId: t, registry: a, required: s, schema: r, title: i, uiSchema: o, description: l } = e, c = !!r.additionalProperties, d = i && !c;
396
+ return /* @__PURE__ */ n.jsxs("fieldset", { id: t.$id, children: [
397
+ d && /* @__PURE__ */ n.jsx(
398
+ P,
399
+ {
400
+ id: Q(t),
401
+ title: i,
402
+ required: s,
403
+ schema: r,
404
+ uiSchema: o,
405
+ registry: a,
406
+ description: l
407
+ }
408
+ ),
409
+ /* @__PURE__ */ n.jsx(
410
+ "div",
411
+ {
412
+ className: `${r.properties && !c && t.$id !== "root" ? "dc__border-left pl-12" : ""} ${t.$id === "root" ? "dc__separated-flexbox dc__separated-flexbox--vertical" : "flexbox-col dc__gap-8"}`,
413
+ children: /* @__PURE__ */ n.jsx(Oe, { ...e })
414
+ }
415
+ )
416
+ ] });
417
+ }, Pe = ({
418
+ id: e,
419
+ disabled: t,
420
+ label: a,
421
+ onKeyRename: s,
422
+ onRemoveProperty: r,
423
+ readonly: i,
424
+ schema: o,
425
+ children: l,
426
+ uiSchema: c,
427
+ registry: d
428
+ }) => {
429
+ const { templates: p } = d, { RemoveButton: m } = p.ButtonTemplates, u = B in o;
430
+ return /* @__PURE__ */ n.jsx(n.Fragment, { children: u ? /* @__PURE__ */ n.jsxs("div", { className: "dc__position-rel rjsf-form-template__additional-fields display-grid dc__gap-8 flex-align-center", children: [
431
+ /* @__PURE__ */ n.jsx("div", { children: /* @__PURE__ */ n.jsx(
432
+ "input",
433
+ {
434
+ type: "text",
435
+ className: "form__input cn-9 fs-13 lh-20 fw-4",
436
+ id: `${e}-key`,
437
+ onBlur: (f) => s(f.target.value),
438
+ placeholder: F.OBJECT_KEY,
439
+ defaultValue: a
440
+ }
441
+ ) }),
442
+ /* @__PURE__ */ n.jsx("div", { children: l }),
443
+ /* @__PURE__ */ n.jsx("div", { className: "dc__position-abs remove-btn__container", style: { right: "-28px", top: "9px" }, children: /* @__PURE__ */ n.jsx(
444
+ m,
445
+ {
446
+ disabled: t || i,
447
+ onClick: r,
448
+ uiSchema: c,
449
+ registry: d
450
+ }
451
+ ) })
452
+ ] }) : l });
453
+ }, Ce = ({
454
+ id: e,
455
+ onChange: t,
456
+ value: a,
457
+ disabled: s,
458
+ readonly: r,
459
+ autofocus: i
460
+ }) => {
461
+ const o = oe(a) ? !1 : a, l = () => {
462
+ t(!o);
463
+ };
464
+ return /* @__PURE__ */ n.jsxs("div", { className: "flexbox dc__align-items-center dc__gap-8", children: [
465
+ /* @__PURE__ */ n.jsx(
466
+ re,
467
+ {
468
+ name: e,
469
+ ariaLabel: e,
470
+ onChange: l,
471
+ isChecked: o,
472
+ autoFocus: i,
473
+ isDisabled: s || r
474
+ }
475
+ ),
476
+ /* @__PURE__ */ n.jsx("span", { className: "dc__capitalize", children: o.toString() })
477
+ ] });
478
+ }, Ee = (e) => {
479
+ const {
480
+ id: t,
481
+ multiple: a = !1,
482
+ options: s,
483
+ value: r,
484
+ disabled: i,
485
+ readonly: o,
486
+ autofocus: l = !1,
487
+ onChange: c,
488
+ onBlur: d,
489
+ onFocus: p,
490
+ placeholder: m,
491
+ schema: u
492
+ } = e, { enumOptions: f = [] } = s, h = a ? [] : null, x = (b) => {
493
+ c(a ? b.map((g) => g.value) : b.value);
494
+ }, [_, j] = ne();
495
+ se(() => {
496
+ j(le(8));
497
+ }, []);
498
+ const C = (b) => a ? f.filter((g) => b.some((M) => R(M, g.value))) : f.find((g) => R(b, g.value));
499
+ return /* @__PURE__ */ n.jsx(
500
+ ie,
501
+ {
502
+ inputId: `devtron-rjsf-select__${t}`,
503
+ name: t,
504
+ isMulti: a,
505
+ value: typeof r > "u" ? h : C(r),
506
+ autoFocus: l,
507
+ onChange: x,
508
+ options: f,
509
+ onBlur: () => d(t, r),
510
+ onFocus: () => p(t, r),
511
+ placeholder: u.placeholder || m || F.SELECT,
512
+ isDisabled: i || o,
513
+ menuPortalTarget: document.getElementById(L),
514
+ menuPosition: "fixed"
515
+ },
516
+ _
517
+ );
518
+ }, Re = {
519
+ CheckboxWidget: Ce,
520
+ SelectWidget: Ee
521
+ }, Ae = {
522
+ ArrayFieldItemTemplate: fe,
523
+ ArrayFieldTemplate: he,
524
+ BaseInputTemplate: xe,
525
+ ButtonTemplates: { AddButton: U, RemoveButton: je, SubmitButton: be },
526
+ FieldTemplate: ge,
527
+ FieldErrorTemplate: ye,
528
+ ObjectFieldTemplate: Fe,
529
+ TitleFieldTemplate: P,
530
+ WrapIfAdditionalTemplate: Pe
531
+ }, Ie = ee, De = ce, Ke = ae((e, t) => {
532
+ const { schemaPathToUpdatePathMap: a, isUpdatePathKeywordPresent: s } = E(() => {
533
+ const l = Se(e.schema);
534
+ return {
535
+ schemaPathToUpdatePathMap: l,
536
+ isUpdatePathKeywordPresent: Object.entries(l).some(([c, d]) => c !== d)
537
+ };
538
+ }, [e.schema]), r = E(() => s ? Ne({ formData: e.formData ?? {}, schemaPathToUpdatePathMap: a }) : e.formData, [e.formData, a, s]), i = (l) => {
539
+ if (!e.onChange)
540
+ return;
541
+ const c = D({
542
+ formState: l.formData,
543
+ formData: e.formData,
544
+ schemaPathToUpdatePathMap: a
545
+ });
546
+ e.onChange({ ...l, formData: c });
547
+ }, o = (l, c) => {
548
+ if (!e.onSubmit)
549
+ return;
550
+ const d = D({
551
+ formState: l.formData,
552
+ formData: e.formData,
553
+ schemaPathToUpdatePathMap: a
554
+ });
555
+ e.onSubmit?.({ ...l, formData: d }, c);
556
+ };
557
+ return /* @__PURE__ */ n.jsxs(n.Fragment, { children: [
558
+ /* @__PURE__ */ n.jsx(
559
+ Ie,
560
+ {
561
+ noHtml5Validate: !0,
562
+ showErrorList: !1,
563
+ autoComplete: "off",
564
+ ...e,
565
+ formData: r,
566
+ ...s ? {
567
+ onChange: i,
568
+ onSubmit: o
569
+ } : {},
570
+ className: `rjsf-form-template__container ${e.className || ""}`,
571
+ validator: De,
572
+ templates: {
573
+ ...Ae,
574
+ ...e.templates
575
+ },
576
+ formContext: r,
577
+ widgets: { ...Re, ...e.widgets },
578
+ translateString: ve,
579
+ ref: t
580
+ }
581
+ ),
582
+ /* @__PURE__ */ n.jsx("div", { id: L })
583
+ ] });
584
+ });
585
+ export {
586
+ Me as H,
587
+ Ke as R,
588
+ We as a,
589
+ Se as b,
590
+ y as c,
591
+ Je as g
592
+ };