@angular-wave/angular.ts 0.0.1

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 (231) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.cjs +29 -0
  3. package/.github/workflows/playwright.yml +27 -0
  4. package/CHANGELOG.md +17974 -0
  5. package/CODE_OF_CONDUCT.md +3 -0
  6. package/CONTRIBUTING.md +246 -0
  7. package/DEVELOPERS.md +488 -0
  8. package/LICENSE +22 -0
  9. package/Makefile +31 -0
  10. package/README.md +115 -0
  11. package/RELEASE.md +98 -0
  12. package/SECURITY.md +16 -0
  13. package/TRIAGING.md +135 -0
  14. package/css/angular.css +22 -0
  15. package/dist/angular-ts.cjs.js +36843 -0
  16. package/dist/angular-ts.esm.js +36841 -0
  17. package/dist/angular-ts.umd.js +36848 -0
  18. package/dist/build/angular-animate.js +4272 -0
  19. package/dist/build/angular-aria.js +426 -0
  20. package/dist/build/angular-message-format.js +1072 -0
  21. package/dist/build/angular-messages.js +829 -0
  22. package/dist/build/angular-mocks.js +3757 -0
  23. package/dist/build/angular-parse-ext.js +1275 -0
  24. package/dist/build/angular-resource.js +911 -0
  25. package/dist/build/angular-route.js +1266 -0
  26. package/dist/build/angular-sanitize.js +891 -0
  27. package/dist/build/angular-touch.js +368 -0
  28. package/dist/build/angular.js +36600 -0
  29. package/e2e/unit.spec.ts +15 -0
  30. package/images/android-chrome-192x192.png +0 -0
  31. package/images/android-chrome-512x512.png +0 -0
  32. package/images/apple-touch-icon.png +0 -0
  33. package/images/favicon-16x16.png +0 -0
  34. package/images/favicon-32x32.png +0 -0
  35. package/images/favicon.ico +0 -0
  36. package/images/site.webmanifest +1 -0
  37. package/index.html +104 -0
  38. package/package.json +47 -0
  39. package/playwright.config.ts +78 -0
  40. package/public/circle.html +1 -0
  41. package/public/my_child_directive.html +1 -0
  42. package/public/my_directive.html +1 -0
  43. package/public/my_other_directive.html +1 -0
  44. package/public/test.html +1 -0
  45. package/rollup.config.js +31 -0
  46. package/src/animations/animateCache.js +55 -0
  47. package/src/animations/animateChildrenDirective.js +105 -0
  48. package/src/animations/animateCss.js +1139 -0
  49. package/src/animations/animateCssDriver.js +291 -0
  50. package/src/animations/animateJs.js +367 -0
  51. package/src/animations/animateJsDriver.js +67 -0
  52. package/src/animations/animateQueue.js +851 -0
  53. package/src/animations/animation.js +506 -0
  54. package/src/animations/module.js +779 -0
  55. package/src/animations/ngAnimateSwap.js +119 -0
  56. package/src/animations/rafScheduler.js +50 -0
  57. package/src/animations/shared.js +378 -0
  58. package/src/constants.js +20 -0
  59. package/src/core/animate.js +845 -0
  60. package/src/core/animateCss.js +73 -0
  61. package/src/core/animateRunner.js +195 -0
  62. package/src/core/attributes.js +199 -0
  63. package/src/core/cache.js +45 -0
  64. package/src/core/compile.js +4727 -0
  65. package/src/core/controller.js +225 -0
  66. package/src/core/exceptionHandler.js +63 -0
  67. package/src/core/filter.js +146 -0
  68. package/src/core/interpolate.js +442 -0
  69. package/src/core/interval.js +188 -0
  70. package/src/core/intervalFactory.js +57 -0
  71. package/src/core/location.js +1086 -0
  72. package/src/core/parser/parse.js +2562 -0
  73. package/src/core/parser/parse.md +13 -0
  74. package/src/core/q.js +746 -0
  75. package/src/core/rootScope.js +1596 -0
  76. package/src/core/sanitizeUri.js +85 -0
  77. package/src/core/sce.js +1161 -0
  78. package/src/core/taskTrackerFactory.js +125 -0
  79. package/src/core/timeout.js +121 -0
  80. package/src/core/urlUtils.js +187 -0
  81. package/src/core/utils.js +1349 -0
  82. package/src/directive/a.js +37 -0
  83. package/src/directive/attrs.js +283 -0
  84. package/src/directive/bind.js +51 -0
  85. package/src/directive/bind.md +142 -0
  86. package/src/directive/change.js +12 -0
  87. package/src/directive/change.md +25 -0
  88. package/src/directive/cloak.js +12 -0
  89. package/src/directive/cloak.md +24 -0
  90. package/src/directive/events.js +75 -0
  91. package/src/directive/events.md +166 -0
  92. package/src/directive/form.js +725 -0
  93. package/src/directive/init.js +15 -0
  94. package/src/directive/init.md +41 -0
  95. package/src/directive/input.js +1783 -0
  96. package/src/directive/list.js +46 -0
  97. package/src/directive/list.md +22 -0
  98. package/src/directive/ngClass.js +249 -0
  99. package/src/directive/ngController.js +64 -0
  100. package/src/directive/ngCsp.js +82 -0
  101. package/src/directive/ngIf.js +134 -0
  102. package/src/directive/ngInclude.js +217 -0
  103. package/src/directive/ngModel.js +1356 -0
  104. package/src/directive/ngModelOptions.js +509 -0
  105. package/src/directive/ngOptions.js +670 -0
  106. package/src/directive/ngRef.js +90 -0
  107. package/src/directive/ngRepeat.js +650 -0
  108. package/src/directive/ngShowHide.js +255 -0
  109. package/src/directive/ngSwitch.js +178 -0
  110. package/src/directive/ngTransclude.js +98 -0
  111. package/src/directive/non-bindable.js +11 -0
  112. package/src/directive/non-bindable.md +17 -0
  113. package/src/directive/script.js +30 -0
  114. package/src/directive/select.js +624 -0
  115. package/src/directive/style.js +25 -0
  116. package/src/directive/style.md +23 -0
  117. package/src/directive/validators.js +329 -0
  118. package/src/exts/aria.js +544 -0
  119. package/src/exts/messages.js +852 -0
  120. package/src/filters/filter.js +207 -0
  121. package/src/filters/filter.md +69 -0
  122. package/src/filters/filters.js +239 -0
  123. package/src/filters/json.md +16 -0
  124. package/src/filters/limit-to.js +43 -0
  125. package/src/filters/limit-to.md +19 -0
  126. package/src/filters/order-by.js +183 -0
  127. package/src/filters/order-by.md +83 -0
  128. package/src/index.js +13 -0
  129. package/src/injector.js +1034 -0
  130. package/src/jqLite.js +1117 -0
  131. package/src/loader.js +1320 -0
  132. package/src/public.js +215 -0
  133. package/src/routeToRegExp.js +41 -0
  134. package/src/services/anchorScroll.js +135 -0
  135. package/src/services/browser.js +321 -0
  136. package/src/services/cacheFactory.js +398 -0
  137. package/src/services/cookieReader.js +72 -0
  138. package/src/services/document.js +64 -0
  139. package/src/services/http.js +1537 -0
  140. package/src/services/httpBackend.js +206 -0
  141. package/src/services/log.js +160 -0
  142. package/src/services/templateRequest.js +139 -0
  143. package/test/angular.spec.js +2153 -0
  144. package/test/aria/aria.spec.js +1245 -0
  145. package/test/binding.spec.js +504 -0
  146. package/test/build-test.html +14 -0
  147. package/test/injector.spec.js +2327 -0
  148. package/test/jasmine/jasmine-5.1.2/boot0.js +65 -0
  149. package/test/jasmine/jasmine-5.1.2/boot1.js +133 -0
  150. package/test/jasmine/jasmine-5.1.2/jasmine-html.js +963 -0
  151. package/test/jasmine/jasmine-5.1.2/jasmine.css +320 -0
  152. package/test/jasmine/jasmine-5.1.2/jasmine.js +10824 -0
  153. package/test/jasmine/jasmine-5.1.2/jasmine_favicon.png +0 -0
  154. package/test/jasmine/jasmine-browser.json +17 -0
  155. package/test/jasmine/jasmine.json +9 -0
  156. package/test/jqlite.spec.js +2133 -0
  157. package/test/loader.spec.js +219 -0
  158. package/test/messages/messages.spec.js +1146 -0
  159. package/test/min-err.spec.js +174 -0
  160. package/test/mock-test.html +13 -0
  161. package/test/module-test.html +15 -0
  162. package/test/ng/anomate.spec.js +606 -0
  163. package/test/ng/cache-factor.spec.js +334 -0
  164. package/test/ng/compile.spec.js +17956 -0
  165. package/test/ng/controller-provider.spec.js +227 -0
  166. package/test/ng/cookie-reader.spec.js +98 -0
  167. package/test/ng/directive/a.spec.js +192 -0
  168. package/test/ng/directive/bind.spec.js +334 -0
  169. package/test/ng/directive/boolean.spec.js +136 -0
  170. package/test/ng/directive/change.spec.js +71 -0
  171. package/test/ng/directive/class.spec.js +858 -0
  172. package/test/ng/directive/click.spec.js +38 -0
  173. package/test/ng/directive/cloak.spec.js +44 -0
  174. package/test/ng/directive/constoller.spec.js +194 -0
  175. package/test/ng/directive/element-style.spec.js +92 -0
  176. package/test/ng/directive/event.spec.js +282 -0
  177. package/test/ng/directive/form.spec.js +1518 -0
  178. package/test/ng/directive/href.spec.js +143 -0
  179. package/test/ng/directive/if.spec.js +402 -0
  180. package/test/ng/directive/include.spec.js +828 -0
  181. package/test/ng/directive/init.spec.js +68 -0
  182. package/test/ng/directive/input.spec.js +3810 -0
  183. package/test/ng/directive/list.spec.js +170 -0
  184. package/test/ng/directive/model-options.spec.js +1008 -0
  185. package/test/ng/directive/model.spec.js +1905 -0
  186. package/test/ng/directive/non-bindable.spec.js +55 -0
  187. package/test/ng/directive/options.spec.js +3583 -0
  188. package/test/ng/directive/ref.spec.js +575 -0
  189. package/test/ng/directive/repeat.spec.js +1675 -0
  190. package/test/ng/directive/script.spec.js +52 -0
  191. package/test/ng/directive/scrset.spec.js +67 -0
  192. package/test/ng/directive/select.spec.js +2541 -0
  193. package/test/ng/directive/show-hide.spec.js +253 -0
  194. package/test/ng/directive/src.spec.js +157 -0
  195. package/test/ng/directive/style.spec.js +178 -0
  196. package/test/ng/directive/switch.spec.js +647 -0
  197. package/test/ng/directive/validators.spec.js +717 -0
  198. package/test/ng/document.spec.js +52 -0
  199. package/test/ng/filter/filter.spec.js +714 -0
  200. package/test/ng/filter/filters.spec.js +35 -0
  201. package/test/ng/filter/limit-to.spec.js +251 -0
  202. package/test/ng/filter/order-by.spec.js +891 -0
  203. package/test/ng/filter.spec.js +149 -0
  204. package/test/ng/http-backend.spec.js +398 -0
  205. package/test/ng/http.spec.js +4071 -0
  206. package/test/ng/interpolate.spec.js +642 -0
  207. package/test/ng/interval.spec.js +343 -0
  208. package/test/ng/location.spec.js +3488 -0
  209. package/test/ng/on.spec.js +229 -0
  210. package/test/ng/parse.spec.js +4655 -0
  211. package/test/ng/prop.spec.js +805 -0
  212. package/test/ng/q.spec.js +2904 -0
  213. package/test/ng/root-element.spec.js +16 -0
  214. package/test/ng/sanitize-uri.spec.js +249 -0
  215. package/test/ng/sce.spec.js +660 -0
  216. package/test/ng/scope.spec.js +3442 -0
  217. package/test/ng/template-request.spec.js +236 -0
  218. package/test/ng/timeout.spec.js +351 -0
  219. package/test/ng/url-utils.spec.js +156 -0
  220. package/test/ng/utils.spec.js +144 -0
  221. package/test/original-test.html +21 -0
  222. package/test/public.spec.js +34 -0
  223. package/test/sanitize/bing-html.spec.js +36 -0
  224. package/test/server/express.js +158 -0
  225. package/test/test-utils.js +11 -0
  226. package/tsconfig.json +17 -0
  227. package/types/angular.d.ts +138 -0
  228. package/types/global.d.ts +9 -0
  229. package/types/index.d.ts +2357 -0
  230. package/types/jqlite.d.ts +558 -0
  231. package/vite.config.js +14 -0
