@webwriter/quiz 1.1.2 → 1.1.5

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 (112) hide show
  1. package/.github/workflows/publish.yml +8 -0
  2. package/LICENSE +6 -6
  3. package/custom.d.ts +175 -175
  4. package/dist/widgets/webwriter-choice-item.js +69 -205
  5. package/dist/widgets/webwriter-choice.js +99 -214
  6. package/dist/widgets/webwriter-cloze-gap.js +74 -213
  7. package/dist/widgets/webwriter-cloze.js +71 -204
  8. package/dist/widgets/webwriter-mark.js +72 -205
  9. package/dist/widgets/webwriter-order-item.js +68 -201
  10. package/dist/widgets/webwriter-order.js +99 -209
  11. package/dist/widgets/webwriter-pairing-item.js +57 -160
  12. package/dist/widgets/webwriter-pairing.js +69 -196
  13. package/dist/widgets/webwriter-quiz.js +72 -211
  14. package/dist/widgets/webwriter-speech.js +71 -204
  15. package/dist/widgets/webwriter-task-explainer.js +57 -160
  16. package/dist/widgets/webwriter-task-hint.js +55 -158
  17. package/dist/widgets/webwriter-task-prompt.js +61 -170
  18. package/dist/widgets/webwriter-task.js +80 -205
  19. package/dist/widgets/webwriter-text.js +94 -205
  20. package/lit-localize.json +14 -14
  21. package/localization/bg.xlf +72 -69
  22. package/localization/cs.xlf +72 -69
  23. package/localization/da.xlf +72 -69
  24. package/localization/de.xlf +77 -74
  25. package/localization/el.xlf +72 -69
  26. package/localization/es.xlf +72 -69
  27. package/localization/et.xlf +72 -69
  28. package/localization/fi.xlf +72 -69
  29. package/localization/fr.xlf +72 -69
  30. package/localization/generated/bg.ts +30 -29
  31. package/localization/generated/cs.ts +30 -29
  32. package/localization/generated/da.ts +30 -29
  33. package/localization/generated/de.ts +30 -29
  34. package/localization/generated/el.ts +30 -29
  35. package/localization/generated/es.ts +30 -29
  36. package/localization/generated/et.ts +30 -29
  37. package/localization/generated/fi.ts +30 -29
  38. package/localization/generated/fr.ts +30 -29
  39. package/localization/generated/hu.ts +30 -29
  40. package/localization/generated/id.ts +30 -29
  41. package/localization/generated/index.js +2 -2
  42. package/localization/generated/it.ts +30 -29
  43. package/localization/generated/ja.ts +30 -29
  44. package/localization/generated/ko.ts +30 -29
  45. package/localization/generated/locale-codes.js +79 -79
  46. package/localization/generated/lt.ts +30 -29
  47. package/localization/generated/lv.ts +30 -29
  48. package/localization/generated/nb.ts +30 -29
  49. package/localization/generated/nl.ts +30 -29
  50. package/localization/generated/pl.ts +30 -29
  51. package/localization/generated/pt-BR.ts +30 -29
  52. package/localization/generated/pt-PT.ts +30 -29
  53. package/localization/generated/ro.ts +30 -29
  54. package/localization/generated/ru.ts +30 -29
  55. package/localization/generated/sk.ts +30 -29
  56. package/localization/generated/sl.ts +30 -29
  57. package/localization/generated/sv.ts +30 -29
  58. package/localization/generated/tr.ts +30 -29
  59. package/localization/generated/uk.ts +30 -29
  60. package/localization/generated/zh-hans.ts +30 -29
  61. package/localization/hu.xlf +72 -69
  62. package/localization/id.xlf +72 -69
  63. package/localization/it.xlf +72 -69
  64. package/localization/ja.xlf +72 -69
  65. package/localization/ko.xlf +72 -69
  66. package/localization/lt.xlf +72 -69
  67. package/localization/lv.xlf +72 -69
  68. package/localization/nb.xlf +72 -69
  69. package/localization/nl.xlf +72 -69
  70. package/localization/pl.xlf +72 -69
  71. package/localization/pt-BR.xlf +72 -69
  72. package/localization/pt-PT.xlf +72 -69
  73. package/localization/ro.xlf +72 -69
  74. package/localization/ru.xlf +72 -69
  75. package/localization/sk.xlf +72 -69
  76. package/localization/sl.xlf +72 -69
  77. package/localization/sv.xlf +72 -69
  78. package/localization/tr.xlf +72 -69
  79. package/localization/uk.xlf +72 -69
  80. package/localization/zh-hans.xlf +72 -69
  81. package/package.json +4 -3
  82. package/src/lib/combobox.ts +455 -455
  83. package/src/lib/highlighter-fill.svg +5 -5
  84. package/src/snippets/Beispiel-Choice.html +57 -57
  85. package/src/snippets/Beispiel-Mark.html +13 -13
  86. package/src/snippets/Beispiel-Order.html +52 -52
  87. package/src/snippets/Beispiel-Text.html +20 -20
  88. package/src/snippets/choice.html +7 -7
  89. package/src/snippets/cloze.html +3 -3
  90. package/src/snippets/mark.html +3 -3
  91. package/src/snippets/order.html +7 -7
  92. package/src/snippets/pairing.html +9 -9
  93. package/src/snippets/speech.html +3 -3
  94. package/src/snippets/text.html +3 -3
  95. package/src/snippets/wordsearch.html +3 -3
  96. package/src/widgets/webwriter-choice-item.ts +256 -253
  97. package/src/widgets/webwriter-choice.ts +352 -336
  98. package/src/widgets/webwriter-cloze-gap.ts +215 -215
  99. package/src/widgets/webwriter-cloze.ts +135 -135
  100. package/src/widgets/webwriter-mark.ts +431 -431
  101. package/src/widgets/webwriter-order-item.ts +440 -440
  102. package/src/widgets/webwriter-order.ts +326 -309
  103. package/src/widgets/webwriter-pairing-item.ts +160 -160
  104. package/src/widgets/webwriter-pairing.ts +192 -192
  105. package/src/widgets/webwriter-quiz.ts +281 -281
  106. package/src/widgets/webwriter-speech.ts +272 -272
  107. package/src/widgets/webwriter-task-explainer.ts +42 -42
  108. package/src/widgets/webwriter-task-hint.ts +22 -22
  109. package/src/widgets/webwriter-task-prompt.ts +23 -23
  110. package/src/widgets/webwriter-task.ts +554 -546
  111. package/src/widgets/webwriter-text.ts +176 -155
  112. package/tsconfig.json +6 -6
