@thryveai/theme-interfaces 2.4.10 → 2.4.12
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 +4 -2
- package/dist/index.js +3 -1
- package/dist/interfaces/retailer-settings.interfaces.d.ts +10 -2
- package/dist/scripts/input.d.ts +4 -0
- package/dist/scripts/input.js +659 -0
- package/dist/scripts/sfui-settings-migrator.d.ts +6 -0
- package/dist/scripts/sfui-settings-migrator.js +205 -0
- package/dist/storefront/SFUISettingsTemplate.AdminUi.d.ts +12 -1
- package/dist/storefront/SFUISettingsTemplate.AdminUi.js +32 -1
- package/dist/storefront/contentEngineComponents.d.ts +23 -0
- package/dist/storefront/contentEngineComponents.js +25 -0
- package/dist/storefront/defaultSettingsStorefront.js +190 -164
- package/package.json +21 -21
- package/dist/defaultSettings.d.ts +0 -3
- package/dist/defaultSettings.js +0 -242
- package/dist/storefrontUiSettingsTemplateForAdminPanel.d.ts +0 -3
- package/dist/storefrontUiSettingsTemplateForAdminPanel.js +0 -686
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (_) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.migrator = void 0;
|
|
51
|
+
var input_1 = require("./input");
|
|
52
|
+
var fs_1 = require("fs");
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
var migrator = function (AllBannerSettings, storeFile) {
|
|
55
|
+
if (storeFile === void 0) { storeFile = false; }
|
|
56
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
57
|
+
var NewAllBannerSettings_1, JSON_SETTINGS, location_1, e_1;
|
|
58
|
+
return __generator(this, function (_a) {
|
|
59
|
+
switch (_a.label) {
|
|
60
|
+
case 0:
|
|
61
|
+
_a.trys.push([0, 3, , 4]);
|
|
62
|
+
NewAllBannerSettings_1 = {};
|
|
63
|
+
Object.keys(AllBannerSettings).forEach(function (bannerName) {
|
|
64
|
+
NewAllBannerSettings_1[bannerName] = settingsMapper(AllBannerSettings[bannerName]);
|
|
65
|
+
});
|
|
66
|
+
JSON_SETTINGS = JSON.stringify(NewAllBannerSettings_1);
|
|
67
|
+
if (!storeFile) return [3 /*break*/, 2];
|
|
68
|
+
location_1 = "./scripts/newSettings.json";
|
|
69
|
+
return [4 /*yield*/, fs_1.promises.writeFile(location_1, JSON_SETTINGS)];
|
|
70
|
+
case 1:
|
|
71
|
+
_a.sent();
|
|
72
|
+
console.log("Successfully merged settings to ".concat(location_1));
|
|
73
|
+
return [2 /*return*/];
|
|
74
|
+
case 2: return [2 /*return*/, JSON_SETTINGS];
|
|
75
|
+
case 3:
|
|
76
|
+
e_1 = _a.sent();
|
|
77
|
+
console.error("Error mapping settings", e_1);
|
|
78
|
+
return [2 /*return*/, "An Error Occurred"];
|
|
79
|
+
case 4: return [2 /*return*/];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
exports.migrator = migrator;
|
|
85
|
+
var settingsMapper = function (oldSettings) {
|
|
86
|
+
return __assign(__assign({}, oldSettings), { adminPanelOnly: {
|
|
87
|
+
bannerName: oldSettings.adminPanelOnly.bannerName,
|
|
88
|
+
logoUrl: oldSettings.adminPanelOnly.logoUrl,
|
|
89
|
+
}, siteSettings: {
|
|
90
|
+
defaultCountry: oldSettings.defaultCountry,
|
|
91
|
+
defaultShoppingMode: oldSettings.defaultShoppingMode,
|
|
92
|
+
anonymousCart: oldSettings.siteSettings.anonymousCart,
|
|
93
|
+
daysToRemainSignedIn: oldSettings.daysToRemainSignedIn,
|
|
94
|
+
defaultSearchParams: oldSettings.defaultSearchParams,
|
|
95
|
+
defaultStoreLocation: oldSettings.defaultStoreLocation,
|
|
96
|
+
googleAutocompleteSettings: oldSettings.googleAutocompleteSettings,
|
|
97
|
+
restrictMapPlacesResults: oldSettings.restrictMapPlacesResults,
|
|
98
|
+
gtmId: !!oldSettings.gtmId ? oldSettings.gtmId : "",
|
|
99
|
+
isPlanningOnly: oldSettings.isPlanningOnly,
|
|
100
|
+
mapZoom: oldSettings.mapZoom,
|
|
101
|
+
promoTemplateVersion: oldSettings.promoTemplateVersion,
|
|
102
|
+
retailerCountry: oldSettings.retailerCountry,
|
|
103
|
+
retailerName: oldSettings.retailerName,
|
|
104
|
+
searchPreview: oldSettings.searchPreview,
|
|
105
|
+
subHeaderHeight: oldSettings.subHeaderHeight,
|
|
106
|
+
disableTprPrice: oldSettings.disableTprPrice,
|
|
107
|
+
footerVersion: oldSettings.layout.footerVersion,
|
|
108
|
+
timeslotModalSettings: oldSettings.timeslotModalSettings,
|
|
109
|
+
ctaButtons: oldSettings.ctaButtons,
|
|
110
|
+
mainHeaderHeight: oldSettings.mainHeaderHeight,
|
|
111
|
+
}, features: {
|
|
112
|
+
additionalCharges: !!oldSettings.features.additionalCharges,
|
|
113
|
+
clientCache: !!oldSettings.features.clientCache,
|
|
114
|
+
vouchers: oldSettings.features.vouchers,
|
|
115
|
+
giftCards: oldSettings.features.giftCards,
|
|
116
|
+
smartbanner: oldSettings.features.smartbanner,
|
|
117
|
+
entryModalVersion: oldSettings.features.entryModalVersion,
|
|
118
|
+
allowInStorePurchases: !!oldSettings.allowInStorePurchases,
|
|
119
|
+
allowPastPurchases: !!oldSettings.allowPastPurchases,
|
|
120
|
+
advertSettings: oldSettings.advertSettings,
|
|
121
|
+
enableGoogleTranslate: !!oldSettings.enableGoogleTranslate,
|
|
122
|
+
enableNewsletterSignup: !!oldSettings.enableNewsletterSignup,
|
|
123
|
+
enableNotifications: !!oldSettings.enableNotifications,
|
|
124
|
+
externalStoreSelectorUrl: {
|
|
125
|
+
enabled: !!oldSettings.externalStoreSelectorUrl,
|
|
126
|
+
url: !!oldSettings.externalStoreSelectorUrl
|
|
127
|
+
? oldSettings.externalStoreSelectorUrl
|
|
128
|
+
: "",
|
|
129
|
+
},
|
|
130
|
+
favoritesV1: !!oldSettings.favoritesV1,
|
|
131
|
+
flipp: oldSettings.flipp,
|
|
132
|
+
globalAnimations: oldSettings.globalAnimations,
|
|
133
|
+
instacart: {
|
|
134
|
+
enabled: !!oldSettings.instacartUrl,
|
|
135
|
+
url: !!oldSettings.instacartUrl ? oldSettings.instacartUrl : "",
|
|
136
|
+
},
|
|
137
|
+
registrationFields: oldSettings.registrationFields,
|
|
138
|
+
secondTierAuthorization: oldSettings.secondTierAuthorization,
|
|
139
|
+
showCheckoutPromoCode: !!oldSettings.showCheckoutPromoCode,
|
|
140
|
+
showImgOnOrder: !!oldSettings.showImgOnOrder,
|
|
141
|
+
smsNotifications: oldSettings.smsNotifications,
|
|
142
|
+
specialRequestItems: !!oldSettings.specialRequestItems,
|
|
143
|
+
couponGallery: oldSettings.layouts.couponGallery,
|
|
144
|
+
}, addressSettings: {
|
|
145
|
+
// todo need to be fixed
|
|
146
|
+
addressValidationTypes: {
|
|
147
|
+
addressLine1: oldSettings.addressValidationTypes.addressLine1,
|
|
148
|
+
addressLine2: oldSettings.addressValidationTypes.addressLine2,
|
|
149
|
+
city: oldSettings.addressValidationTypes.city,
|
|
150
|
+
countyProvinceState: oldSettings.addressValidationTypes.countyProvinceState,
|
|
151
|
+
familyName: oldSettings.addressValidationTypes.familyName,
|
|
152
|
+
firstName: oldSettings.addressValidationTypes.firstName,
|
|
153
|
+
instructions: oldSettings.addressValidationTypes.instructions,
|
|
154
|
+
phoneNumber: oldSettings.addressValidationTypes.phoneNumber,
|
|
155
|
+
postCode: oldSettings.addressValidationTypes.postCode,
|
|
156
|
+
smsNumber: oldSettings.checkoutValidation.smsNumber,
|
|
157
|
+
},
|
|
158
|
+
eircode: {
|
|
159
|
+
enabled: !!oldSettings.eircode,
|
|
160
|
+
url: !!oldSettings.eircode ? oldSettings.eircode : "",
|
|
161
|
+
},
|
|
162
|
+
integration: {
|
|
163
|
+
addressFinderType: oldSettings.addressIntegration.addressFinderType,
|
|
164
|
+
enabled: oldSettings.addressIntegration.enabled,
|
|
165
|
+
useForNewAddresses: oldSettings.addressIntegration.useForNewAddresses,
|
|
166
|
+
addNewAddressUrl: oldSettings.addresses.integration.addNewAddressUrl,
|
|
167
|
+
editAddressUrl: oldSettings.addresses.integration.editAddressUrl,
|
|
168
|
+
deleteAddressUrl: oldSettings.addresses.integration.deleteAddressUrl,
|
|
169
|
+
},
|
|
170
|
+
useAddressValidation: oldSettings.useAddressValidation,
|
|
171
|
+
disableAddressOnDelivery: false,
|
|
172
|
+
}, accountPage: {
|
|
173
|
+
loyaltyTab: {
|
|
174
|
+
disabledEdit: !!oldSettings.accountPage.loyaltyTab.disabledEdit,
|
|
175
|
+
enabled: !!oldSettings.accountPage.loyaltyTab.enabled,
|
|
176
|
+
loyaltyNumberLength: oldSettings.accountPage.loyaltyTab.loyaltyNumberLength,
|
|
177
|
+
loyaltyNumberPrefix: oldSettings.accountPage.loyaltyTab.loyaltyNumberPrefix,
|
|
178
|
+
loyaltyValidationType: oldSettings.accountPage.loyaltyTab.loyaltyValidationType,
|
|
179
|
+
},
|
|
180
|
+
idp: {
|
|
181
|
+
enabled: !!oldSettings.idpUrl,
|
|
182
|
+
target: oldSettings.idpTarget,
|
|
183
|
+
url: !!oldSettings.idpUrl ? oldSettings.idpUrl : "",
|
|
184
|
+
},
|
|
185
|
+
}, productCard: {
|
|
186
|
+
limitProductCardTitleHeight: oldSettings.limitProductCardTitleHeight,
|
|
187
|
+
productCardTitleHeight: oldSettings.productCardTitleHeight,
|
|
188
|
+
productCards: oldSettings.productCards,
|
|
189
|
+
}, checkout: {
|
|
190
|
+
numericPhonePayload: oldSettings.checkout.numericPhonePayload,
|
|
191
|
+
houseAccountRegExValidation: oldSettings.houseAccountRegExValidation,
|
|
192
|
+
minimumCreditCardAmount: oldSettings.minimumCreditCardAmount,
|
|
193
|
+
paymentCards: oldSettings.paymentCards,
|
|
194
|
+
checkoutValidation: oldSettings.checkoutValidation,
|
|
195
|
+
}, pdpSettings: {
|
|
196
|
+
nutritionZone: oldSettings.nutritionZone,
|
|
197
|
+
pdpDetailsLayout: oldSettings.pdpDetailsLayout,
|
|
198
|
+
sodiumWarning: oldSettings.sodiumWarning,
|
|
199
|
+
}, cartSummary: {
|
|
200
|
+
hideTaxOnSummary: !!oldSettings.hideTaxOnSummary,
|
|
201
|
+
showTaxTotal: !!oldSettings.layouts.cartSummary.showTaxTotal,
|
|
202
|
+
showTaxGroups: !!oldSettings.layouts.cartSummary.showTaxGroups,
|
|
203
|
+
} });
|
|
204
|
+
};
|
|
205
|
+
(0, exports.migrator)(input_1.default, true);
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
import { IAdminSettingsTemplate, IAdminTemplateInputTypes } from "../interfaces/admin-settings-interfaces";
|
|
1
|
+
import { IAdminControlType, IAdminSettingsTemplate, IAdminTemplateInputTypes } from "../interfaces/admin-settings-interfaces";
|
|
2
|
+
import { CMSNames } from "./contentEngineComponents";
|
|
2
3
|
export declare const AdminTemplateInputTypes: IAdminTemplateInputTypes;
|
|
4
|
+
export declare type IUseContentEngineV2ComponentsAdmin = {
|
|
5
|
+
[key in CMSNames]: IContentEngineAdminTypes;
|
|
6
|
+
};
|
|
7
|
+
interface IContentEngineAdminTypes {
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
helpLink: string;
|
|
11
|
+
type: IAdminControlType;
|
|
12
|
+
}
|
|
3
13
|
export declare const AdminSettingsTemplateSFUI: IAdminSettingsTemplate;
|
|
14
|
+
export {};
|
|
@@ -235,6 +235,16 @@ var FeatureSettingsChildren = {
|
|
|
235
235
|
type: exports.AdminTemplateInputTypes.dropdown,
|
|
236
236
|
options: [100, 95, 90, 85, 80, 75, 70, 65, 60],
|
|
237
237
|
},
|
|
238
|
+
locale: {
|
|
239
|
+
title: "Locale",
|
|
240
|
+
description: "The locale of flipp flyers",
|
|
241
|
+
type: exports.AdminTemplateInputTypes.inputChar,
|
|
242
|
+
},
|
|
243
|
+
hideHeader: {
|
|
244
|
+
title: "hideHeader",
|
|
245
|
+
description: "Setting to toggle visibility of the flipp navigation header",
|
|
246
|
+
type: exports.AdminTemplateInputTypes.checkbox,
|
|
247
|
+
},
|
|
238
248
|
},
|
|
239
249
|
},
|
|
240
250
|
smartbanner: {
|
|
@@ -306,6 +316,14 @@ var FeatureSettingsChildren = {
|
|
|
306
316
|
},
|
|
307
317
|
},
|
|
308
318
|
};
|
|
319
|
+
var ContentEngineV2Components = {
|
|
320
|
+
HeroBanner: {
|
|
321
|
+
description: "Use HeroBanner V2",
|
|
322
|
+
helpLink: "https://mi9retail.atlassian.net/wiki/spaces/FDS/pages/3478946114/Hero+Banner",
|
|
323
|
+
title: "Enable HeroBanner V2 component",
|
|
324
|
+
type: "checkbox",
|
|
325
|
+
},
|
|
326
|
+
};
|
|
309
327
|
var SiteSettingsChildren = {
|
|
310
328
|
anonymousCart: {
|
|
311
329
|
title: "Anonymous Cart",
|
|
@@ -367,6 +385,12 @@ var SiteSettingsChildren = {
|
|
|
367
385
|
description: "Google Tag Manager ID",
|
|
368
386
|
type: exports.AdminTemplateInputTypes.inputChar,
|
|
369
387
|
},
|
|
388
|
+
hideWelcomeModalOnCorporate: {
|
|
389
|
+
title: "Hide Welcome Modal on Corporate",
|
|
390
|
+
description: "Enable to hide the initial welcome modal selection screen when on corporate store",
|
|
391
|
+
helpLink: "https://mi9retail.atlassian.net/wiki/spaces/FDS/pages/3472326883/Hide+Welcome+Modal+on+Corporate",
|
|
392
|
+
type: exports.AdminTemplateInputTypes.checkbox,
|
|
393
|
+
},
|
|
370
394
|
isPlanningOnly: {
|
|
371
395
|
title: "Planning Only",
|
|
372
396
|
description: "Enable if planning mode is the only available shopping method",
|
|
@@ -396,7 +420,7 @@ var SiteSettingsChildren = {
|
|
|
396
420
|
description: "Enable Maintain customer preferences",
|
|
397
421
|
type: exports.AdminTemplateInputTypes.checkbox,
|
|
398
422
|
},
|
|
399
|
-
}
|
|
423
|
+
},
|
|
400
424
|
},
|
|
401
425
|
retailerCountry: {
|
|
402
426
|
title: "Retailer country",
|
|
@@ -433,6 +457,13 @@ var SiteSettingsChildren = {
|
|
|
433
457
|
},
|
|
434
458
|
},
|
|
435
459
|
},
|
|
460
|
+
useContentEngineV2Components: {
|
|
461
|
+
title: "Use Content Engine V2 Components",
|
|
462
|
+
description: "(work in progress)",
|
|
463
|
+
helpLink: "https://mi9retail.atlassian.net/wiki/spaces/FDS/pages/3478618892/Content+Engine+V2+Components",
|
|
464
|
+
type: exports.AdminTemplateInputTypes.object,
|
|
465
|
+
value: ContentEngineV2Components,
|
|
466
|
+
},
|
|
436
467
|
};
|
|
437
468
|
var AccountPageSettingsChildren = {
|
|
438
469
|
loyaltyTab: {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const CMSComponentNames: {
|
|
2
|
+
Carousel: string;
|
|
3
|
+
SmallCarousel: string;
|
|
4
|
+
Freeform: string;
|
|
5
|
+
ContactUs: string;
|
|
6
|
+
HeroBanner: string;
|
|
7
|
+
Image: string;
|
|
8
|
+
Video: string;
|
|
9
|
+
VideoWithContent: string;
|
|
10
|
+
ImageWithContent: string;
|
|
11
|
+
ImageTextButton: string;
|
|
12
|
+
SmallPromotion: string;
|
|
13
|
+
SmallImageWithContent: string;
|
|
14
|
+
LargePromotion: string;
|
|
15
|
+
TwoBannerContainer: string;
|
|
16
|
+
ThreeBannerContainer: string;
|
|
17
|
+
Sale: string;
|
|
18
|
+
SmallBannerWithBackgroundImage: string;
|
|
19
|
+
SmallBannerWithSupportingImage: string;
|
|
20
|
+
ProductCardStory: string;
|
|
21
|
+
Recipe: string;
|
|
22
|
+
};
|
|
23
|
+
export declare type CMSNames = keyof typeof CMSComponentNames;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CMSComponentNames = void 0;
|
|
4
|
+
exports.CMSComponentNames = {
|
|
5
|
+
Carousel: "Carousel",
|
|
6
|
+
SmallCarousel: "CarouselSmall",
|
|
7
|
+
Freeform: "Freeform",
|
|
8
|
+
ContactUs: "ContactUs",
|
|
9
|
+
HeroBanner: "HeroBanner",
|
|
10
|
+
Image: "Image",
|
|
11
|
+
Video: "Video",
|
|
12
|
+
VideoWithContent: "VideoWithContent",
|
|
13
|
+
ImageWithContent: "StandardContentBlock3",
|
|
14
|
+
ImageTextButton: "ImageTextButton",
|
|
15
|
+
SmallPromotion: "SmallPromotion",
|
|
16
|
+
SmallImageWithContent: "StackedContentBlock",
|
|
17
|
+
LargePromotion: "LargePromotion",
|
|
18
|
+
TwoBannerContainer: "TwoBannerContainer",
|
|
19
|
+
ThreeBannerContainer: "ThreeBannerContainer",
|
|
20
|
+
Sale: "Sale",
|
|
21
|
+
SmallBannerWithBackgroundImage: "StandardContentBlock1",
|
|
22
|
+
SmallBannerWithSupportingImage: "StandardContentBlock2",
|
|
23
|
+
ProductCardStory: "ProductCardStory",
|
|
24
|
+
Recipe: "Recipe",
|
|
25
|
+
};
|