inferred-types 0.30.3 → 0.32.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.
- package/dist/index.d.ts +38 -1
- package/dist/index.js +12 -1
- package/dist/index.mjs +10 -1
- package/package.json +1 -1
- package/src/types/dictionary/MapTo.ts +12 -0
- package/src/utility/dictionary/mapTo.ts +1 -0
- package/src/utility/runtime/conditions/isNumber.ts +17 -0
- package/src/utility/runtime/conditions/isString.ts +15 -0
- package/tests/runtime/if-is.spec.ts +17 -0
package/dist/index.d.ts
CHANGED
|
@@ -615,7 +615,20 @@ declare function isFunction<T extends unknown>(input: T): IsFunction<T>;
|
|
|
615
615
|
|
|
616
616
|
declare function isNull<T>(i: T): T extends null ? true : false;
|
|
617
617
|
|
|
618
|
+
declare type IsNumber<T> = T extends number ? true : false;
|
|
618
619
|
declare function isNumber<T>(i: T): T extends number ? true : false;
|
|
620
|
+
/**
|
|
621
|
+
* **ifNumber**
|
|
622
|
+
*
|
|
623
|
+
* Strongly type-aware conditional statement which checks whether a value is
|
|
624
|
+
* a _number_ and returns one of two values (strongly typed) based on the evaluation
|
|
625
|
+
* of this criteria.
|
|
626
|
+
*
|
|
627
|
+
* @param val the value being tested
|
|
628
|
+
* @param ifVal the value (strongly typed) returned if val is number
|
|
629
|
+
* @param elseVal the value (strongly typed) returned if val is NOT a number
|
|
630
|
+
*/
|
|
631
|
+
declare function ifNumber<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsNumber<T> extends true ? IF : ELSE;
|
|
619
632
|
|
|
620
633
|
declare type ObjectType = Not<Record<string, Narrowable>, FunctionType>;
|
|
621
634
|
/**
|
|
@@ -628,6 +641,18 @@ declare function isObject<T extends unknown>(i: T): IsObject<T>;
|
|
|
628
641
|
|
|
629
642
|
declare type IsString<T> = T extends string ? true : false;
|
|
630
643
|
declare function isString<T>(i: T): IsString<T>;
|
|
644
|
+
/**
|
|
645
|
+
* **ifString**
|
|
646
|
+
*
|
|
647
|
+
* Strongly type-aware conditional statement which checks whether a value is
|
|
648
|
+
* a _string_ and returns one of two values (strongly typed) based on the evaluation
|
|
649
|
+
* of this criteria.
|
|
650
|
+
*
|
|
651
|
+
* @param val the value being tested
|
|
652
|
+
* @param ifVal the value (strongly typed) returned if val is _string_
|
|
653
|
+
* @param elseVal the value (strongly typed) returned if val is NOT a _string
|
|
654
|
+
*/
|
|
655
|
+
declare function ifString<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE): IsString<T> extends true ? IF : ELSE;
|
|
631
656
|
|
|
632
657
|
declare function isSymbol<T>(i: T): T extends symbol ? true : false;
|
|
633
658
|
|
|
@@ -980,6 +1005,11 @@ declare type MapFn<I, O, C extends FinalizedMapConfig<OptRequired, MapCardinalit
|
|
|
980
1005
|
* const mapped = m(inputs);
|
|
981
1006
|
* const mappedOver = inputs.map(m);
|
|
982
1007
|
* ```
|
|
1008
|
+
*
|
|
1009
|
+
* Note: the root of a `Mapper` is the mapper function but
|
|
1010
|
+
* this is combined with a dictionary of settings and types
|
|
1011
|
+
* which you can use. For instance, look at the `fnSignature`
|
|
1012
|
+
* property to get the _type_ signature of the map function.
|
|
983
1013
|
*/
|
|
984
1014
|
declare type Mapper<I = unknown, O = unknown, C extends FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired> = FinalizedMapConfig<OptRequired, MapCardinalityIllustrated, OptRequired>> = {
|
|
985
1015
|
input: MapIR<C>;
|
|
@@ -988,6 +1018,13 @@ declare type Mapper<I = unknown, O = unknown, C extends FinalizedMapConfig<OptRe
|
|
|
988
1018
|
debug: boolean | string;
|
|
989
1019
|
inputType: I;
|
|
990
1020
|
outputType: O;
|
|
1021
|
+
/**
|
|
1022
|
+
* Provides the _type_ information for mapper function.
|
|
1023
|
+
*
|
|
1024
|
+
* Note: _this is just a **type**_ not the actual function which positioned
|
|
1025
|
+
* at the root of the Mapper type
|
|
1026
|
+
*/
|
|
1027
|
+
fnSignature: MapFn<I, O, C>;
|
|
991
1028
|
} & MapFn<I, O, C>;
|
|
992
1029
|
/**
|
|
993
1030
|
* **MapInputFrom**
|
|
@@ -2297,4 +2334,4 @@ interface IFluentConfigurator<C> {
|
|
|
2297
2334
|
*/
|
|
2298
2335
|
declare function FluentConfigurator<I>(initial?: I): IFluentConfigurator<{}>;
|
|
2299
2336
|
|
|
2300
|
-
export { AllCaps, Alpha, AlphaNumeric, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DynamicRule, DynamicRuleSet, Email, EnumValues, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, ExtendsClause, ExtendsNarrowlyClause, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FluentConfigurator, FluentFunction, FromDictArray, FunctionType, GeneralDictionary, Get, HasUppercase, IConfigurator, IFluentConfigurator, If, IfBooleanLiteral, IfExtends, IfExtendsThen, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfScalar, IfStringLiteral, Include, Includes, IntersectingKeys, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsFalse, IsFunction, IsLiteral, IsNumericLiteral, IsObject, IsOptionalLiteral, IsScalar, IsString, IsStringLiteral, IsTrue, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Model, Mutable, MutableProps, MutationFunction, MutationIdentity, Narrowable, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimplifyObject, SnakeCase, SpecialCharacters, StringDelimiter, StringFilter, StringKeys, StringLength, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeCondition, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, ValueTuple, ValueTypeFunc, ValueTypes, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, condition, createFnWithProps, createMutationFunction, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifTypeOf, isArray, isBoolean, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, randomString, readonlyFnWithProps, ruleSet, strArrayToDict, type, typeApi, uuid, valueTypes, withValue };
|
|
2337
|
+
export { AllCaps, Alpha, AlphaNumeric, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DynamicRule, DynamicRuleSet, Email, EnumValues, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, ExtendsClause, ExtendsNarrowlyClause, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FluentConfigurator, FluentFunction, FromDictArray, FunctionType, GeneralDictionary, Get, HasUppercase, IConfigurator, IFluentConfigurator, If, IfBooleanLiteral, IfExtends, IfExtendsThen, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfScalar, IfStringLiteral, Include, Includes, IntersectingKeys, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsFalse, IsFunction, IsLiteral, IsNumber, IsNumericLiteral, IsObject, IsOptionalLiteral, IsScalar, IsString, IsStringLiteral, IsTrue, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Model, Mutable, MutableProps, MutationFunction, MutationIdentity, Narrowable, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimplifyObject, SnakeCase, SpecialCharacters, StringDelimiter, StringFilter, StringKeys, StringLength, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeCondition, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, ValueTuple, ValueTypeFunc, ValueTypes, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, condition, createFnWithProps, createMutationFunction, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifNumber, ifString, ifTypeOf, isArray, isBoolean, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, randomString, readonlyFnWithProps, ruleSet, strArrayToDict, type, typeApi, uuid, valueTypes, withValue };
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,8 @@ __export(src_exports, {
|
|
|
50
50
|
idLiteral: () => idLiteral,
|
|
51
51
|
idTypeGuard: () => idTypeGuard,
|
|
52
52
|
identity: () => identity,
|
|
53
|
+
ifNumber: () => ifNumber,
|
|
54
|
+
ifString: () => ifString,
|
|
53
55
|
ifTypeOf: () => ifTypeOf,
|
|
54
56
|
isArray: () => isArray,
|
|
55
57
|
isBoolean: () => isBoolean,
|
|
@@ -297,6 +299,9 @@ function isNull(i) {
|
|
|
297
299
|
function isNumber(i) {
|
|
298
300
|
return typeof i === "number";
|
|
299
301
|
}
|
|
302
|
+
function ifNumber(val, ifVal, elseVal) {
|
|
303
|
+
return isNumber(val) ? ifVal : elseVal;
|
|
304
|
+
}
|
|
300
305
|
|
|
301
306
|
// src/utility/runtime/conditions/isObject.ts
|
|
302
307
|
function isObject(i) {
|
|
@@ -307,6 +312,9 @@ function isObject(i) {
|
|
|
307
312
|
function isString(i) {
|
|
308
313
|
return typeof i === "string";
|
|
309
314
|
}
|
|
315
|
+
function ifString(val, ifVal, elseVal) {
|
|
316
|
+
return isString(val) ? ifVal : elseVal;
|
|
317
|
+
}
|
|
310
318
|
|
|
311
319
|
// src/utility/runtime/conditions/isSymbol.ts
|
|
312
320
|
function isSymbol(i) {
|
|
@@ -645,7 +653,8 @@ var mapper = (config) => (map) => {
|
|
|
645
653
|
cardinality: config.cardinality,
|
|
646
654
|
debug: config.debug,
|
|
647
655
|
inputType: {},
|
|
648
|
-
outputType: {}
|
|
656
|
+
outputType: {},
|
|
657
|
+
fnSignature: null
|
|
649
658
|
});
|
|
650
659
|
};
|
|
651
660
|
var setMapper = (config = { input: void 0, output: void 0, cardinality: void 0 }, defaultValue) => ({
|
|
@@ -877,6 +886,8 @@ function Model(name) {
|
|
|
877
886
|
idLiteral,
|
|
878
887
|
idTypeGuard,
|
|
879
888
|
identity,
|
|
889
|
+
ifNumber,
|
|
890
|
+
ifString,
|
|
880
891
|
ifTypeOf,
|
|
881
892
|
isArray,
|
|
882
893
|
isBoolean,
|
package/dist/index.mjs
CHANGED
|
@@ -206,6 +206,9 @@ function isNull(i) {
|
|
|
206
206
|
function isNumber(i) {
|
|
207
207
|
return typeof i === "number";
|
|
208
208
|
}
|
|
209
|
+
function ifNumber(val, ifVal, elseVal) {
|
|
210
|
+
return isNumber(val) ? ifVal : elseVal;
|
|
211
|
+
}
|
|
209
212
|
|
|
210
213
|
// src/utility/runtime/conditions/isObject.ts
|
|
211
214
|
function isObject(i) {
|
|
@@ -216,6 +219,9 @@ function isObject(i) {
|
|
|
216
219
|
function isString(i) {
|
|
217
220
|
return typeof i === "string";
|
|
218
221
|
}
|
|
222
|
+
function ifString(val, ifVal, elseVal) {
|
|
223
|
+
return isString(val) ? ifVal : elseVal;
|
|
224
|
+
}
|
|
219
225
|
|
|
220
226
|
// src/utility/runtime/conditions/isSymbol.ts
|
|
221
227
|
function isSymbol(i) {
|
|
@@ -554,7 +560,8 @@ var mapper = (config) => (map) => {
|
|
|
554
560
|
cardinality: config.cardinality,
|
|
555
561
|
debug: config.debug,
|
|
556
562
|
inputType: {},
|
|
557
|
-
outputType: {}
|
|
563
|
+
outputType: {},
|
|
564
|
+
fnSignature: null
|
|
558
565
|
});
|
|
559
566
|
};
|
|
560
567
|
var setMapper = (config = { input: void 0, output: void 0, cardinality: void 0 }, defaultValue) => ({
|
|
@@ -785,6 +792,8 @@ export {
|
|
|
785
792
|
idLiteral,
|
|
786
793
|
idTypeGuard,
|
|
787
794
|
identity,
|
|
795
|
+
ifNumber,
|
|
796
|
+
ifString,
|
|
788
797
|
ifTypeOf,
|
|
789
798
|
isArray,
|
|
790
799
|
isBoolean,
|
package/package.json
CHANGED
|
@@ -372,6 +372,11 @@ export type MapFn<
|
|
|
372
372
|
* const mapped = m(inputs);
|
|
373
373
|
* const mappedOver = inputs.map(m);
|
|
374
374
|
* ```
|
|
375
|
+
*
|
|
376
|
+
* Note: the root of a `Mapper` is the mapper function but
|
|
377
|
+
* this is combined with a dictionary of settings and types
|
|
378
|
+
* which you can use. For instance, look at the `fnSignature`
|
|
379
|
+
* property to get the _type_ signature of the map function.
|
|
375
380
|
*/
|
|
376
381
|
export type Mapper<
|
|
377
382
|
I = unknown,
|
|
@@ -388,6 +393,13 @@ export type Mapper<
|
|
|
388
393
|
debug: boolean | string;
|
|
389
394
|
inputType: I;
|
|
390
395
|
outputType: O;
|
|
396
|
+
/**
|
|
397
|
+
* Provides the _type_ information for mapper function.
|
|
398
|
+
*
|
|
399
|
+
* Note: _this is just a **type**_ not the actual function which positioned
|
|
400
|
+
* at the root of the Mapper type
|
|
401
|
+
*/
|
|
402
|
+
fnSignature: MapFn<I, O, C>;
|
|
391
403
|
} & MapFn<I, O, C>;
|
|
392
404
|
|
|
393
405
|
/**
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
export type IsNumber<T> = T extends number ? true : false;
|
|
2
|
+
|
|
1
3
|
export function isNumber<T>(i: T) {
|
|
2
4
|
return (typeof i === "number") as T extends number ? true : false;
|
|
3
5
|
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* **ifNumber**
|
|
9
|
+
*
|
|
10
|
+
* Strongly type-aware conditional statement which checks whether a value is
|
|
11
|
+
* a _number_ and returns one of two values (strongly typed) based on the evaluation
|
|
12
|
+
* of this criteria.
|
|
13
|
+
*
|
|
14
|
+
* @param val the value being tested
|
|
15
|
+
* @param ifVal the value (strongly typed) returned if val is number
|
|
16
|
+
* @param elseVal the value (strongly typed) returned if val is NOT a number
|
|
17
|
+
*/
|
|
18
|
+
export function ifNumber<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE) {
|
|
19
|
+
return (isNumber(val) ? ifVal : elseVal) as IsNumber<T> extends true ? IF : ELSE;
|
|
20
|
+
}
|
|
@@ -3,3 +3,18 @@ export type IsString<T> = T extends string ? true : false;
|
|
|
3
3
|
export function isString<T>(i: T) {
|
|
4
4
|
return (typeof i === "string") as IsString<T>;
|
|
5
5
|
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* **ifString**
|
|
9
|
+
*
|
|
10
|
+
* Strongly type-aware conditional statement which checks whether a value is
|
|
11
|
+
* a _string_ and returns one of two values (strongly typed) based on the evaluation
|
|
12
|
+
* of this criteria.
|
|
13
|
+
*
|
|
14
|
+
* @param val the value being tested
|
|
15
|
+
* @param ifVal the value (strongly typed) returned if val is _string_
|
|
16
|
+
* @param elseVal the value (strongly typed) returned if val is NOT a _string
|
|
17
|
+
*/
|
|
18
|
+
export function ifString<T, IF, ELSE>(val: T, ifVal: IF, elseVal: ELSE) {
|
|
19
|
+
return (isString(val) ? ifVal : elseVal) as IsString<T> extends true ? IF : ELSE;
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import type { Expect, Equal } from "@type-challenges/utils";
|
|
4
|
+
import { ifString } from "src/utility";
|
|
5
|
+
|
|
6
|
+
describe("runtime if/is", () => {
|
|
7
|
+
it("ifString(v,i,e)", () => {
|
|
8
|
+
const t = ifString("foo", 42, false);
|
|
9
|
+
const f = ifString(-1, "yikes", 42);
|
|
10
|
+
|
|
11
|
+
type cases = [
|
|
12
|
+
Expect<Equal<typeof t, 42>>, //
|
|
13
|
+
Expect<Equal<typeof f, 42>> //
|
|
14
|
+
];
|
|
15
|
+
const cases: cases = [true, true];
|
|
16
|
+
});
|
|
17
|
+
});
|