@@ -1,254 +1,257 @@
1
- import {css, html, PropertyValues} from "lit"
2
- import {styleMap} from "lit/directives/style-map.js"
3
- import {classMap} from "lit/directives/class-map.js"
4
- import {unsafeStatic} from "lit/static-html.js"
5
- import {LitElementWw} from "@webwriter/lit"
6
- import {customElement, property, query} from "lit/decorators.js"
7
-
8
- import SlRadio from "@shoelace-style/shoelace/dist/components/radio/radio.component.js"
9
- import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"
10
- import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
11
- import "@shoelace-style/shoelace/dist/themes/light.css"
12
- import { keyed } from "lit/directives/keyed.js"
13
- import IconX from "bootstrap-icons/icons/x.svg"
14
- import IconCheck from "bootstrap-icons/icons/check.svg"
15
-
16
- import LOCALIZE from "../../localization/generated"
17
- import {msg} from "@lit/localize"
18
-
19
- declare global {interface HTMLElementTagNameMap {
20
- "webwriter-choice-item": WebwriterChoiceItem;
21
- }}
22
-
23
- @customElement("webwriter-choice-item")
24
- export class WebwriterChoiceItem extends LitElementWw {
25
-
26
- localize = LOCALIZE
27
-
28
- @property({type: Boolean, attribute: false})
29
- accessor showSolution = true
30
-
31
- @property({type: Boolean, attribute: false})
32
- accessor active = false
33
-
34
- @property({type: Boolean, attribute: false})
35
- accessor valid: true | false | undefined
36
-
37
- // inactive + invalid/no validity -> nothing
38
- // active + no validity -> blue circle
39
- // inactive/active + valid -> green upper checkmark
40
- // active + invalid -> red upper cross
41
-
42
-
43
- @property({type: String, attribute: true, reflect: true})
44
- accessor layout: "list" | "tiles" = "list"
45
-
46
- static scopedElements = {
47
- "sl-radio": SlRadio,
48
- "sl-checkbox": SlCheckbox,
49
- "sl-icon": SlIcon
50
- }
51
-
52
- static styles = css`
53
-
54
- :host {
55
- width: 100%;
56
- position: relative;
57
- }
58
-
59
- :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
60
- display: none;
61
- }
62
-
63
- :host(:is([contenteditable=true], [contenteditable=""])) .user-only {
64
- display: none;
65
- }
66
-
67
- :host(:is([contenteditable=true], [contenteditable=""])) sl-checkbox.valid {
68
- --webwriter-control-color-600: var(--sl-color-success-600);
69
- --webwriter-control-color-400: var(--sl-color-success-400);
70
- }
71
-
72
- sl-checkbox {
73
- display: block;
74
- width: 100%;
75
- &::part(base) {
76
- width: 100%;
77
- display: flex;
78
- flex-direction: row;
79
- align-items: center;
80
- cursor: unset;
81
- }
82
-
83
- &::part(control) {
84
- cursor: pointer;
85
- border-radius: var(--webwriter-choice-radius, 2px);
86
- border-width: 2px;
87
- }
88
-
89
- &::part(control):not(:hover){
90
- border-color: var(--sl-color-gray-500);
91
- }
92
-
93
- &::part(control):hover {
94
- border-color: var(--sl-color-gray-700);
95
- }
96
-
97
- &::part(control--checked):not(:hover) {
98
- background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
99
- border-color: var(--sl-color-gray-500);
100
- }
101
- &::part(control--checked):hover {
102
- background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
103
- border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
104
- }
105
-
106
- &::part(label) {
107
- width: 100%;
108
- }
109
- }
110
-
111
- .solution {
112
- position: absolute;
113
- top: -6px;
114
- left: -6px;
115
- border: 2px solid var(--sl-color-gray-500);
116
- border-radius: var(--webwriter-choice-radius, 2px);
117
- width: 12px;
118
- height: 12px;
119
- z-index: 1;
120
- color: white;
121
-
122
- &[data-valid] {
123
- background: var(--sl-color-success-600);
124
- }
125
-
126
- &:not([data-valid]) {
127
- background: var(--sl-color-danger-600);
128
- }
129
- }
130
-
131
- :host([layout=tiles]) {
132
- position: relative;
133
- overflow: visible !important;
134
-
135
- & ::slotted(:is(picture, audio, video, img, iframe)) {
136
- height: 100%;
137
- width: 100%;
138
- }
139
-
140
- & ::slotted(:not(:is(picture, audio, video, img, iframe))) {
141
- margin: 5px !important;
142
- }
143
-
144
- sl-checkbox {
145
- display: block;
146
- &::part(base) {
147
- display: flex;
148
- flex-direction: row;
149
- align-items: center;
150
- cursor: unset;
151
- position: static;
152
- }
153
-
154
- &::part(control) {
155
- position: absolute;
156
- bottom: -10px;
157
- left: -10px;
158
- cursor: pointer;
159
- border-radius: var(--webwriter-choice-radius, 2px);
160
- z-index: 100;
161
- border-color: var(--sl-color-gray-500);
162
- }
163
-
164
- &::part(control--checked):not(:hover) {
165
- background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
166
- border-color: var(--sl-color-gray-500);
167
- }
168
- &::part(control--checked):hover {
169
- background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
170
- border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
171
- }
172
-
173
- &::part(label) {
174
- aspect-ratio: 1;
175
- min-width: 125px;
176
- max-width: 350px;
177
- min-height: 125px;
178
- max-height: 350px;
179
- overflow: hidden;
180
- resize: both;
181
- margin-inline-start: 0;
182
- overflow-y: auto;
183
- scrollbar-width: thin;
184
- }
185
- }
186
- }
187
- `
188
-
189
- handleClick = (e: PointerEvent) => {
190
- const checkboxClicked = e.composedPath().some(v => (v as HTMLElement)?.classList?.contains("checkbox__control"))
191
- const editable = this.isContentEditable
192
- if(editable && !checkboxClicked) {
193
- e.preventDefault()
194
- }
195
- else {
196
- e.stopImmediatePropagation()
197
- }
198
- }
199
-
200
- handleChange = (e: CustomEvent) => {
201
- if(this.isContentEditable) {
202
- this.valid = !this.valid
203
- }
204
- else {
205
- this.active = !this.active
206
- }
207
- }
208
-
209
- @query("sl-checkbox")
210
- accessor checkbox: SlCheckbox
211
-
212
- observer: MutationObserver
213
-
214
- protected async updated(_changedProperties: PropertyValues) {
215
- await this.checkbox.updateComplete
216
- const labelEl = this.checkbox.shadowRoot.querySelector(".checkbox__label") as HTMLElement
217
-
218
- if(_changedProperties.has("layout") && this.layout === "list") {
219
- this.syncSize(true)
220
- this.observer?.disconnect()
221
- }
222
- else if(_changedProperties.has("layout") && this.layout === "tiles") {
223
- this.syncSize()
224
- this.observer = new MutationObserver(() => this.syncSize())
225
- this.observer.observe(labelEl, {attributeFilter: ["style"], attributes: true})
226
- }
227
- }
228
-
229
- syncSize(clear=false) {
230
- const labelEl = this.checkbox?.shadowRoot.querySelector(".checkbox__label") as HTMLElement
231
- if(labelEl && !clear) {
232
- this.style.width = labelEl.style.width
233
- this.style.height = labelEl.style.height
234
- }
235
- else if(labelEl && clear) {
236
- this.style.width = labelEl.style.width = null
237
- this.style.height = labelEl.style.height = null
238
- }
239
- }
240
-
241
- disconnectedCallback(): void {
242
- super.disconnectedCallback()
243
- this.observer?.disconnect()
244
- }
245
-
246
- render() {
247
- return keyed(this.layout, html`
248
- ${this.showSolution && this.valid !== undefined && (this.active || !this.active && this.valid)? html`<sl-icon class="solution user-only" ?data-valid=${this.valid} src=${this.valid? IconCheck: IconX}></sl-icon>`: null}
249
- <sl-checkbox class=${classMap({valid: this.valid, active: this.active})} exportparts="base, control, label" @click=${this.handleClick} @sl-change=${this.handleChange} ?checked=${this.isContentEditable? this.valid: this.active}>
250
- <slot part="slot" style=${styleMap({"--ww-placeholder": `"${msg("Option")}"`})}></slot>
251
- </sl-checkbox>
252
- `)
253
- }
1
+ import {css, html, PropertyValues} from "lit"
2
+ import {styleMap} from "lit/directives/style-map.js"
3
+ import {classMap} from "lit/directives/class-map.js"
4
+ import {unsafeStatic} from "lit/static-html.js"
5
+ import {LitElementWw} from "@webwriter/lit"
6
+ import {customElement, property, query} from "lit/decorators.js"
7
+
8
+ import SlRadio from "@shoelace-style/shoelace/dist/components/radio/radio.component.js"
9
+ import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"
10
+ import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
11
+ import "@shoelace-style/shoelace/dist/themes/light.css"
12
+ import { keyed } from "lit/directives/keyed.js"
13
+ import IconX from "bootstrap-icons/icons/x.svg"
14
+ import IconCheck from "bootstrap-icons/icons/check.svg"
15
+
16
+ import LOCALIZE from "../../localization/generated"
17
+ import {msg} from "@lit/localize"
18
+
19
+ declare global {interface HTMLElementTagNameMap {
20
+ "webwriter-choice-item": WebwriterChoiceItem;
21
+ }}
22
+
23
+ @customElement("webwriter-choice-item")
24
+ export class WebwriterChoiceItem extends LitElementWw {
25
+
26
+ localize = LOCALIZE
27
+
28
+ @property({type: Boolean, attribute: false})
29
+ accessor showSolution = true
30
+
31
+ @property({type: Boolean, attribute: false})
32
+ accessor active = false
33
+
34
+ @property({type: Boolean, attribute: false})
35
+ accessor valid: true | false | undefined
36
+
37
+ // inactive + invalid/no validity -> nothing
38
+ // active + no validity -> blue circle
39
+ // inactive/active + valid -> green upper checkmark
40
+ // active + invalid -> red upper cross
41
+
42
+
43
+ @property({type: String, attribute: true, reflect: true})
44
+ accessor layout: "list" | "tiles" = "list"
45
+
46
+ static scopedElements = {
47
+ "sl-radio": SlRadio,
48
+ "sl-checkbox": SlCheckbox,
49
+ "sl-icon": SlIcon
50
+ }
51
+
52
+ static styles = css`
53
+
54
+ :host {
55
+ width: 100%;
56
+ position: relative;
57
+ }
58
+
59
+ :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
60
+ display: none;
61
+ }
62
+
63
+ :host(:is([contenteditable=true], [contenteditable=""])) .user-only {
64
+ display: none;
65
+ }
66
+
67
+ :host(:is([contenteditable=true], [contenteditable=""])) sl-checkbox.valid {
68
+ --webwriter-control-color-600: var(--sl-color-success-600);
69
+ --webwriter-control-color-400: var(--sl-color-success-400);
70
+ }
71
+
72
+ sl-checkbox {
73
+ display: block;
74
+ width: 100%;
75
+ &::part(base) {
76
+ width: 100%;
77
+ display: flex;
78
+ flex-direction: row;
79
+ align-items: center;
80
+ cursor: unset;
81
+ }
82
+
83
+ &::part(control) {
84
+ cursor: pointer;
85
+ border-radius: var(--webwriter-choice-radius, 2px);
86
+ border-width: 2px;
87
+ }
88
+
89
+ &::part(control):not(:hover){
90
+ border-color: var(--sl-color-gray-500);
91
+ }
92
+
93
+ &::part(control):hover {
94
+ border-color: var(--sl-color-gray-700);
95
+ }
96
+
97
+ &::part(control--checked):not(:hover) {
98
+ background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
99
+ border-color: var(--sl-color-gray-500);
100
+ }
101
+ &::part(control--checked):hover {
102
+ background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
103
+ border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
104
+ }
105
+
106
+ &::part(label) {
107
+ width: 100%;
108
+ }
109
+ }
110
+
111
+ .solution {
112
+ position: absolute;
113
+ top: -6px;
114
+ left: -6px;
115
+ border: 2px solid var(--sl-color-gray-500);
116
+ border-radius: var(--webwriter-choice-radius, 2px);
117
+ width: 12px;
118
+ height: 12px;
119
+ z-index: 1;
120
+ color: white;
121
+
122
+ &[data-valid] {
123
+ background: var(--sl-color-success-600);
124
+ }
125
+
126
+ &:not([data-valid]) {
127
+ background: var(--sl-color-danger-600);
128
+ }
129
+ }
130
+
131
+ :host([layout=tiles]) {
132
+ position: relative;
133
+ overflow: visible !important;
134
+
135
+ & ::slotted(:is(picture, audio, video, img, iframe)) {
136
+ height: 100%;
137
+ width: 100%;
138
+ }
139
+
140
+ & ::slotted(:not(:is(picture, audio, video, img, iframe))) {
141
+ margin: 5px !important;
142
+ }
143
+
144
+ sl-checkbox {
145
+ display: block;
146
+ &::part(base) {
147
+ display: flex;
148
+ flex-direction: row;
149
+ align-items: center;
150
+ cursor: unset;
151
+ position: static;
152
+ }
153
+
154
+ &::part(control) {
155
+ position: absolute;
156
+ bottom: -10px;
157
+ left: -10px;
158
+ cursor: pointer;
159
+ border-radius: var(--webwriter-choice-radius, 2px);
160
+ z-index: 100;
161
+ border-color: var(--sl-color-gray-500);
162
+ }
163
+
164
+ &::part(control--checked):not(:hover) {
165
+ background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
166
+ border-color: var(--sl-color-gray-500);
167
+ }
168
+ &::part(control--checked):hover {
169
+ background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
170
+ border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
171
+ }
172
+
173
+ &::part(label) {
174
+ aspect-ratio: 1;
175
+ min-width: 125px;
176
+ max-width: 350px;
177
+ min-height: 125px;
178
+ max-height: 350px;
179
+ overflow: hidden;
180
+ margin-inline-start: 0;
181
+ overflow-y: auto;
182
+ scrollbar-width: thin;
183
+ }
184
+
185
+ :host(:is([contenteditable=true], [contenteditable=""])) &::part(label) {
186
+ resize: both;
187
+ }
188
+ }
189
+ }
190
+ `
191
+
192
+ handleClick = (e: PointerEvent) => {
193
+ const checkboxClicked = e.composedPath().some(v => (v as HTMLElement)?.classList?.contains("checkbox__control"))
194
+ const editable = this.isContentEditable
195
+ if(editable && !checkboxClicked) {
196
+ e.preventDefault()
197
+ }
198
+ else {
199
+ e.stopImmediatePropagation()
200
+ }
201
+ }
202
+
203
+ handleChange = (e: CustomEvent) => {
204
+ if(this.isContentEditable) {
205
+ this.valid = !this.valid
206
+ }
207
+ else {
208
+ this.active = !this.active
209
+ }
210
+ }
211
+
212
+ @query("sl-checkbox")
213
+ accessor checkbox: SlCheckbox
214
+
215
+ observer: MutationObserver
216
+
217
+ protected async updated(_changedProperties: PropertyValues) {
218
+ await this.checkbox.updateComplete
219
+ const labelEl = this.checkbox.shadowRoot.querySelector(".checkbox__label") as HTMLElement
220
+
221
+ if(_changedProperties.has("layout") && this.layout === "list") {
222
+ this.syncSize(true)
223
+ this.observer?.disconnect()
224
+ }
225
+ else if(_changedProperties.has("layout") && this.layout === "tiles") {
226
+ this.syncSize()
227
+ this.observer = new MutationObserver(() => this.syncSize())
228
+ this.observer.observe(labelEl, {attributeFilter: ["style"], attributes: true})
229
+ }
230
+ }
231
+
232
+ syncSize(clear=false) {
233
+ const labelEl = this.checkbox?.shadowRoot.querySelector(".checkbox__label") as HTMLElement
234
+ if(labelEl && !clear) {
235
+ this.style.width = labelEl.style.width
236
+ this.style.height = labelEl.style.height
237
+ }
238
+ else if(labelEl && clear) {
239
+ this.style.width = labelEl.style.width = null
240
+ this.style.height = labelEl.style.height = null
241
+ }
242
+ }
243
+
244
+ disconnectedCallback(): void {
245
+ super.disconnectedCallback()
246
+ this.observer?.disconnect()
247
+ }
248
+
249
+ render() {
250
+ return keyed(this.layout, html`
251
+ ${this.showSolution && this.valid !== undefined && (this.active || !this.active && this.valid)? html`<sl-icon class="solution user-only" ?data-valid=${this.valid} src=${this.valid? IconCheck: IconX}></sl-icon>`: null}
252
+ <sl-checkbox class=${classMap({valid: this.valid, active: this.active})} exportparts="base, control, label" @click=${this.handleClick} @sl-change=${this.handleChange} ?checked=${this.isContentEditable? this.valid: this.active}>
253
+ <slot part="slot" style=${styleMap({"--ww-placeholder": `"${msg("Option")}"`})}></slot>
254
+ </sl-checkbox>
255
+ `)
256
+ }
254
257
  }