@angular-wave/angular.ts 0.0.51 → 0.0.53
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.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/animations/animate-children-directive.js +19 -99
- package/src/animations/animate-children-directive.md +80 -0
- package/src/animations/animate-css-driver.js +250 -256
- package/src/animations/animate-css.js +646 -875
- package/src/animations/animate-css.md +263 -0
- package/src/animations/animate-js-driver.js +54 -56
- package/src/animations/animate-js.js +303 -306
- package/src/animations/animate-queue.js +707 -716
- package/src/animations/animate-swap.js +30 -119
- package/src/animations/animate-swap.md +88 -0
- package/src/animations/animation.js +3 -3
- package/src/core/animate/animate-css.js +21 -6
- package/src/core/animate/animate-runner.js +147 -145
- package/src/core/animate/animate.js +572 -585
- package/src/core/animate/animate.spec.js +194 -286
- package/src/core/animate/anomate.md +13 -0
- package/src/core/animate/helpers.js +10 -0
- package/src/core/compile/compile.spec.js +5 -6
- package/src/core/core.html +0 -1
- package/src/directive/select/select.js +301 -305
- package/src/public.js +0 -1
- package/src/router/directives/state-directives.js +256 -574
- package/src/router/directives/state-directives.md +435 -0
- package/src/router/directives/view-directive.js +3 -3
- package/src/router/index.js +7 -7
- package/types/animations/animate-children-directive.d.ts +5 -80
- package/types/animations/animate-css-driver.d.ts +11 -0
- package/types/animations/animate-css.d.ts +8 -0
- package/types/animations/animate-js-driver.d.ts +8 -0
- package/types/animations/animate-js.d.ts +12 -0
- package/types/animations/animate-queue.d.ts +19 -0
- package/types/animations/animate-swap.d.ts +5 -89
- package/types/core/animate/animate-css.d.ts +1 -1
- package/types/core/animate/animate-runner.d.ts +32 -0
- package/types/core/animate/animate.d.ts +509 -0
- package/types/core/animate/helpers.d.ts +8 -0
- package/types/directive/select/select.d.ts +79 -0
- package/types/router/directives/state-directives.d.ts +31 -0
- package/src/core/document.spec.js +0 -52
|
@@ -2,290 +2,284 @@ import { JQLite } from "../shared/jqlite/jqlite";
|
|
|
2
2
|
import { forEach, isString } from "../shared/utils";
|
|
3
3
|
import { concatWithSpace, getDomNode } from "./shared";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// animation is over unless both animations are not used.
|
|
85
|
-
if (!animatorOut) {
|
|
86
|
-
animatorIn = prepareInAnimation();
|
|
87
|
-
if (!animatorIn) {
|
|
88
|
-
return end();
|
|
89
|
-
}
|
|
5
|
+
const NG_ANIMATE_SHIM_CLASS_NAME = "ng-animate-shim";
|
|
6
|
+
const NG_ANIMATE_ANCHOR_CLASS_NAME = "ng-anchor";
|
|
7
|
+
|
|
8
|
+
const NG_OUT_ANCHOR_CLASS_NAME = "ng-anchor-out";
|
|
9
|
+
const NG_IN_ANCHOR_CLASS_NAME = "ng-anchor-in";
|
|
10
|
+
|
|
11
|
+
$$AnimateCssDriverProvider.$inject = ["$$animationProvider"];
|
|
12
|
+
export function $$AnimateCssDriverProvider($$animationProvider) {
|
|
13
|
+
$$animationProvider.drivers.push("$$animateCssDriver");
|
|
14
|
+
|
|
15
|
+
function isDocumentFragment(node) {
|
|
16
|
+
return node.parentNode && node.parentNode.nodeType === 11;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @returns {Function}
|
|
21
|
+
*/
|
|
22
|
+
this.$get = [
|
|
23
|
+
"$animateCss",
|
|
24
|
+
"$$AnimateRunner",
|
|
25
|
+
"$rootElement",
|
|
26
|
+
"$document",
|
|
27
|
+
function ($animateCss, $$AnimateRunner, $rootElement, $document) {
|
|
28
|
+
const bodyNode = $document[0].body;
|
|
29
|
+
const rootNode = getDomNode($rootElement);
|
|
30
|
+
|
|
31
|
+
const rootBodyElement = JQLite(
|
|
32
|
+
// this is to avoid using something that exists outside of the body
|
|
33
|
+
// we also special case the doc fragment case because our unit test code
|
|
34
|
+
// appends the $rootElement to the body after the app has been bootstrapped
|
|
35
|
+
isDocumentFragment(rootNode) || bodyNode.contains(rootNode)
|
|
36
|
+
? rootNode
|
|
37
|
+
: bodyNode,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return function initDriverFn(animationDetails) {
|
|
41
|
+
return animationDetails.from && animationDetails.to
|
|
42
|
+
? prepareFromToAnchorAnimation(
|
|
43
|
+
animationDetails.from,
|
|
44
|
+
animationDetails.to,
|
|
45
|
+
animationDetails.classes,
|
|
46
|
+
animationDetails.anchors,
|
|
47
|
+
)
|
|
48
|
+
: prepareRegularAnimation(animationDetails);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function filterCssClasses(classes) {
|
|
52
|
+
// remove all the `ng-` stuff
|
|
53
|
+
return classes.replace(/\bng-\S+\b/g, "");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getUniqueValues(a, b) {
|
|
57
|
+
if (isString(a)) a = a.split(" ");
|
|
58
|
+
if (isString(b)) b = b.split(" ");
|
|
59
|
+
return a.filter((val) => b.indexOf(val) === -1).join(" ");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {
|
|
63
|
+
const clone = JQLite(getDomNode(outAnchor).cloneNode(true));
|
|
64
|
+
const startingClasses = filterCssClasses(getClassVal(clone));
|
|
65
|
+
|
|
66
|
+
outAnchor[0].classList.add(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
67
|
+
inAnchor[0].classList.add(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
68
|
+
|
|
69
|
+
clone[0].classList.add(NG_ANIMATE_ANCHOR_CLASS_NAME);
|
|
70
|
+
|
|
71
|
+
rootBodyElement.append(clone);
|
|
72
|
+
|
|
73
|
+
let animatorIn;
|
|
74
|
+
const animatorOut = prepareOutAnimation();
|
|
75
|
+
|
|
76
|
+
// the user may not end up using the `out` animation and
|
|
77
|
+
// only making use of the `in` animation or vice-versa.
|
|
78
|
+
// In either case we should allow this and not assume the
|
|
79
|
+
// animation is over unless both animations are not used.
|
|
80
|
+
if (!animatorOut) {
|
|
81
|
+
animatorIn = prepareInAnimation();
|
|
82
|
+
if (!animatorIn) {
|
|
83
|
+
return end();
|
|
90
84
|
}
|
|
85
|
+
}
|
|
91
86
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// in the event that there is no `in` animation
|
|
114
|
-
end();
|
|
115
|
-
runner.complete();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
runner = new $$AnimateRunner({
|
|
119
|
-
end: endFn,
|
|
120
|
-
cancel: endFn,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
return runner;
|
|
124
|
-
|
|
125
|
-
function endFn() {
|
|
126
|
-
if (currentAnimation) {
|
|
127
|
-
currentAnimation.end();
|
|
87
|
+
const startingAnimator = animatorOut || animatorIn;
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
start() {
|
|
91
|
+
let runner;
|
|
92
|
+
|
|
93
|
+
let currentAnimation = startingAnimator.start();
|
|
94
|
+
currentAnimation.done(() => {
|
|
95
|
+
currentAnimation = null;
|
|
96
|
+
if (!animatorIn) {
|
|
97
|
+
animatorIn = prepareInAnimation();
|
|
98
|
+
if (animatorIn) {
|
|
99
|
+
currentAnimation = animatorIn.start();
|
|
100
|
+
currentAnimation.done(() => {
|
|
101
|
+
currentAnimation = null;
|
|
102
|
+
end();
|
|
103
|
+
runner.complete();
|
|
104
|
+
});
|
|
105
|
+
return currentAnimation;
|
|
128
106
|
}
|
|
129
107
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
function calculateAnchorStyles(anchor) {
|
|
134
|
-
const styles = {};
|
|
135
|
-
|
|
136
|
-
const coords = getDomNode(anchor).getBoundingClientRect();
|
|
137
|
-
|
|
138
|
-
// we iterate directly since safari messes up and doesn't return
|
|
139
|
-
// all the keys for the coords object when iterated
|
|
140
|
-
["width", "height", "top", "left"].forEach((key) => {
|
|
141
|
-
let value = coords[key];
|
|
142
|
-
switch (key) {
|
|
143
|
-
case "top":
|
|
144
|
-
value += bodyNode.scrollTop;
|
|
145
|
-
break;
|
|
146
|
-
case "left":
|
|
147
|
-
value += bodyNode.scrollLeft;
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
styles[key] = `${Math.floor(value)}px`;
|
|
108
|
+
// in the event that there is no `in` animation
|
|
109
|
+
end();
|
|
110
|
+
runner.complete();
|
|
151
111
|
});
|
|
152
|
-
return styles;
|
|
153
|
-
}
|
|
154
112
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
delay: true,
|
|
159
|
-
from: calculateAnchorStyles(outAnchor),
|
|
113
|
+
runner = new $$AnimateRunner({
|
|
114
|
+
end: endFn,
|
|
115
|
+
cancel: endFn,
|
|
160
116
|
});
|
|
161
117
|
|
|
162
|
-
|
|
163
|
-
// why this check is necessary
|
|
164
|
-
return animator.$$willAnimate ? animator : null;
|
|
165
|
-
}
|
|
118
|
+
return runner;
|
|
166
119
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
120
|
+
function endFn() {
|
|
121
|
+
if (currentAnimation) {
|
|
122
|
+
currentAnimation.end();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
|
170
127
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
128
|
+
function calculateAnchorStyles(anchor) {
|
|
129
|
+
const styles = {};
|
|
130
|
+
|
|
131
|
+
const coords = getDomNode(anchor).getBoundingClientRect();
|
|
132
|
+
|
|
133
|
+
// we iterate directly since safari messes up and doesn't return
|
|
134
|
+
// all the keys for the coords object when iterated
|
|
135
|
+
["width", "height", "top", "left"].forEach((key) => {
|
|
136
|
+
let value = coords[key];
|
|
137
|
+
switch (key) {
|
|
138
|
+
case "top":
|
|
139
|
+
value += bodyNode.scrollTop;
|
|
140
|
+
break;
|
|
141
|
+
case "left":
|
|
142
|
+
value += bodyNode.scrollLeft;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
styles[key] = `${Math.floor(value)}px`;
|
|
146
|
+
});
|
|
147
|
+
return styles;
|
|
148
|
+
}
|
|
175
149
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
150
|
+
function prepareOutAnimation() {
|
|
151
|
+
const animator = $animateCss(clone, {
|
|
152
|
+
addClass: NG_OUT_ANCHOR_CLASS_NAME,
|
|
153
|
+
delay: true,
|
|
154
|
+
from: calculateAnchorStyles(outAnchor),
|
|
155
|
+
});
|
|
182
156
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
157
|
+
// read the comment within `prepareRegularAnimation` to understand
|
|
158
|
+
// why this check is necessary
|
|
159
|
+
return animator.$$willAnimate ? animator : null;
|
|
160
|
+
}
|
|
187
161
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
191
|
-
inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
192
|
-
}
|
|
162
|
+
function getClassVal(element) {
|
|
163
|
+
return element.attr("class") || "";
|
|
193
164
|
}
|
|
194
165
|
|
|
195
|
-
function
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
const anchorAnimations = [];
|
|
200
|
-
forEach(anchors, (anchor) => {
|
|
201
|
-
const outElement = anchor.out;
|
|
202
|
-
const inElement = anchor.in;
|
|
203
|
-
const animator = prepareAnchoredAnimation(
|
|
204
|
-
classes,
|
|
205
|
-
outElement,
|
|
206
|
-
inElement,
|
|
207
|
-
);
|
|
208
|
-
if (animator) {
|
|
209
|
-
anchorAnimations.push(animator);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
166
|
+
function prepareInAnimation() {
|
|
167
|
+
const endingClasses = filterCssClasses(getClassVal(inAnchor));
|
|
168
|
+
const toAdd = getUniqueValues(endingClasses, startingClasses);
|
|
169
|
+
const toRemove = getUniqueValues(startingClasses, endingClasses);
|
|
212
170
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
171
|
+
const animator = $animateCss(clone, {
|
|
172
|
+
to: calculateAnchorStyles(inAnchor),
|
|
173
|
+
addClass: `${NG_IN_ANCHOR_CLASS_NAME} ${toAdd}`,
|
|
174
|
+
removeClass: `${NG_OUT_ANCHOR_CLASS_NAME} ${toRemove}`,
|
|
175
|
+
delay: true,
|
|
176
|
+
});
|
|
216
177
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
178
|
+
// read the comment within `prepareRegularAnimation` to understand
|
|
179
|
+
// why this check is necessary
|
|
180
|
+
return animator.$$willAnimate ? animator : null;
|
|
181
|
+
}
|
|
220
182
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
183
|
+
function end() {
|
|
184
|
+
clone.remove();
|
|
185
|
+
outAnchor[0].classList.remove(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
186
|
+
inAnchor[0].classList.remove(NG_ANIMATE_SHIM_CLASS_NAME);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function prepareFromToAnchorAnimation(from, to, classes, anchors) {
|
|
191
|
+
const fromAnimation = prepareRegularAnimation(from);
|
|
192
|
+
const toAnimation = prepareRegularAnimation(to);
|
|
193
|
+
|
|
194
|
+
const anchorAnimations = [];
|
|
195
|
+
forEach(anchors, (anchor) => {
|
|
196
|
+
const outElement = anchor.out;
|
|
197
|
+
const inElement = anchor.in;
|
|
198
|
+
const animator = prepareAnchoredAnimation(
|
|
199
|
+
classes,
|
|
200
|
+
outElement,
|
|
201
|
+
inElement,
|
|
202
|
+
);
|
|
203
|
+
if (animator) {
|
|
204
|
+
anchorAnimations.push(animator);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
224
207
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
208
|
+
// no point in doing anything when there are no elements to animate
|
|
209
|
+
if (!fromAnimation && !toAnimation && anchorAnimations.length === 0)
|
|
210
|
+
return;
|
|
228
211
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
212
|
+
return {
|
|
213
|
+
start() {
|
|
214
|
+
const animationRunners = [];
|
|
232
215
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
});
|
|
216
|
+
if (fromAnimation) {
|
|
217
|
+
animationRunners.push(fromAnimation.start());
|
|
218
|
+
}
|
|
237
219
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
220
|
+
if (toAnimation) {
|
|
221
|
+
animationRunners.push(toAnimation.start());
|
|
222
|
+
}
|
|
241
223
|
|
|
242
|
-
|
|
224
|
+
forEach(anchorAnimations, (animation) => {
|
|
225
|
+
animationRunners.push(animation.start());
|
|
226
|
+
});
|
|
243
227
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
}
|
|
228
|
+
const runner = new $$AnimateRunner({
|
|
229
|
+
end: endFn,
|
|
230
|
+
cancel: endFn, // CSS-driven animations cannot be cancelled, only ended
|
|
231
|
+
});
|
|
252
232
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
233
|
+
$$AnimateRunner.all(animationRunners, (status) => {
|
|
234
|
+
runner.complete(status);
|
|
235
|
+
});
|
|
256
236
|
|
|
257
|
-
|
|
258
|
-
options.event = animationDetails.event;
|
|
259
|
-
options.structural = true;
|
|
260
|
-
options.applyClassesEarly = true;
|
|
237
|
+
return runner;
|
|
261
238
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
options.onDone = options.domOperation;
|
|
239
|
+
function endFn() {
|
|
240
|
+
forEach(animationRunners, (runner) => {
|
|
241
|
+
runner.end();
|
|
242
|
+
});
|
|
267
243
|
}
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function prepareRegularAnimation(animationDetails) {
|
|
249
|
+
const { element } = animationDetails;
|
|
250
|
+
const options = animationDetails.options || {};
|
|
251
|
+
|
|
252
|
+
if (animationDetails.structural) {
|
|
253
|
+
options.event = animationDetails.event;
|
|
254
|
+
options.structural = true;
|
|
255
|
+
options.applyClassesEarly = true;
|
|
256
|
+
|
|
257
|
+
// we special case the leave animation since we want to ensure that
|
|
258
|
+
// the element is removed as soon as the animation is over. Otherwise
|
|
259
|
+
// a flicker might appear or the element may not be removed at all
|
|
260
|
+
if (animationDetails.event === "leave") {
|
|
261
|
+
options.onDone = options.domOperation;
|
|
268
262
|
}
|
|
263
|
+
}
|
|
269
264
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const animator = $animateCss(element, options);
|
|
281
|
-
|
|
282
|
-
// the driver lookup code inside of $$animation attempts to spawn a
|
|
283
|
-
// driver one by one until a driver returns a.$$willAnimate animator object.
|
|
284
|
-
// $animateCss will always return an object, however, it will pass in
|
|
285
|
-
// a flag as a hint as to whether an animation was detected or not
|
|
286
|
-
return animator.$$willAnimate ? animator : null;
|
|
265
|
+
// We assign the preparationClasses as the actual animation event since
|
|
266
|
+
// the internals of $animateCss will just suffix the event token values
|
|
267
|
+
// with `-active` to trigger the animation.
|
|
268
|
+
if (options.preparationClasses) {
|
|
269
|
+
options.event = concatWithSpace(
|
|
270
|
+
options.event,
|
|
271
|
+
options.preparationClasses,
|
|
272
|
+
);
|
|
287
273
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
274
|
+
|
|
275
|
+
const animator = $animateCss(element, options);
|
|
276
|
+
|
|
277
|
+
// the driver lookup code inside of $$animation attempts to spawn a
|
|
278
|
+
// driver one by one until a driver returns a.$$willAnimate animator object.
|
|
279
|
+
// $animateCss will always return an object, however, it will pass in
|
|
280
|
+
// a flag as a hint as to whether an animation was detected or not
|
|
281
|
+
return animator.$$willAnimate ? animator : null;
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
];
|
|
285
|
+
}
|