@@ -0,0 +1,321 @@
1
+ import { jqLite } from "../jqLite";
2
+ import { urlResolve } from "../core/urlUtils";
3
+ import { forEach, isUndefined, equals } from "../core/utils";
4
+
5
+ // This variable should be used *only* inside the cacheState function.
6
+ let lastCachedState = null;
7
+
8
+ export function getHash(url) {
9
+ const index = url.indexOf("#");
10
+ return index === -1 ? "" : url.substr(index);
11
+ }
12
+
13
+ export function trimEmptyHash(url) {
14
+ return url.replace(/#$/, "");
15
+ }
16
+
17
+ /**
18
+ *
19
+ *
20
+ * @name $browser
21
+ * @requires $log
22
+ * @description
23
+ * This object has two goals:
24
+ *
25
+ * - hide all the global state in the browser caused by the window object
26
+ * - abstract away all the browser specific features and inconsistencies
27
+ *
28
+ */
29
+
30
+ /**
31
+ * @param {object} $log window.console or an object with the same interface.
32
+ */
33
+ export function Browser($log, $$taskTrackerFactory) {
34
+ const self = this;
35
+ let { location } = window;
36
+ let { history } = window;
37
+ const { setTimeout } = window;
38
+ const { clearTimeout } = window;
39
+ const pendingDeferIds = {};
40
+ const taskTracker = $$taskTrackerFactory($log);
41
+
42
+ /// ///////////////////////////////////////////////////////////
43
+ // Task-tracking API
44
+ /// ///////////////////////////////////////////////////////////
45
+
46
+ // TODO(vojta): remove this temporary api
47
+ self.$$completeOutstandingRequest = taskTracker.completeTask;
48
+ self.$$incOutstandingRequestCount = taskTracker.incTaskCount;
49
+
50
+ // TODO(vojta): prefix this method with $$ ?
51
+ self.notifyWhenNoOutstandingRequests = taskTracker.notifyWhenNoPendingTasks;
52
+
53
+ /// ///////////////////////////////////////////////////////////
54
+ // URL API
55
+ /// ///////////////////////////////////////////////////////////
56
+
57
+ let cachedState;
58
+ let lastHistoryState;
59
+ let lastBrowserUrl = location.href;
60
+ const baseElement = jqLite(
61
+ Array.from(window.document.getElementsByTagName("base")),
62
+ );
63
+ let pendingLocation = null;
64
+ const getCurrentState = function getCurrentState() {
65
+ return history.state;
66
+ };
67
+
68
+ cacheState();
69
+
70
+ /**
71
+ * @name $browser#url
72
+ *
73
+ * @description
74
+ * GETTER:
75
+ * Without any argument, this method just returns current value of `location.href` (with a
76
+ * trailing `#` stripped of if the hash is empty).
77
+ *
78
+ * SETTER:
79
+ * With at least one argument, this method sets url to new value.
80
+ * If html5 history api supported, `pushState`/`replaceState` is used, otherwise
81
+ * `location.href`/`location.replace` is used.
82
+ * Returns its own instance to allow chaining.
83
+ *
84
+ * NOTE: this api is intended for use only by the `$location` service. Please use the
85
+ * {@link ng.$location $location service} to change url.
86
+ *
87
+ * @param {string} url New url (when used as setter)
88
+ * @param {boolean=} replace Should new url replace current history record?
89
+ * @param {object=} state State object to use with `pushState`/`replaceState`
90
+ */
91
+ self.url = function (url, replace, state) {
92
+ // In modern browsers `history.state` is `null` by default; treating it separately
93
+ // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
94
+ // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
95
+ if (isUndefined(state)) {
96
+ state = null;
97
+ }
98
+
99
+ // Android Browser BFCache causes location, history reference to become stale.
100
+ if (location !== window.location) location = window.location;
101
+ if (history !== window.history) history = window.history;
102
+
103
+ // setter
104
+ if (url) {
105
+ const sameState = lastHistoryState === state;
106
+
107
+ // Normalize the inputted URL
108
+ url = urlResolve(url).href;
109
+
110
+ // Don't change anything if previous and current URLs and states match. This also prevents
111
+ // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
112
+ // See https://github.com/angular/angular.js/commit/ffb2701
113
+ if (lastBrowserUrl === url && sameState) {
114
+ return self;
115
+ }
116
+ // const sameBase =
117
+ // lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
118
+ lastBrowserUrl = url;
119
+ lastHistoryState = state;
120
+ // Don't use history API if only the hash changed
121
+ // due to a bug in IE10/IE11 which leads
122
+ // to not firing a `hashchange` nor `popstate` event
123
+ // in some cases (see #9143).
124
+ history[replace ? "replaceState" : "pushState"](state, "", url);
125
+ cacheState();
126
+ return self;
127
+ // getter
128
+ }
129
+ // - pendingLocation is needed as browsers don't allow to read out
130
+ // the new location.href if a reload happened or if there is a bug like in iOS 9 (see
131
+ // https://openradar.appspot.com/22186109).
132
+ return trimEmptyHash(pendingLocation || location.href);
133
+ };
134
+
135
+ /**
136
+ * @name $browser#state
137
+ *
138
+ * @description
139
+ * This method is a getter.
140
+ *
141
+ * Return history.state or null if history.state is undefined.
142
+ *
143
+ * @returns {object} state
144
+ */
145
+ self.state = function () {
146
+ return cachedState;
147
+ };
148
+
149
+ const urlChangeListeners = [];
150
+ let urlChangeInit = false;
151
+
152
+ function cacheStateAndFireUrlChange() {
153
+ pendingLocation = null;
154
+ fireStateOrUrlChange();
155
+ }
156
+
157
+ function cacheState() {
158
+ // This should be the only place in $browser where `history.state` is read.
159
+ cachedState = getCurrentState();
160
+ cachedState = isUndefined(cachedState) ? null : cachedState;
161
+
162
+ // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
163
+ if (equals(cachedState, lastCachedState)) {
164
+ cachedState = lastCachedState;
165
+ }
166
+
167
+ lastCachedState = cachedState;
168
+ lastHistoryState = cachedState;
169
+ }
170
+
171
+ function fireStateOrUrlChange() {
172
+ const prevLastHistoryState = lastHistoryState;
173
+ cacheState();
174
+
175
+ if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
176
+ return;
177
+ }
178
+
179
+ lastBrowserUrl = self.url();
180
+ lastHistoryState = cachedState;
181
+ forEach(urlChangeListeners, (listener) => {
182
+ listener(self.url(), cachedState);
183
+ });
184
+ }
185
+
186
+ /**
187
+ * @name $browser#onUrlChange
188
+ *
189
+ * @description
190
+ * Register callback function that will be called, when url changes.
191
+ *
192
+ * It's only called when the url is changed from outside of AngularJS:
193
+ * - user types different url into address bar
194
+ * - user clicks on history (forward/back) button
195
+ * - user clicks on a link
196
+ *
197
+ * It's not called when url is changed by $browser.url() method
198
+ *
199
+ * The listener gets called with new url as parameter.
200
+ *
201
+ * NOTE: this api is intended for use only by the $location service. Please use the
202
+ * {@link ng.$location $location service} to monitor url changes in AngularJS apps.
203
+ *
204
+ * @param {function(string)} listener Listener function to be called when url changes.
205
+ * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
206
+ */
207
+ self.onUrlChange = function (callback) {
208
+ // TODO(vojta): refactor to use node's syntax for events
209
+ if (!urlChangeInit) {
210
+ // We listen on both (hashchange/popstate) when available, as some browsers don't
211
+ // fire popstate when user changes the address bar and don't fire hashchange when url
212
+ // changed by push/replaceState
213
+
214
+ // html5 history api - popstate event
215
+ jqLite(window).on("popstate", cacheStateAndFireUrlChange);
216
+ // hashchange event
217
+ jqLite(window).on("hashchange", cacheStateAndFireUrlChange);
218
+
219
+ urlChangeInit = true;
220
+ }
221
+
222
+ urlChangeListeners.push(callback);
223
+ return callback;
224
+ };
225
+
226
+ /**
227
+ * Remove popstate and hashchange handler from window.
228
+ *
229
+ * NOTE: this api is intended for use only by $rootScope.
230
+ */
231
+ self.$$applicationDestroyed = function () {
232
+ jqLite(window).off("hashchange popstate", cacheStateAndFireUrlChange);
233
+ };
234
+
235
+ /**
236
+ * Checks whether the url has changed outside of AngularJS.
237
+ * Needs to be exported to be able to check for changes that have been done in sync,
238
+ * as hashchange/popstate events fire in async.
239
+ */
240
+ self.$$checkUrlChange = fireStateOrUrlChange;
241
+
242
+ /// ///////////////////////////////////////////////////////////
243
+ // Misc API
244
+ /// ///////////////////////////////////////////////////////////
245
+
246
+ /**
247
+ * @name $browser#baseHref
248
+ *
249
+ * @description
250
+ * Returns current <base href>
251
+ * (always relative - without domain)
252
+ *
253
+ * @returns {string} The current base href
254
+ */
255
+ self.baseHref = function () {
256
+ const href = baseElement.attr("href");
257
+ return href ? href.replace(/^(https?:)?\/\/[^/]*/, "") : "";
258
+ };
259
+
260
+ /**
261
+ * @name $browser#defer
262
+ * @param {function()} fn A function, who's execution should be deferred.
263
+ * @param {number=} [delay=0] Number of milliseconds to defer the function execution.
264
+ * @param {string=} [taskType=DEFAULT_TASK_TYPE] The type of task that is deferred.
265
+ * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
266
+ *
267
+ * @description
268
+ * Executes a fn asynchronously via `setTimeout(fn, delay)`.
269
+ *
270
+ * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
271
+ * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
272
+ * via `$browser.defer.flush()`.
273
+ *
274
+ */
275
+ self.defer = function (fn, delay, taskType) {
276
+ let timeoutId;
277
+
278
+ delay = delay || 0;
279
+ taskType = taskType || taskTracker.DEFAULT_TASK_TYPE;
280
+
281
+ taskTracker.incTaskCount(taskType);
282
+ timeoutId = setTimeout(() => {
283
+ delete pendingDeferIds[timeoutId];
284
+ taskTracker.completeTask(fn, taskType);
285
+ }, delay);
286
+ pendingDeferIds[timeoutId] = taskType;
287
+
288
+ return timeoutId;
289
+ };
290
+
291
+ /**
292
+ * @name $browser#defer.cancel
293
+ *
294
+ * @description
295
+ * Cancels a deferred task identified with `deferId`.
296
+ *
297
+ * @param {*} deferId Token returned by the `$browser.defer` function.
298
+ * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
299
+ * canceled.
300
+ */
301
+ self.defer.cancel = function (deferId) {
302
+ if (Object.prototype.hasOwnProperty.call(pendingDeferIds, deferId)) {
303
+ const taskType = pendingDeferIds[deferId];
304
+ delete pendingDeferIds[deferId];
305
+ clearTimeout(deferId);
306
+ taskTracker.completeTask(() => {}, taskType);
307
+ return true;
308
+ }
309
+ return false;
310
+ };
311
+ }
312
+
313
+ export function BrowserProvider() {
314
+ this.$get = [
315
+ "$log",
316
+ "$$taskTrackerFactory",
317
+ function ($log, $$taskTrackerFactory) {
318
+ return new Browser($log, $$taskTrackerFactory);
319
+ },
320
+ ];
321
+ }