1 | !function(f) {
|
2 | if ("object" == typeof exports && "undefined" != typeof module) module.exports = f(); else if ("function" == typeof define && define.amd) define([], f); else {
|
3 | var g;
|
4 | g = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this;
|
5 | g.gameStorage = f();
|
6 | }
|
7 | }(function() {
|
8 | return function e(t, n, r) {
|
9 | function s(o, u) {
|
10 | if (!n[o]) {
|
11 | if (!t[o]) {
|
12 | var a = "function" == typeof require && require;
|
13 | if (!u && a) return a(o, !0);
|
14 | if (i) return i(o, !0);
|
15 | var f = new Error("Cannot find module '" + o + "'");
|
16 | throw f.code = "MODULE_NOT_FOUND", f;
|
17 | }
|
18 | var l = n[o] = {
|
19 | exports: {}
|
20 | };
|
21 | t[o][0].call(l.exports, function(e) {
|
22 | var n = t[o][1][e];
|
23 | return s(n ? n : e);
|
24 | }, l, l.exports, e, t, n, r);
|
25 | }
|
26 | return n[o].exports;
|
27 | }
|
28 | for (var i = "function" == typeof require && require, o = 0; o < r.length; o++) s(r[o]);
|
29 | return s;
|
30 | }({
|
31 | 1: [ function(require, module, exports) {
|
32 | "use strict";
|
33 | var g = require("@akashic/akashic-engine"), validator = require("./validator"), KEY_PREFIX = "akst:", GameStorage = function() {
|
34 | function GameStorage(localStorage, metaData) {
|
35 | this._localStorage = localStorage;
|
36 | this._metaData = metaData;
|
37 | }
|
38 | GameStorage.prototype.set = function(key, value, option) {
|
39 | validator.validateStorageKey(key);
|
40 | this.expandVariables(key);
|
41 | var strKey = this.storageKeyToStringKey(key), current = this.getValue(strKey), newValue = null;
|
42 | switch (key.region) {
|
43 | case g.StorageRegion.Values:
|
44 | newValue = this.createValuesValue(current, value, option);
|
45 | break;
|
46 |
|
47 | case g.StorageRegion.Counts:
|
48 | newValue = this.createCountsValue(current, value, option);
|
49 | break;
|
50 |
|
51 | case g.StorageRegion.Scores:
|
52 | newValue = this.createScoresValue(current, value, option);
|
53 | break;
|
54 |
|
55 | case g.StorageRegion.Slots:
|
56 | throw new Error("Slots is not supported.");
|
57 |
|
58 | default:
|
59 | throw new Error("Unknown region.");
|
60 | }
|
61 | if (newValue) {
|
62 | var finalValue = null, date = new Date();
|
63 | finalValue = current ? {
|
64 | data: newValue.data,
|
65 | tag: newValue.tag,
|
66 | createdAt: current.createdAt,
|
67 | updatedAt: date
|
68 | } : {
|
69 | data: newValue.data,
|
70 | tag: newValue.tag,
|
71 | createdAt: date,
|
72 | updatedAt: date
|
73 | };
|
74 | this.setValue(strKey, finalValue);
|
75 | }
|
76 | };
|
77 | GameStorage.prototype.load = function(readKeys) {
|
78 | var _this = this, allValues = {};
|
79 | Object.keys(this._localStorage).forEach(function(key) {
|
80 | if (0 === key.indexOf(KEY_PREFIX)) {
|
81 | var k = key.slice(KEY_PREFIX.length);
|
82 | allValues[k] = _this.getValue(k);
|
83 | }
|
84 | });
|
85 | var results = [];
|
86 | readKeys.forEach(function(readKey) {
|
87 | validator.validateStorageReadKey(readKey);
|
88 | _this.expandVariables(readKey);
|
89 | var values = [];
|
90 | if (readKey.regionKey.indexOf("*") !== -1 || "*" === readKey.userId) {
|
91 | var regexp = _this.storageReadKeyToRegExp(readKey);
|
92 | Object.keys(allValues).forEach(function(key) {
|
93 | if (regexp.test(key)) {
|
94 | var lv = allValues[key], sv = {
|
95 | data: lv.data,
|
96 | storageKey: _this.stringKeyToStorageKey(key)
|
97 | };
|
98 | null != lv.tag && (sv.tag = lv.tag);
|
99 | values.push(sv);
|
100 | }
|
101 | });
|
102 | if (readKey.option) {
|
103 | void 0 !== readKey.option.valueOrder && _this.sortByValue(values, readKey.option.valueOrder);
|
104 | void 0 !== readKey.option.keyOrder && _this.sortByRegionKey(values, readKey.option.keyOrder);
|
105 | }
|
106 | } else {
|
107 | var readStrKey = _this.storageKeyToStringKey(readKey), v = allValues[readStrKey];
|
108 | if (v) {
|
109 | var sv = {
|
110 | data: v.data,
|
111 | storageKey: {
|
112 | region: readKey.region,
|
113 | regionKey: readKey.regionKey,
|
114 | userId: readKey.userId,
|
115 | gameId: readKey.gameId
|
116 | }
|
117 | };
|
118 | null != v.tag && (sv.tag = v.tag);
|
119 | values.push(sv);
|
120 | }
|
121 | }
|
122 | results.push(values);
|
123 | });
|
124 | return results;
|
125 | };
|
126 | GameStorage.prototype.clearAll = function() {
|
127 | var _this = this;
|
128 | Object.keys(this._localStorage).forEach(function(key) {
|
129 | 0 === key.indexOf(KEY_PREFIX) && _this._localStorage.removeItem(key);
|
130 | });
|
131 | };
|
132 | GameStorage.prototype.createValuesValue = function(current, value, option) {
|
133 | if (!value) return null;
|
134 | if (option && null != option.condition && null != option.comparisonValue && current && null != current.data) {
|
135 | if (option.condition !== g.StorageCondition.Equal) throw new Error("Invalid condition.");
|
136 | if (current.data !== option.comparisonValue) return null;
|
137 | }
|
138 | var result = {
|
139 | data: value.data
|
140 | };
|
141 | null != value.tag ? result.tag = value.tag : current && null != current.tag && (result.tag = current.tag);
|
142 | return result;
|
143 | };
|
144 | GameStorage.prototype.createScoresValue = function(current, value, option) {
|
145 | if (!value) return null;
|
146 | if (option && null != option.condition && null != option.comparisonValue && current && null != current.data) switch (option.condition) {
|
147 | case g.StorageCondition.Equal:
|
148 | if (current.data !== option.comparisonValue) return null;
|
149 | break;
|
150 |
|
151 | case g.StorageCondition.GreaterThan:
|
152 | if (!(current.data > option.comparisonValue)) return null;
|
153 | break;
|
154 |
|
155 | case g.StorageCondition.LessThan:
|
156 | if (!(current.data < option.comparisonValue)) return null;
|
157 | }
|
158 | var result = {
|
159 | data: value.data
|
160 | };
|
161 | null != value.tag ? result.tag = value.tag : current && null != current.tag && (result.tag = current.tag);
|
162 | return result;
|
163 | };
|
164 | GameStorage.prototype.createCountsIncrDecrValue = function(current, value, option) {
|
165 | var result = {
|
166 | data: 0
|
167 | }, currentCount = 0;
|
168 | current && (currentCount = Number(current.data));
|
169 | if (null != option.condition && null != option.comparisonValue) switch (option.condition) {
|
170 | case g.StorageCondition.Equal:
|
171 | if (currentCount !== option.comparisonValue) return current ? null : result;
|
172 | break;
|
173 |
|
174 | case g.StorageCondition.GreaterThan:
|
175 | if (!(currentCount > option.comparisonValue)) return current ? null : result;
|
176 | break;
|
177 |
|
178 | case g.StorageCondition.LessThan:
|
179 | if (!(currentCount < option.comparisonValue)) return current ? null : result;
|
180 | }
|
181 | if (option.operation === g.StorageCountsOperation.Incr) value && null != value.data ? result.data = currentCount + Number(value.data) : result.data = currentCount + 1; else {
|
182 | if (option.operation !== g.StorageCountsOperation.Decr) throw new Error("Unknown StorageCountsOperation");
|
183 | value && null != value.data ? result.data = currentCount - Number(value.data) : result.data = currentCount - 1;
|
184 | }
|
185 | value && null != value.tag ? result.tag = value.tag : current && null != current.tag && (result.tag = current.tag);
|
186 | return result;
|
187 | };
|
188 | GameStorage.prototype.createCountsValue = function(current, value, option) {
|
189 | if (option) {
|
190 | if (option.operation === g.StorageCountsOperation.Incr || option.operation === g.StorageCountsOperation.Decr) return this.createCountsIncrDecrValue(current, value, option);
|
191 | if (null != option.condition && null != option.comparisonValue && current && null != current.data) switch (option.condition) {
|
192 | case g.StorageCondition.Equal:
|
193 | if (current.data !== option.comparisonValue) return null;
|
194 | break;
|
195 |
|
196 | case g.StorageCondition.GreaterThan:
|
197 | if (!(current.data > option.comparisonValue)) return null;
|
198 | break;
|
199 |
|
200 | case g.StorageCondition.LessThan:
|
201 | if (!(current.data < option.comparisonValue)) return null;
|
202 | }
|
203 | }
|
204 | var result = {
|
205 | data: value.data
|
206 | };
|
207 | value && null != value.tag ? result.tag = value.tag : current && null != current.tag && (result.tag = current.tag);
|
208 | return result;
|
209 | };
|
210 | GameStorage.prototype.setValue = function(key, value) {
|
211 | this._localStorage.setItem("" + KEY_PREFIX + key, JSON.stringify(value));
|
212 | };
|
213 | GameStorage.prototype.getValue = function(key) {
|
214 | var v = JSON.parse(this._localStorage.getItem("" + KEY_PREFIX + key));
|
215 | return v;
|
216 | };
|
217 | GameStorage.prototype.storageKeyToStringKey = function(key) {
|
218 | var region = key.region || "", gameId = null != key.gameId ? String(key.gameId) : "", userId = null != key.userId ? String(key.userId) : "", regionKey = key.regionKey || "";
|
219 | return region + "/" + gameId + "/" + userId + "/" + regionKey;
|
220 | };
|
221 | GameStorage.prototype.stringKeyToStorageKey = function(key) {
|
222 | var s = key.split("/"), res = {
|
223 | region: Number(s[0]),
|
224 | regionKey: s[3]
|
225 | };
|
226 | s[1] && (res.gameId = s[1]);
|
227 | s[2] && (res.userId = s[2]);
|
228 | return res;
|
229 | };
|
230 | GameStorage.prototype.storageReadKeyToRegExp = function(key) {
|
231 | var region = key.region || "", gameId = null != key.gameId ? String(key.gameId) : "", userId = null != key.userId ? String(key.userId) : "", regionKey = "";
|
232 | "*" === userId && (userId = "[0-9]+");
|
233 | if (key.regionKey.indexOf("*") !== -1) {
|
234 | var layerKeys = key.regionKey.split(".");
|
235 | layerKeys.forEach(function(layerKey, index) {
|
236 | regionKey += "*" === layerKey ? "[.a-z0-9]*" : layerKey.indexOf("*") !== -1 ? layerKey.replace("*", "[a-z0-9]*") : layerKey;
|
237 | index !== layerKeys.length - 1 && (regionKey += ".");
|
238 | });
|
239 | } else regionKey = key.regionKey.replace(".", ".");
|
240 | return new RegExp("^" + region + "/" + gameId + "/" + userId + "/" + regionKey + "$");
|
241 | };
|
242 | GameStorage.prototype.sortByValue = function(values, order) {
|
243 | values.sort(function(a, b) {
|
244 | var va = a.data, vb = b.data;
|
245 | if (order === g.StorageOrder.Asc) {
|
246 | if (va < vb) return -1;
|
247 | if (va > vb) return 1;
|
248 | } else if (order === g.StorageOrder.Desc) {
|
249 | if (va < vb) return 1;
|
250 | if (va > vb) return -1;
|
251 | }
|
252 | return 0;
|
253 | });
|
254 | };
|
255 | GameStorage.prototype.sortByRegionKey = function(values, order) {
|
256 | values.sort(function(a, b) {
|
257 | var ka = a.storageKey.regionKey, kb = b.storageKey.regionKey;
|
258 | if (order === g.StorageOrder.Asc) {
|
259 | if (ka < kb) return -1;
|
260 | if (ka > kb) return 1;
|
261 | } else if (order === g.StorageOrder.Desc) {
|
262 | if (ka < kb) return 1;
|
263 | if (ka > kb) return -1;
|
264 | }
|
265 | return 0;
|
266 | });
|
267 | };
|
268 | GameStorage.prototype.expandVariables = function(key) {
|
269 | key.gameId && key.gameId.indexOf("$gameId") !== -1 && this._metaData.gameId && (key.gameId = key.gameId.replace(/\$gameId/g, this._metaData.gameId));
|
270 | };
|
271 | return GameStorage;
|
272 | }();
|
273 | exports.GameStorage = GameStorage;
|
274 | }, {
|
275 | "./validator": 3,
|
276 | "@akashic/akashic-engine": "@akashic/akashic-engine"
|
277 | } ],
|
278 | 2: [ function(require, module, exports) {
|
279 | "use strict";
|
280 | var gs = require("./GameStorage");
|
281 | exports.GameStorage = gs.GameStorage;
|
282 | }, {
|
283 | "./GameStorage": 1
|
284 | } ],
|
285 | 3: [ function(require, module, exports) {
|
286 | "use strict";
|
287 | function validateRegionKey(regionKey, forReading) {
|
288 | assert(regionKey.length > 0, "regionKey is empty.");
|
289 | var layerKeys = regionKey.split(".");
|
290 | assert(layerKeys.length <= REGIONKEY_MAX_LAYER_NUM, "The maximum number of layers in the region key is " + REGIONKEY_MAX_LAYER_NUM + ".");
|
291 | for (var hasWildcard = !1, i = 0; i < layerKeys.length; ++i) if (forReading) if ("*" === layerKeys[i]) {
|
292 | assert(!hasWildcard, "The only one layer of the region key for reading consists of a wildcard character.");
|
293 | hasWildcard = !0;
|
294 | } else assert(/^(\*|[a-z])[a-z0-9]{0,31}\*?$/.test(layerKeys[i]), "The layer of the region key for reading must match '^(*|[a-z])[a-z0-9]{0,31}*?$'."); else assert(/^[a-z][a-z0-9]{0,31}$/.test(layerKeys[i]), "The layer of the region key for writing must match '^[a-z][a-z0-9]{0,31}$'.");
|
295 | }
|
296 | function validateStorageKey(key, forReading) {
|
297 | void 0 === forReading && (forReading = !1);
|
298 | assert(key.region === g.StorageRegion.Counts || key.region === g.StorageRegion.Scores || key.region === g.StorageRegion.Values, "Invalid region.");
|
299 | assert(key.regionKey, "regionKey must be set.");
|
300 | validateRegionKey(key.regionKey, forReading);
|
301 | assert(key.gameId || key.userId, "StorageKey must have any one at least from gameId and userId.");
|
302 | if (null != key.gameId) {
|
303 | assert.equal(typeof key.gameId, "string", "gameId must be a string type.");
|
304 | assert(key.gameId.length > 0, "gameId is empty.");
|
305 | }
|
306 | if (null != key.userId) {
|
307 | assert.equal(typeof key.userId, "string", "userId must be a string type.");
|
308 | assert(key.userId.length > 0, "userId is empty.");
|
309 | if (forReading) {
|
310 | if ("*" === key.userId) {
|
311 | assert(key.gameId, 'gameId for reading must be set when userId is "*".');
|
312 | assert(key.regionKey.indexOf("*") === -1, 'regionKey for reading must not include "*" when userId is "*".');
|
313 | }
|
314 | } else assert("*" !== key.userId, 'userId for writing must not include "*".');
|
315 | }
|
316 | }
|
317 | function validateStorageReadKey(key) {
|
318 | validateStorageKey(key, !0);
|
319 | if (null != key.option) {
|
320 | var opt = key.option;
|
321 | null != opt.keyOrder && assert(opt.keyOrder === g.StorageOrder.Asc || opt.keyOrder === g.StorageOrder.Desc, "Invalid keyOrder.");
|
322 | null != opt.valueOrder && assert(opt.valueOrder === g.StorageOrder.Asc || opt.valueOrder === g.StorageOrder.Desc, "Invalid valueOrder.");
|
323 | }
|
324 | }
|
325 | function validateStorageWriteOption(option) {}
|
326 | var assert = require("assert"), g = require("@akashic/akashic-engine"), REGIONKEY_MAX_LAYER_NUM = 4;
|
327 | exports.validateRegionKey = validateRegionKey;
|
328 | exports.validateStorageKey = validateStorageKey;
|
329 | exports.validateStorageReadKey = validateStorageReadKey;
|
330 | exports.validateStorageWriteOption = validateStorageWriteOption;
|
331 | }, {
|
332 | "@akashic/akashic-engine": "@akashic/akashic-engine",
|
333 | assert: 4
|
334 | } ],
|
335 | 4: [ function(require, module, exports) {
|
336 | (function(global) {
|
337 | "use strict";
|
338 | |
339 |
|
340 |
|
341 |
|
342 |
|
343 |
|
344 | function compare(a, b) {
|
345 | if (a === b) return 0;
|
346 | for (var x = a.length, y = b.length, i = 0, len = Math.min(x, y); i < len; ++i) if (a[i] !== b[i]) {
|
347 | x = a[i];
|
348 | y = b[i];
|
349 | break;
|
350 | }
|
351 | return x < y ? -1 : y < x ? 1 : 0;
|
352 | }
|
353 | function isBuffer(b) {
|
354 | return global.Buffer && "function" == typeof global.Buffer.isBuffer ? global.Buffer.isBuffer(b) : !(null == b || !b._isBuffer);
|
355 | }
|
356 | function pToString(obj) {
|
357 | return Object.prototype.toString.call(obj);
|
358 | }
|
359 | function isView(arrbuf) {
|
360 | return !isBuffer(arrbuf) && ("function" == typeof global.ArrayBuffer && ("function" == typeof ArrayBuffer.isView ? ArrayBuffer.isView(arrbuf) : !!arrbuf && (arrbuf instanceof DataView || !!(arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer))));
|
361 | }
|
362 | function getName(func) {
|
363 | if (util.isFunction(func)) {
|
364 | if (functionsHaveNames) return func.name;
|
365 | var str = func.toString(), match = str.match(regex);
|
366 | return match && match[1];
|
367 | }
|
368 | }
|
369 | function truncate(s, n) {
|
370 | return "string" == typeof s ? s.length < n ? s : s.slice(0, n) : s;
|
371 | }
|
372 | function inspect(something) {
|
373 | if (functionsHaveNames || !util.isFunction(something)) return util.inspect(something);
|
374 | var rawname = getName(something), name = rawname ? ": " + rawname : "";
|
375 | return "[Function" + name + "]";
|
376 | }
|
377 | function getMessage(self) {
|
378 | return truncate(inspect(self.actual), 128) + " " + self.operator + " " + truncate(inspect(self.expected), 128);
|
379 | }
|
380 | function fail(actual, expected, message, operator, stackStartFunction) {
|
381 | throw new assert.AssertionError({
|
382 | message: message,
|
383 | actual: actual,
|
384 | expected: expected,
|
385 | operator: operator,
|
386 | stackStartFunction: stackStartFunction
|
387 | });
|
388 | }
|
389 | function ok(value, message) {
|
390 | value || fail(value, !0, message, "==", assert.ok);
|
391 | }
|
392 | function _deepEqual(actual, expected, strict, memos) {
|
393 | if (actual === expected) return !0;
|
394 | if (isBuffer(actual) && isBuffer(expected)) return 0 === compare(actual, expected);
|
395 | if (util.isDate(actual) && util.isDate(expected)) return actual.getTime() === expected.getTime();
|
396 | if (util.isRegExp(actual) && util.isRegExp(expected)) return actual.source === expected.source && actual.global === expected.global && actual.multiline === expected.multiline && actual.lastIndex === expected.lastIndex && actual.ignoreCase === expected.ignoreCase;
|
397 | if (null !== actual && "object" == typeof actual || null !== expected && "object" == typeof expected) {
|
398 | if (isView(actual) && isView(expected) && pToString(actual) === pToString(expected) && !(actual instanceof Float32Array || actual instanceof Float64Array)) return 0 === compare(new Uint8Array(actual.buffer), new Uint8Array(expected.buffer));
|
399 | if (isBuffer(actual) !== isBuffer(expected)) return !1;
|
400 | memos = memos || {
|
401 | actual: [],
|
402 | expected: []
|
403 | };
|
404 | var actualIndex = memos.actual.indexOf(actual);
|
405 | if (actualIndex !== -1 && actualIndex === memos.expected.indexOf(expected)) return !0;
|
406 | memos.actual.push(actual);
|
407 | memos.expected.push(expected);
|
408 | return objEquiv(actual, expected, strict, memos);
|
409 | }
|
410 | return strict ? actual === expected : actual == expected;
|
411 | }
|
412 | function isArguments(object) {
|
413 | return "[object Arguments]" == Object.prototype.toString.call(object);
|
414 | }
|
415 | function objEquiv(a, b, strict, actualVisitedObjects) {
|
416 | if (null === a || void 0 === a || null === b || void 0 === b) return !1;
|
417 | if (util.isPrimitive(a) || util.isPrimitive(b)) return a === b;
|
418 | if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return !1;
|
419 | var aIsArgs = isArguments(a), bIsArgs = isArguments(b);
|
420 | if (aIsArgs && !bIsArgs || !aIsArgs && bIsArgs) return !1;
|
421 | if (aIsArgs) {
|
422 | a = pSlice.call(a);
|
423 | b = pSlice.call(b);
|
424 | return _deepEqual(a, b, strict);
|
425 | }
|
426 | var key, i, ka = objectKeys(a), kb = objectKeys(b);
|
427 | if (ka.length !== kb.length) return !1;
|
428 | ka.sort();
|
429 | kb.sort();
|
430 | for (i = ka.length - 1; i >= 0; i--) if (ka[i] !== kb[i]) return !1;
|
431 | for (i = ka.length - 1; i >= 0; i--) {
|
432 | key = ka[i];
|
433 | if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) return !1;
|
434 | }
|
435 | return !0;
|
436 | }
|
437 | function notDeepStrictEqual(actual, expected, message) {
|
438 | _deepEqual(actual, expected, !0) && fail(actual, expected, message, "notDeepStrictEqual", notDeepStrictEqual);
|
439 | }
|
440 | function expectedException(actual, expected) {
|
441 | if (!actual || !expected) return !1;
|
442 | if ("[object RegExp]" == Object.prototype.toString.call(expected)) return expected.test(actual);
|
443 | try {
|
444 | if (actual instanceof expected) return !0;
|
445 | } catch (e) {}
|
446 | return !Error.isPrototypeOf(expected) && expected.call({}, actual) === !0;
|
447 | }
|
448 | function _tryBlock(block) {
|
449 | var error;
|
450 | try {
|
451 | block();
|
452 | } catch (e) {
|
453 | error = e;
|
454 | }
|
455 | return error;
|
456 | }
|
457 | function _throws(shouldThrow, block, expected, message) {
|
458 | var actual;
|
459 | if ("function" != typeof block) throw new TypeError('"block" argument must be a function');
|
460 | if ("string" == typeof expected) {
|
461 | message = expected;
|
462 | expected = null;
|
463 | }
|
464 | actual = _tryBlock(block);
|
465 | message = (expected && expected.name ? " (" + expected.name + ")." : ".") + (message ? " " + message : ".");
|
466 | shouldThrow && !actual && fail(actual, expected, "Missing expected exception" + message);
|
467 | var userProvidedMessage = "string" == typeof message, isUnwantedException = !shouldThrow && util.isError(actual), isUnexpectedException = !shouldThrow && actual && !expected;
|
468 | (isUnwantedException && userProvidedMessage && expectedException(actual, expected) || isUnexpectedException) && fail(actual, expected, "Got unwanted exception" + message);
|
469 | if (shouldThrow && actual && expected && !expectedException(actual, expected) || !shouldThrow && actual) throw actual;
|
470 | }
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 | var util = require("util/"), hasOwn = Object.prototype.hasOwnProperty, pSlice = Array.prototype.slice, functionsHaveNames = function() {
|
490 | return "foo" === function() {}.name;
|
491 | }(), assert = module.exports = ok, regex = /\s*function\s+([^\(\s]*)\s*/;
|
492 | assert.AssertionError = function(options) {
|
493 | this.name = "AssertionError";
|
494 | this.actual = options.actual;
|
495 | this.expected = options.expected;
|
496 | this.operator = options.operator;
|
497 | if (options.message) {
|
498 | this.message = options.message;
|
499 | this.generatedMessage = !1;
|
500 | } else {
|
501 | this.message = getMessage(this);
|
502 | this.generatedMessage = !0;
|
503 | }
|
504 | var stackStartFunction = options.stackStartFunction || fail;
|
505 | if (Error.captureStackTrace) Error.captureStackTrace(this, stackStartFunction); else {
|
506 | var err = new Error();
|
507 | if (err.stack) {
|
508 | var out = err.stack, fn_name = getName(stackStartFunction), idx = out.indexOf("\n" + fn_name);
|
509 | if (idx >= 0) {
|
510 | var next_line = out.indexOf("\n", idx + 1);
|
511 | out = out.substring(next_line + 1);
|
512 | }
|
513 | this.stack = out;
|
514 | }
|
515 | }
|
516 | };
|
517 | util.inherits(assert.AssertionError, Error);
|
518 | assert.fail = fail;
|
519 | assert.ok = ok;
|
520 | assert.equal = function(actual, expected, message) {
|
521 | actual != expected && fail(actual, expected, message, "==", assert.equal);
|
522 | };
|
523 | assert.notEqual = function(actual, expected, message) {
|
524 | actual == expected && fail(actual, expected, message, "!=", assert.notEqual);
|
525 | };
|
526 | assert.deepEqual = function(actual, expected, message) {
|
527 | _deepEqual(actual, expected, !1) || fail(actual, expected, message, "deepEqual", assert.deepEqual);
|
528 | };
|
529 | assert.deepStrictEqual = function(actual, expected, message) {
|
530 | _deepEqual(actual, expected, !0) || fail(actual, expected, message, "deepStrictEqual", assert.deepStrictEqual);
|
531 | };
|
532 | assert.notDeepEqual = function(actual, expected, message) {
|
533 | _deepEqual(actual, expected, !1) && fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
|
534 | };
|
535 | assert.notDeepStrictEqual = notDeepStrictEqual;
|
536 | assert.strictEqual = function(actual, expected, message) {
|
537 | actual !== expected && fail(actual, expected, message, "===", assert.strictEqual);
|
538 | };
|
539 | assert.notStrictEqual = function(actual, expected, message) {
|
540 | actual === expected && fail(actual, expected, message, "!==", assert.notStrictEqual);
|
541 | };
|
542 | assert.throws = function(block, error, message) {
|
543 | _throws(!0, block, error, message);
|
544 | };
|
545 | assert.doesNotThrow = function(block, error, message) {
|
546 | _throws(!1, block, error, message);
|
547 | };
|
548 | assert.ifError = function(err) {
|
549 | if (err) throw err;
|
550 | };
|
551 | var objectKeys = Object.keys || function(obj) {
|
552 | var keys = [];
|
553 | for (var key in obj) hasOwn.call(obj, key) && keys.push(key);
|
554 | return keys;
|
555 | };
|
556 | }).call(this, "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
|
557 | }, {
|
558 | "util/": 8
|
559 | } ],
|
560 | 5: [ function(require, module, exports) {
|
561 | function defaultSetTimout() {
|
562 | throw new Error("setTimeout has not been defined");
|
563 | }
|
564 | function defaultClearTimeout() {
|
565 | throw new Error("clearTimeout has not been defined");
|
566 | }
|
567 | function runTimeout(fun) {
|
568 | if (cachedSetTimeout === setTimeout) return setTimeout(fun, 0);
|
569 | if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
570 | cachedSetTimeout = setTimeout;
|
571 | return setTimeout(fun, 0);
|
572 | }
|
573 | try {
|
574 | return cachedSetTimeout(fun, 0);
|
575 | } catch (e) {
|
576 | try {
|
577 | return cachedSetTimeout.call(null, fun, 0);
|
578 | } catch (e) {
|
579 | return cachedSetTimeout.call(this, fun, 0);
|
580 | }
|
581 | }
|
582 | }
|
583 | function runClearTimeout(marker) {
|
584 | if (cachedClearTimeout === clearTimeout) return clearTimeout(marker);
|
585 | if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
586 | cachedClearTimeout = clearTimeout;
|
587 | return clearTimeout(marker);
|
588 | }
|
589 | try {
|
590 | return cachedClearTimeout(marker);
|
591 | } catch (e) {
|
592 | try {
|
593 | return cachedClearTimeout.call(null, marker);
|
594 | } catch (e) {
|
595 | return cachedClearTimeout.call(this, marker);
|
596 | }
|
597 | }
|
598 | }
|
599 | function cleanUpNextTick() {
|
600 | if (draining && currentQueue) {
|
601 | draining = !1;
|
602 | currentQueue.length ? queue = currentQueue.concat(queue) : queueIndex = -1;
|
603 | queue.length && drainQueue();
|
604 | }
|
605 | }
|
606 | function drainQueue() {
|
607 | if (!draining) {
|
608 | var timeout = runTimeout(cleanUpNextTick);
|
609 | draining = !0;
|
610 | for (var len = queue.length; len; ) {
|
611 | currentQueue = queue;
|
612 | queue = [];
|
613 | for (;++queueIndex < len; ) currentQueue && currentQueue[queueIndex].run();
|
614 | queueIndex = -1;
|
615 | len = queue.length;
|
616 | }
|
617 | currentQueue = null;
|
618 | draining = !1;
|
619 | runClearTimeout(timeout);
|
620 | }
|
621 | }
|
622 | function Item(fun, array) {
|
623 | this.fun = fun;
|
624 | this.array = array;
|
625 | }
|
626 | function noop() {}
|
627 | var cachedSetTimeout, cachedClearTimeout, process = module.exports = {};
|
628 | !function() {
|
629 | try {
|
630 | cachedSetTimeout = "function" == typeof setTimeout ? setTimeout : defaultSetTimout;
|
631 | } catch (e) {
|
632 | cachedSetTimeout = defaultSetTimout;
|
633 | }
|
634 | try {
|
635 | cachedClearTimeout = "function" == typeof clearTimeout ? clearTimeout : defaultClearTimeout;
|
636 | } catch (e) {
|
637 | cachedClearTimeout = defaultClearTimeout;
|
638 | }
|
639 | }();
|
640 | var currentQueue, queue = [], draining = !1, queueIndex = -1;
|
641 | process.nextTick = function(fun) {
|
642 | var args = new Array(arguments.length - 1);
|
643 | if (arguments.length > 1) for (var i = 1; i < arguments.length; i++) args[i - 1] = arguments[i];
|
644 | queue.push(new Item(fun, args));
|
645 | 1 !== queue.length || draining || runTimeout(drainQueue);
|
646 | };
|
647 | Item.prototype.run = function() {
|
648 | this.fun.apply(null, this.array);
|
649 | };
|
650 | process.title = "browser";
|
651 | process.browser = !0;
|
652 | process.env = {};
|
653 | process.argv = [];
|
654 | process.version = "";
|
655 | process.versions = {};
|
656 | process.on = noop;
|
657 | process.addListener = noop;
|
658 | process.once = noop;
|
659 | process.off = noop;
|
660 | process.removeListener = noop;
|
661 | process.removeAllListeners = noop;
|
662 | process.emit = noop;
|
663 | process.binding = function(name) {
|
664 | throw new Error("process.binding is not supported");
|
665 | };
|
666 | process.cwd = function() {
|
667 | return "/";
|
668 | };
|
669 | process.chdir = function(dir) {
|
670 | throw new Error("process.chdir is not supported");
|
671 | };
|
672 | process.umask = function() {
|
673 | return 0;
|
674 | };
|
675 | }, {} ],
|
676 | 6: [ function(require, module, exports) {
|
677 | "function" == typeof Object.create ? module.exports = function(ctor, superCtor) {
|
678 | ctor.super_ = superCtor;
|
679 | ctor.prototype = Object.create(superCtor.prototype, {
|
680 | constructor: {
|
681 | value: ctor,
|
682 | enumerable: !1,
|
683 | writable: !0,
|
684 | configurable: !0
|
685 | }
|
686 | });
|
687 | } : module.exports = function(ctor, superCtor) {
|
688 | ctor.super_ = superCtor;
|
689 | var TempCtor = function() {};
|
690 | TempCtor.prototype = superCtor.prototype;
|
691 | ctor.prototype = new TempCtor();
|
692 | ctor.prototype.constructor = ctor;
|
693 | };
|
694 | }, {} ],
|
695 | 7: [ function(require, module, exports) {
|
696 | module.exports = function(arg) {
|
697 | return arg && "object" == typeof arg && "function" == typeof arg.copy && "function" == typeof arg.fill && "function" == typeof arg.readUInt8;
|
698 | };
|
699 | }, {} ],
|
700 | 8: [ function(require, module, exports) {
|
701 | (function(process, global) {
|
702 | function inspect(obj, opts) {
|
703 | var ctx = {
|
704 | seen: [],
|
705 | stylize: stylizeNoColor
|
706 | };
|
707 | arguments.length >= 3 && (ctx.depth = arguments[2]);
|
708 | arguments.length >= 4 && (ctx.colors = arguments[3]);
|
709 | isBoolean(opts) ? ctx.showHidden = opts : opts && exports._extend(ctx, opts);
|
710 | isUndefined(ctx.showHidden) && (ctx.showHidden = !1);
|
711 | isUndefined(ctx.depth) && (ctx.depth = 2);
|
712 | isUndefined(ctx.colors) && (ctx.colors = !1);
|
713 | isUndefined(ctx.customInspect) && (ctx.customInspect = !0);
|
714 | ctx.colors && (ctx.stylize = stylizeWithColor);
|
715 | return formatValue(ctx, obj, ctx.depth);
|
716 | }
|
717 | function stylizeWithColor(str, styleType) {
|
718 | var style = inspect.styles[styleType];
|
719 | return style ? "[" + inspect.colors[style][0] + "m" + str + "[" + inspect.colors[style][1] + "m" : str;
|
720 | }
|
721 | function stylizeNoColor(str, styleType) {
|
722 | return str;
|
723 | }
|
724 | function arrayToHash(array) {
|
725 | var hash = {};
|
726 | array.forEach(function(val, idx) {
|
727 | hash[val] = !0;
|
728 | });
|
729 | return hash;
|
730 | }
|
731 | function formatValue(ctx, value, recurseTimes) {
|
732 | if (ctx.customInspect && value && isFunction(value.inspect) && value.inspect !== exports.inspect && (!value.constructor || value.constructor.prototype !== value)) {
|
733 | var ret = value.inspect(recurseTimes, ctx);
|
734 | isString(ret) || (ret = formatValue(ctx, ret, recurseTimes));
|
735 | return ret;
|
736 | }
|
737 | var primitive = formatPrimitive(ctx, value);
|
738 | if (primitive) return primitive;
|
739 | var keys = Object.keys(value), visibleKeys = arrayToHash(keys);
|
740 | ctx.showHidden && (keys = Object.getOwnPropertyNames(value));
|
741 | if (isError(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) return formatError(value);
|
742 | if (0 === keys.length) {
|
743 | if (isFunction(value)) {
|
744 | var name = value.name ? ": " + value.name : "";
|
745 | return ctx.stylize("[Function" + name + "]", "special");
|
746 | }
|
747 | if (isRegExp(value)) return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
|
748 | if (isDate(value)) return ctx.stylize(Date.prototype.toString.call(value), "date");
|
749 | if (isError(value)) return formatError(value);
|
750 | }
|
751 | var base = "", array = !1, braces = [ "{", "}" ];
|
752 | if (isArray(value)) {
|
753 | array = !0;
|
754 | braces = [ "[", "]" ];
|
755 | }
|
756 | if (isFunction(value)) {
|
757 | var n = value.name ? ": " + value.name : "";
|
758 | base = " [Function" + n + "]";
|
759 | }
|
760 | isRegExp(value) && (base = " " + RegExp.prototype.toString.call(value));
|
761 | isDate(value) && (base = " " + Date.prototype.toUTCString.call(value));
|
762 | isError(value) && (base = " " + formatError(value));
|
763 | if (0 === keys.length && (!array || 0 == value.length)) return braces[0] + base + braces[1];
|
764 | if (recurseTimes < 0) return isRegExp(value) ? ctx.stylize(RegExp.prototype.toString.call(value), "regexp") : ctx.stylize("[Object]", "special");
|
765 | ctx.seen.push(value);
|
766 | var output;
|
767 | output = array ? formatArray(ctx, value, recurseTimes, visibleKeys, keys) : keys.map(function(key) {
|
768 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
|
769 | });
|
770 | ctx.seen.pop();
|
771 | return reduceToSingleString(output, base, braces);
|
772 | }
|
773 | function formatPrimitive(ctx, value) {
|
774 | if (isUndefined(value)) return ctx.stylize("undefined", "undefined");
|
775 | if (isString(value)) {
|
776 | var simple = "'" + JSON.stringify(value).replace(/^"|"$/g, "").replace(/'/g, "\\'").replace(/\\"/g, '"') + "'";
|
777 | return ctx.stylize(simple, "string");
|
778 | }
|
779 | return isNumber(value) ? ctx.stylize("" + value, "number") : isBoolean(value) ? ctx.stylize("" + value, "boolean") : isNull(value) ? ctx.stylize("null", "null") : void 0;
|
780 | }
|
781 | function formatError(value) {
|
782 | return "[" + Error.prototype.toString.call(value) + "]";
|
783 | }
|
784 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
|
785 | for (var output = [], i = 0, l = value.length; i < l; ++i) hasOwnProperty(value, String(i)) ? output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), !0)) : output.push("");
|
786 | keys.forEach(function(key) {
|
787 | key.match(/^\d+$/) || output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, !0));
|
788 | });
|
789 | return output;
|
790 | }
|
791 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
|
792 | var name, str, desc;
|
793 | desc = Object.getOwnPropertyDescriptor(value, key) || {
|
794 | value: value[key]
|
795 | };
|
796 | desc.get ? str = desc.set ? ctx.stylize("[Getter/Setter]", "special") : ctx.stylize("[Getter]", "special") : desc.set && (str = ctx.stylize("[Setter]", "special"));
|
797 | hasOwnProperty(visibleKeys, key) || (name = "[" + key + "]");
|
798 | if (!str) if (ctx.seen.indexOf(desc.value) < 0) {
|
799 | str = isNull(recurseTimes) ? formatValue(ctx, desc.value, null) : formatValue(ctx, desc.value, recurseTimes - 1);
|
800 | str.indexOf("\n") > -1 && (str = array ? str.split("\n").map(function(line) {
|
801 | return " " + line;
|
802 | }).join("\n").substr(2) : "\n" + str.split("\n").map(function(line) {
|
803 | return " " + line;
|
804 | }).join("\n"));
|
805 | } else str = ctx.stylize("[Circular]", "special");
|
806 | if (isUndefined(name)) {
|
807 | if (array && key.match(/^\d+$/)) return str;
|
808 | name = JSON.stringify("" + key);
|
809 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
|
810 | name = name.substr(1, name.length - 2);
|
811 | name = ctx.stylize(name, "name");
|
812 | } else {
|
813 | name = name.replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
|
814 | name = ctx.stylize(name, "string");
|
815 | }
|
816 | }
|
817 | return name + ": " + str;
|
818 | }
|
819 | function reduceToSingleString(output, base, braces) {
|
820 | var numLinesEst = 0, length = output.reduce(function(prev, cur) {
|
821 | numLinesEst++;
|
822 | cur.indexOf("\n") >= 0 && numLinesEst++;
|
823 | return prev + cur.replace(/\u001b\[\d\d?m/g, "").length + 1;
|
824 | }, 0);
|
825 | return length > 60 ? braces[0] + ("" === base ? "" : base + "\n ") + " " + output.join(",\n ") + " " + braces[1] : braces[0] + base + " " + output.join(", ") + " " + braces[1];
|
826 | }
|
827 | function isArray(ar) {
|
828 | return Array.isArray(ar);
|
829 | }
|
830 | function isBoolean(arg) {
|
831 | return "boolean" == typeof arg;
|
832 | }
|
833 | function isNull(arg) {
|
834 | return null === arg;
|
835 | }
|
836 | function isNullOrUndefined(arg) {
|
837 | return null == arg;
|
838 | }
|
839 | function isNumber(arg) {
|
840 | return "number" == typeof arg;
|
841 | }
|
842 | function isString(arg) {
|
843 | return "string" == typeof arg;
|
844 | }
|
845 | function isSymbol(arg) {
|
846 | return "symbol" == typeof arg;
|
847 | }
|
848 | function isUndefined(arg) {
|
849 | return void 0 === arg;
|
850 | }
|
851 | function isRegExp(re) {
|
852 | return isObject(re) && "[object RegExp]" === objectToString(re);
|
853 | }
|
854 | function isObject(arg) {
|
855 | return "object" == typeof arg && null !== arg;
|
856 | }
|
857 | function isDate(d) {
|
858 | return isObject(d) && "[object Date]" === objectToString(d);
|
859 | }
|
860 | function isError(e) {
|
861 | return isObject(e) && ("[object Error]" === objectToString(e) || e instanceof Error);
|
862 | }
|
863 | function isFunction(arg) {
|
864 | return "function" == typeof arg;
|
865 | }
|
866 | function isPrimitive(arg) {
|
867 | return null === arg || "boolean" == typeof arg || "number" == typeof arg || "string" == typeof arg || "symbol" == typeof arg || "undefined" == typeof arg;
|
868 | }
|
869 | function objectToString(o) {
|
870 | return Object.prototype.toString.call(o);
|
871 | }
|
872 | function pad(n) {
|
873 | return n < 10 ? "0" + n.toString(10) : n.toString(10);
|
874 | }
|
875 | function timestamp() {
|
876 | var d = new Date(), time = [ pad(d.getHours()), pad(d.getMinutes()), pad(d.getSeconds()) ].join(":");
|
877 | return [ d.getDate(), months[d.getMonth()], time ].join(" ");
|
878 | }
|
879 | function hasOwnProperty(obj, prop) {
|
880 | return Object.prototype.hasOwnProperty.call(obj, prop);
|
881 | }
|
882 |
|
883 |
|
884 |
|
885 |
|
886 |
|
887 |
|
888 |
|
889 |
|
890 |
|
891 |
|
892 |
|
893 |
|
894 |
|
895 |
|
896 |
|
897 |
|
898 |
|
899 |
|
900 |
|
901 |
|
902 | var formatRegExp = /%[sdj%]/g;
|
903 | exports.format = function(f) {
|
904 | if (!isString(f)) {
|
905 | for (var objects = [], i = 0; i < arguments.length; i++) objects.push(inspect(arguments[i]));
|
906 | return objects.join(" ");
|
907 | }
|
908 | for (var i = 1, args = arguments, len = args.length, str = String(f).replace(formatRegExp, function(x) {
|
909 | if ("%%" === x) return "%";
|
910 | if (i >= len) return x;
|
911 | switch (x) {
|
912 | case "%s":
|
913 | return String(args[i++]);
|
914 |
|
915 | case "%d":
|
916 | return Number(args[i++]);
|
917 |
|
918 | case "%j":
|
919 | try {
|
920 | return JSON.stringify(args[i++]);
|
921 | } catch (_) {
|
922 | return "[Circular]";
|
923 | }
|
924 |
|
925 | default:
|
926 | return x;
|
927 | }
|
928 | }), x = args[i]; i < len; x = args[++i]) str += isNull(x) || !isObject(x) ? " " + x : " " + inspect(x);
|
929 | return str;
|
930 | };
|
931 | exports.deprecate = function(fn, msg) {
|
932 | function deprecated() {
|
933 | if (!warned) {
|
934 | if (process.throwDeprecation) throw new Error(msg);
|
935 | process.traceDeprecation ? console.trace(msg) : console.error(msg);
|
936 | warned = !0;
|
937 | }
|
938 | return fn.apply(this, arguments);
|
939 | }
|
940 | if (isUndefined(global.process)) return function() {
|
941 | return exports.deprecate(fn, msg).apply(this, arguments);
|
942 | };
|
943 | if (process.noDeprecation === !0) return fn;
|
944 | var warned = !1;
|
945 | return deprecated;
|
946 | };
|
947 | var debugEnviron, debugs = {};
|
948 | exports.debuglog = function(set) {
|
949 | isUndefined(debugEnviron) && (debugEnviron = process.env.NODE_DEBUG || "");
|
950 | set = set.toUpperCase();
|
951 | if (!debugs[set]) if (new RegExp("\\b" + set + "\\b", "i").test(debugEnviron)) {
|
952 | var pid = process.pid;
|
953 | debugs[set] = function() {
|
954 | var msg = exports.format.apply(exports, arguments);
|
955 | console.error("%s %d: %s", set, pid, msg);
|
956 | };
|
957 | } else debugs[set] = function() {};
|
958 | return debugs[set];
|
959 | };
|
960 | exports.inspect = inspect;
|
961 | inspect.colors = {
|
962 | bold: [ 1, 22 ],
|
963 | italic: [ 3, 23 ],
|
964 | underline: [ 4, 24 ],
|
965 | inverse: [ 7, 27 ],
|
966 | white: [ 37, 39 ],
|
967 | grey: [ 90, 39 ],
|
968 | black: [ 30, 39 ],
|
969 | blue: [ 34, 39 ],
|
970 | cyan: [ 36, 39 ],
|
971 | green: [ 32, 39 ],
|
972 | magenta: [ 35, 39 ],
|
973 | red: [ 31, 39 ],
|
974 | yellow: [ 33, 39 ]
|
975 | };
|
976 | inspect.styles = {
|
977 | special: "cyan",
|
978 | number: "yellow",
|
979 | boolean: "yellow",
|
980 | undefined: "grey",
|
981 | null: "bold",
|
982 | string: "green",
|
983 | date: "magenta",
|
984 | regexp: "red"
|
985 | };
|
986 | exports.isArray = isArray;
|
987 | exports.isBoolean = isBoolean;
|
988 | exports.isNull = isNull;
|
989 | exports.isNullOrUndefined = isNullOrUndefined;
|
990 | exports.isNumber = isNumber;
|
991 | exports.isString = isString;
|
992 | exports.isSymbol = isSymbol;
|
993 | exports.isUndefined = isUndefined;
|
994 | exports.isRegExp = isRegExp;
|
995 | exports.isObject = isObject;
|
996 | exports.isDate = isDate;
|
997 | exports.isError = isError;
|
998 | exports.isFunction = isFunction;
|
999 | exports.isPrimitive = isPrimitive;
|
1000 | exports.isBuffer = require("./support/isBuffer");
|
1001 | var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
|
1002 | exports.log = function() {
|
1003 | console.log("%s - %s", timestamp(), exports.format.apply(exports, arguments));
|
1004 | };
|
1005 | exports.inherits = require("inherits");
|
1006 | exports._extend = function(origin, add) {
|
1007 | if (!add || !isObject(add)) return origin;
|
1008 | for (var keys = Object.keys(add), i = keys.length; i--; ) origin[keys[i]] = add[keys[i]];
|
1009 | return origin;
|
1010 | };
|
1011 | }).call(this, require("_process"), "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
|
1012 | }, {
|
1013 | "./support/isBuffer": 7,
|
1014 | _process: 5,
|
1015 | inherits: 6
|
1016 | } ]
|
1017 | }, {}, [ 2 ])(2);
|
1018 | }); |
\ | No newline at end of file |