@everyonesoftware/common 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 (163) hide show
  1. package/.c8rc.json +12 -0
  2. package/.github/workflows/publish.yml +38 -0
  3. package/.mocharc.json +9 -0
  4. package/README.md +9 -0
  5. package/package.json +36 -0
  6. package/sources/assertMessageParameters.ts +22 -0
  7. package/sources/asyncIterator.ts +437 -0
  8. package/sources/asyncIteratorToJavascriptAsyncIteratorAdapter.ts +48 -0
  9. package/sources/asyncResult.ts +95 -0
  10. package/sources/basicDisposable.ts +57 -0
  11. package/sources/byteList.ts +202 -0
  12. package/sources/byteListStream.ts +121 -0
  13. package/sources/byteReadStream.ts +24 -0
  14. package/sources/byteWriteStream.ts +16 -0
  15. package/sources/bytes.ts +25 -0
  16. package/sources/characterList.ts +195 -0
  17. package/sources/characterListStream.ts +151 -0
  18. package/sources/characterReadStream.ts +81 -0
  19. package/sources/characterReadStreamIterator.ts +128 -0
  20. package/sources/characterWriteStream.ts +45 -0
  21. package/sources/commandLineParameter.ts +45 -0
  22. package/sources/commandLineParameters.ts +21 -0
  23. package/sources/comparable.ts +144 -0
  24. package/sources/comparer.ts +133 -0
  25. package/sources/comparison.ts +20 -0
  26. package/sources/concatenateIterable.ts +119 -0
  27. package/sources/concatenateIterator.ts +165 -0
  28. package/sources/condition.ts +329 -0
  29. package/sources/currentProcess.ts +158 -0
  30. package/sources/dateTime.ts +130 -0
  31. package/sources/depthFirstSearch.ts +230 -0
  32. package/sources/disposable.ts +31 -0
  33. package/sources/emptyError.ts +10 -0
  34. package/sources/english.ts +45 -0
  35. package/sources/equalFunctions.ts +123 -0
  36. package/sources/fetchHttpClient.ts +89 -0
  37. package/sources/fetchHttpResponse.ts +106 -0
  38. package/sources/flatMapIterable.ts +104 -0
  39. package/sources/flatMapIterator.ts +152 -0
  40. package/sources/generator.ts +251 -0
  41. package/sources/httpClient.ts +36 -0
  42. package/sources/httpHeader.ts +37 -0
  43. package/sources/httpHeaders.ts +216 -0
  44. package/sources/httpIncomingRequest.ts +30 -0
  45. package/sources/httpIncomingResponse.ts +19 -0
  46. package/sources/httpMethod.ts +164 -0
  47. package/sources/httpOutgoingRequest.ts +119 -0
  48. package/sources/httpOutgoingResponse.ts +113 -0
  49. package/sources/httpServer.ts +34 -0
  50. package/sources/inMemoryCharacterWriteStream.ts +78 -0
  51. package/sources/index.ts +101 -0
  52. package/sources/iterable.ts +345 -0
  53. package/sources/iterator.ts +481 -0
  54. package/sources/iteratorToJavascriptIteratorAdapter.ts +48 -0
  55. package/sources/javascript.ts +59 -0
  56. package/sources/javascriptArrayList.ts +175 -0
  57. package/sources/javascriptAsyncIteratorToAsyncIteratorAdapter.ts +124 -0
  58. package/sources/javascriptIteratorToIteratorAdapter.ts +133 -0
  59. package/sources/javascriptMapMap.ts +143 -0
  60. package/sources/javascriptSetSet.ts +134 -0
  61. package/sources/list.ts +330 -0
  62. package/sources/listQueue.ts +62 -0
  63. package/sources/listStack.ts +62 -0
  64. package/sources/luxonDateTime.ts +109 -0
  65. package/sources/map.ts +302 -0
  66. package/sources/mapAsyncIterator.ts +141 -0
  67. package/sources/mapIterable.ts +105 -0
  68. package/sources/mapIterator.ts +145 -0
  69. package/sources/mutableCondition.ts +451 -0
  70. package/sources/mutableHttpHeaders.ts +204 -0
  71. package/sources/mutableMap.ts +292 -0
  72. package/sources/network.ts +18 -0
  73. package/sources/node.ts +37 -0
  74. package/sources/nodeJSCharacterWriteStream.ts +42 -0
  75. package/sources/nodeJSHttpIncomingRequest.ts +132 -0
  76. package/sources/nodeJSHttpServer.ts +134 -0
  77. package/sources/notFoundError.ts +12 -0
  78. package/sources/postCondition.ts +284 -0
  79. package/sources/postConditionError.ts +12 -0
  80. package/sources/preCondition.ts +284 -0
  81. package/sources/preConditionError.ts +12 -0
  82. package/sources/promiseAsyncResult.ts +174 -0
  83. package/sources/property.ts +63 -0
  84. package/sources/queue.ts +49 -0
  85. package/sources/realNetwork.ts +28 -0
  86. package/sources/recreationDotGovClient.ts +259 -0
  87. package/sources/searchControl.ts +42 -0
  88. package/sources/set.ts +244 -0
  89. package/sources/skipAsyncIterator.ts +145 -0
  90. package/sources/skipIterator.ts +155 -0
  91. package/sources/stack.ts +48 -0
  92. package/sources/stringComparer.ts +33 -0
  93. package/sources/stringIterator.ts +149 -0
  94. package/sources/strings.ts +322 -0
  95. package/sources/syncResult.ts +300 -0
  96. package/sources/takeAsyncIterator.ts +141 -0
  97. package/sources/takeIterator.ts +151 -0
  98. package/sources/toStringFunctions.ts +185 -0
  99. package/sources/types.ts +371 -0
  100. package/sources/whereAsyncIterator.ts +143 -0
  101. package/sources/whereIterable.ts +108 -0
  102. package/sources/whereIterator.ts +157 -0
  103. package/sources/wonderlandTrailClient.ts +1503 -0
  104. package/tests/assertTest.ts +113 -0
  105. package/tests/assertTestTests.ts +75 -0
  106. package/tests/basicTestSkip.ts +51 -0
  107. package/tests/byteListStreamTests.ts +390 -0
  108. package/tests/byteListTests.ts +27 -0
  109. package/tests/bytesTests.ts +43 -0
  110. package/tests/characterListStreamTests.ts +391 -0
  111. package/tests/characterListTests.ts +250 -0
  112. package/tests/characterWriteStreamTests.ts +12 -0
  113. package/tests/comparerTests.ts +92 -0
  114. package/tests/conditionTests.ts +877 -0
  115. package/tests/consoleTestRunner.ts +404 -0
  116. package/tests/consoleTestRunnerTests.ts +651 -0
  117. package/tests/dateTimeTests.ts +30 -0
  118. package/tests/depthFirstSearchTests.ts +106 -0
  119. package/tests/disposableTests.ts +121 -0
  120. package/tests/englishTests.ts +103 -0
  121. package/tests/equalFunctionsTests.ts +223 -0
  122. package/tests/failedTest.ts +43 -0
  123. package/tests/fetchHttpClientTests.ts +33 -0
  124. package/tests/generatorTests.ts +86 -0
  125. package/tests/httpClientTests.ts +18 -0
  126. package/tests/inMemoryCharacterWriteStreamTests.ts +117 -0
  127. package/tests/iterableTests.ts +141 -0
  128. package/tests/iteratorTests.ts +1086 -0
  129. package/tests/javascriptMapMapTests.ts +21 -0
  130. package/tests/listTests.ts +338 -0
  131. package/tests/mapIteratorTests.ts +55 -0
  132. package/tests/mapTests.ts +104 -0
  133. package/tests/mutableConditionTests.ts +273 -0
  134. package/tests/mutableMapTests.ts +154 -0
  135. package/tests/nodeJSHttpServerTests.ts +75 -0
  136. package/tests/notFoundErrorTests.ts +24 -0
  137. package/tests/postConditionErrorTests.ts +24 -0
  138. package/tests/preConditionErrorTests.ts +24 -0
  139. package/tests/promiseAsyncResultTests.ts +688 -0
  140. package/tests/propertyTests.ts +63 -0
  141. package/tests/queueTests.ts +29 -0
  142. package/tests/recreationDotGovClientTests.ts +191 -0
  143. package/tests/setTests.ts +140 -0
  144. package/tests/skippedTest.ts +39 -0
  145. package/tests/stackTests.ts +66 -0
  146. package/tests/stringComparerTests.ts +60 -0
  147. package/tests/stringIteratorTests.ts +156 -0
  148. package/tests/stringsTests.ts +516 -0
  149. package/tests/syncResultTests.ts +1251 -0
  150. package/tests/test.ts +228 -0
  151. package/tests/testAction.ts +75 -0
  152. package/tests/testActionTests.ts +93 -0
  153. package/tests/testFailureTests.ts +12 -0
  154. package/tests/testRunner.ts +267 -0
  155. package/tests/testRunnerTests.ts +895 -0
  156. package/tests/testSkip.ts +34 -0
  157. package/tests/tests.ts +103 -0
  158. package/tests/toStringFunctionsTests.ts +55 -0
  159. package/tests/typesTests.ts +257 -0
  160. package/tests/whereIteratorTests.ts +77 -0
  161. package/tests/wonderlandTrailClientTests.ts +452 -0
  162. package/tsconfig.json +17 -0
  163. package/tsup.config.ts +13 -0
@@ -0,0 +1,250 @@
1
+ import { CharacterList } from "../sources/characterList";
2
+ import { EqualFunctions } from "../sources/equalFunctions";
3
+ import { JavascriptIterable } from "../sources/javascript";
4
+ import { NotFoundError } from "../sources/notFoundError";
5
+ import { PreConditionError } from "../sources/preConditionError";
6
+ import { isNumber, isString } from "../sources/types";
7
+ import { Test } from "./test";
8
+ import { TestRunner } from "./testRunner";
9
+
10
+ export function test(runner: TestRunner): void
11
+ {
12
+ runner.testFile("characterList.ts", () =>
13
+ {
14
+ runner.testType("CharacterList", () =>
15
+ {
16
+ runner.testFunction("create()", () =>
17
+ {
18
+ runner.test("with no arguments", (test: Test) =>
19
+ {
20
+ const list: CharacterList = CharacterList.create();
21
+ test.assertNotUndefinedAndNotNull(list);
22
+ test.assertEqual(0, list.getCount().await());
23
+ test.assertFalse(list.any().await());
24
+ test.assertEqual([], list.toArray().await());
25
+ });
26
+
27
+ runner.test("with undefined", (test: Test) =>
28
+ {
29
+ const list: CharacterList = CharacterList.create(undefined);
30
+ test.assertNotUndefinedAndNotNull(list);
31
+ test.assertEqual(0, list.getCount().await());
32
+ test.assertFalse(list.any().await());
33
+ test.assertEqual([], list.toArray().await());
34
+ });
35
+
36
+ runner.test("with null", (test: Test) =>
37
+ {
38
+ const list: CharacterList = CharacterList.create(null!);
39
+ test.assertNotUndefinedAndNotNull(list);
40
+ test.assertEqual(0, list.getCount().await());
41
+ test.assertFalse(list.any().await());
42
+ test.assertEqual([], list.toArray().await());
43
+ });
44
+
45
+ runner.test("with empty initialValues", (test: Test) =>
46
+ {
47
+ const list: CharacterList = CharacterList.create([]);
48
+ test.assertNotUndefinedAndNotNull(list);
49
+ test.assertEqual(0, list.getCount().await());
50
+ test.assertFalse(list.any().await());
51
+ test.assertEqual([], list.toArray().await());
52
+ });
53
+
54
+ runner.test("with one value", (test: Test) =>
55
+ {
56
+ const list: CharacterList = CharacterList.create(["m"]);
57
+ test.assertNotUndefinedAndNotNull(list);
58
+ test.assertEqual(1, list.getCount().await());
59
+ test.assertTrue(list.any().await());
60
+ test.assertEqual(["m"], list.toArray().await());
61
+ });
62
+
63
+ runner.test("with two values", (test: Test) =>
64
+ {
65
+ const list: CharacterList = CharacterList.create(["n", "l"]);
66
+ test.assertNotUndefinedAndNotNull(list);
67
+ test.assertEqual(2, list.getCount().await());
68
+ test.assertTrue(list.any().await());
69
+ test.assertEqual(["n", "l"], list.toArray().await());
70
+ });
71
+ });
72
+
73
+ runner.testFunction("add()", () =>
74
+ {
75
+ function addErrorTest(value: string, expected: Error): void
76
+ {
77
+ runner.test(`with ${runner.toString(value)}`, (test: Test) =>
78
+ {
79
+ const list: CharacterList = CharacterList.create();
80
+ test.assertThrows(() => list.add(value), expected);
81
+ test.assertEqual([], list.toArray().await());
82
+ });
83
+ }
84
+
85
+ addErrorTest("", new PreConditionError(
86
+ "Expression: value",
87
+ "Expected: character",
88
+ "Actual: \"\"",
89
+ ));
90
+ addErrorTest("ab", new PreConditionError(
91
+ "Expression: value",
92
+ "Expected: character",
93
+ "Actual: \"ab\"",
94
+ ));
95
+
96
+ runner.test("with valid value", (test: Test) =>
97
+ {
98
+ const list: CharacterList = CharacterList.create();
99
+
100
+ const addResult1: CharacterList = list.add("a");
101
+ test.assertSame(list, addResult1);
102
+ test.assertEqual(["a"], addResult1.toArray().await());
103
+
104
+ const addResult2: CharacterList = list.add("b");
105
+ test.assertSame(list, addResult2);
106
+ test.assertEqual(["a", "b"], addResult2.toArray().await());
107
+
108
+ const addResult3: CharacterList = list.add("c");
109
+ test.assertSame(list, addResult3);
110
+ test.assertEqual(["a", "b", "c"], addResult3.toArray().await());
111
+
112
+ const addResult4: CharacterList = list.add("d");
113
+ test.assertSame(list, addResult4);
114
+ test.assertEqual(["a", "b", "c", "d"], addResult4.toArray().await());
115
+ });
116
+ });
117
+
118
+ runner.testFunction("addAll()", () =>
119
+ {
120
+ runner.test("with empty values", (test: Test) =>
121
+ {
122
+ const list: CharacterList = CharacterList.create();
123
+
124
+ const addAllResult: CharacterList = list.addAll([]);
125
+ test.assertSame(list, addAllResult);
126
+ test.assertEqual([], list.toArray().await());
127
+ });
128
+
129
+ runner.test("with non-empty values", (test: Test) =>
130
+ {
131
+ const list: CharacterList = CharacterList.create();
132
+
133
+ const addAllResult: CharacterList = list.addAll("abcde");
134
+ test.assertSame(list, addAllResult);
135
+ test.assertEqual(["a", "b", "c", "d", "e"], list.toArray().await());
136
+ });
137
+ });
138
+
139
+ runner.testFunction("insert()", () =>
140
+ {
141
+ function insertErrorTest(initialValues: string[], index: number, value: string, expected: Error): void
142
+ {
143
+ runner.test(`with ${runner.andList([initialValues, index, value])}`, (test: Test) =>
144
+ {
145
+ const list: CharacterList = CharacterList.create(initialValues);
146
+ test.assertThrows(() => list.insert(index, value), expected);
147
+ test.assertEqual(initialValues, list.toArray().await());
148
+ });
149
+ }
150
+
151
+ insertErrorTest([], -1, "a", new PreConditionError(
152
+ "Expression: index",
153
+ "Expected: 0",
154
+ "Actual: -1",
155
+ ));
156
+ insertErrorTest([], 1, "a", new PreConditionError(
157
+ "Expression: index",
158
+ "Expected: 0",
159
+ "Actual: 1",
160
+ ));
161
+ insertErrorTest(["z"], -1, "a", new PreConditionError(
162
+ "Expression: index",
163
+ "Expected: between 0 and 1",
164
+ "Actual: -1",
165
+ ));
166
+ insertErrorTest(["z"], 2, "a", new PreConditionError(
167
+ "Expression: index",
168
+ "Expected: between 0 and 1",
169
+ "Actual: 2",
170
+ ));
171
+ insertErrorTest([], 0, "", new PreConditionError(
172
+ "Expression: value",
173
+ "Expected: character",
174
+ "Actual: \"\"",
175
+ ));
176
+ insertErrorTest([], 0, "ab", new PreConditionError(
177
+ "Expression: value",
178
+ "Expected: character",
179
+ "Actual: \"ab\"",
180
+ ));
181
+
182
+ function insertTest(initialValues: JavascriptIterable<string>, index: number, value: string, expected: string[]): void
183
+ {
184
+ runner.test(`with ${runner.andList([initialValues, index, value])}`, (test: Test) =>
185
+ {
186
+ const list: CharacterList = CharacterList.create(initialValues);
187
+
188
+ const insertResult: CharacterList = list.insert(index, value);
189
+ test.assertSame(list, insertResult);
190
+ test.assertEqual(expected, list.toArray().await());
191
+ });
192
+ }
193
+
194
+ insertTest([], 0, "z", ["z"]);
195
+ insertTest(["a"], 0, "y", ["y", "a"]);
196
+ insertTest(["a"], 1, "y", ["a", "y"]);
197
+ insertTest(["a", "b", "c"], 0, "z", ["z", "a", "b", "c"]);
198
+ insertTest(["a", "b", "c"], 1, "z", ["a", "z", "b", "c"]);
199
+ insertTest(["a", "b", "c"], 2, "z", ["a", "b", "z", "c"]);
200
+ insertTest(["a", "b", "c"], 3, "z", ["a", "b", "c", "z"]);
201
+ insertTest(["a", "b", "c", "d", "e"], 2, "z", ["a", "b", "z", "c", "d", "e"]);
202
+ });
203
+
204
+ runner.testFunction("remove()", () =>
205
+ {
206
+ runner.test("with not-found value", (test: Test) =>
207
+ {
208
+ const list: CharacterList = CharacterList.create();
209
+
210
+ test.assertThrows(() => list.remove("a").await(), new NotFoundError("Could not find the value to remove: \"a\""));
211
+ test.assertEqual([], list.toArray().await());
212
+ });
213
+
214
+ runner.test("with found value", (test: Test) =>
215
+ {
216
+ const list: CharacterList = CharacterList.create(["a"]);
217
+
218
+ const removeResult: string = list.remove("a").await();
219
+ test.assertEqual("a", removeResult);
220
+ test.assertEqual([], list.toArray().await());
221
+ });
222
+
223
+ runner.test("with multiple found values", (test: Test) =>
224
+ {
225
+ const list: CharacterList = CharacterList.create(["a", "a", "a"]);
226
+
227
+ const removeResult: string = list.remove("a").await();
228
+ test.assertEqual("a", removeResult);
229
+ test.assertEqual(["a", "a"], list.toArray().await());
230
+ });
231
+
232
+ runner.test("with multiple found values and equalFunctions", (test: Test) =>
233
+ {
234
+ const list: CharacterList = CharacterList.create(["a", "b", "c", "d", "e"]);
235
+ const isVowel = (character: string) => ["a", "e", "i", "o", "u"].includes(character);
236
+ const equalFunctions: EqualFunctions = EqualFunctions.create()
237
+ .add((left: unknown, right: unknown) =>
238
+ {
239
+ return isString(left) && isString(right)
240
+ ? isVowel(left) === isVowel(right)
241
+ : undefined;
242
+ });
243
+ const removeResult: string = list.remove("i", equalFunctions).await();
244
+ test.assertEqual("a", removeResult);
245
+ test.assertEqual(["b", "c", "d", "e"], list.toArray().await());
246
+ });
247
+ });
248
+ });
249
+ });
250
+ }
@@ -0,0 +1,12 @@
1
+ import { CharacterWriteStream } from "../sources/characterWriteStream";
2
+ import { TestRunner } from "./testRunner";
3
+
4
+ export function test(runner: TestRunner, creator: () => CharacterWriteStream): void
5
+ {
6
+ runner.testFile("characterWriteStream.ts", () =>
7
+ {
8
+ runner.testType("CharacterWriteStream", () =>
9
+ {
10
+ });
11
+ });
12
+ }
@@ -0,0 +1,92 @@
1
+ import { Comparer } from "../sources/comparer";
2
+ import { Comparison } from "../sources/comparison";
3
+ import { Test } from "./test";
4
+ import { TestRunner } from "./testRunner";
5
+
6
+ export function test(runner: TestRunner): void
7
+ {
8
+ runner.testFile("comparer.ts", () =>
9
+ {
10
+ runner.testType("Comparer<TLeft,TRight>", () =>
11
+ {
12
+ runner.testFunction("compareSameUndefinedNull()", () =>
13
+ {
14
+ function compareSameUndefinedNullTest(left: unknown, right: unknown, expected: Comparison | undefined): void
15
+ {
16
+ runner.test(`with ${runner.andList([left, right])}`, (test: Test) =>
17
+ {
18
+ test.assertEqual(Comparer.compareSameUndefinedNull(left, right), expected);
19
+ });
20
+ }
21
+
22
+ compareSameUndefinedNullTest(undefined, undefined, Comparison.Equal);
23
+ compareSameUndefinedNullTest(undefined, null, Comparison.LessThan);
24
+ compareSameUndefinedNullTest(undefined, "hello", Comparison.LessThan);
25
+ compareSameUndefinedNullTest(undefined, 50, Comparison.LessThan);
26
+
27
+ compareSameUndefinedNullTest(null, undefined, Comparison.GreaterThan);
28
+ compareSameUndefinedNullTest(null, null, Comparison.Equal);
29
+ compareSameUndefinedNullTest(null, "hello", Comparison.LessThan);
30
+ compareSameUndefinedNullTest(null, 50, Comparison.LessThan);
31
+
32
+ compareSameUndefinedNullTest("hello", undefined, Comparison.GreaterThan);
33
+ compareSameUndefinedNullTest("hello", null, Comparison.GreaterThan);
34
+ compareSameUndefinedNullTest("hello", "hello", Comparison.Equal);
35
+ compareSameUndefinedNullTest("hello", "abc", undefined);
36
+ compareSameUndefinedNullTest("hello", 50, undefined);
37
+ });
38
+
39
+ runner.testFunction("equalSameUndefinedNull()", () =>
40
+ {
41
+ function equalSameUndefinedNullTest(left: unknown, right: unknown, expected: boolean | undefined): void
42
+ {
43
+ runner.test(`with ${runner.andList([left, right])}`, (test: Test) =>
44
+ {
45
+ test.assertEqual(Comparer.equalSameUndefinedNull(left, right), expected);
46
+ });
47
+ }
48
+
49
+ equalSameUndefinedNullTest(undefined, undefined, true);
50
+ equalSameUndefinedNullTest(undefined, null, false);
51
+ equalSameUndefinedNullTest(undefined, "hello", false);
52
+ equalSameUndefinedNullTest(undefined, 50, false);
53
+
54
+ equalSameUndefinedNullTest(null, undefined, false);
55
+ equalSameUndefinedNullTest(null, null, true);
56
+ equalSameUndefinedNullTest(null, "hello", false);
57
+ equalSameUndefinedNullTest(null, 50, false);
58
+
59
+ equalSameUndefinedNullTest("hello", undefined, false);
60
+ equalSameUndefinedNullTest("hello", null, false);
61
+ equalSameUndefinedNullTest("hello", "hello", true);
62
+ equalSameUndefinedNullTest("hello", "abc", undefined);
63
+ equalSameUndefinedNullTest("hello", 50, undefined);
64
+ });
65
+
66
+ runner.testFunction("compareNumbers()", () =>
67
+ {
68
+ function compareNumbersTest(left: number | null | undefined, right: number | null | undefined, expected: Comparison | undefined): void
69
+ {
70
+ runner.test(`with ${runner.andList([left, right])}`, (test: Test) =>
71
+ {
72
+ test.assertEqual(Comparer.compareNumbers(left, right), expected);
73
+ });
74
+ }
75
+
76
+ compareNumbersTest(undefined, undefined, Comparison.Equal);
77
+ compareNumbersTest(undefined, null, Comparison.LessThan);
78
+ compareNumbersTest(undefined, 50, Comparison.LessThan);
79
+
80
+ compareNumbersTest(null, undefined, Comparison.GreaterThan);
81
+ compareNumbersTest(null, null, Comparison.Equal);
82
+ compareNumbersTest(null, 50, Comparison.LessThan);
83
+
84
+ compareNumbersTest(50, undefined, Comparison.GreaterThan);
85
+ compareNumbersTest(50, null, Comparison.GreaterThan);
86
+ compareNumbersTest(50, 30, Comparison.GreaterThan);
87
+ compareNumbersTest(50, 50, Comparison.Equal);
88
+ compareNumbersTest(50, 60, Comparison.LessThan);
89
+ });
90
+ });
91
+ });
92
+ }