upgrade @frontend/kitui

use cart calc functions from kitui
This commit is contained in:
nflnkr 2024-03-27 13:53:47 +03:00
parent a980fe5fe4
commit 3d7a518208
6 changed files with 55 additions and 369 deletions

@ -6,7 +6,7 @@
"@craco/craco": "^7.0.0",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@frontend/kitui": "^1.0.63",
"@frontend/kitui": "^1.0.74",
"@frontend/squzanswerer": "^1.0.6",
"@mui/icons-material": "^5.10.14",
"@mui/material": "^5.10.14",

@ -1,5 +1,5 @@
import { Privilege, PrivilegeWithAmount } from "@frontend/kitui";
import { Privilege } from "@frontend/kitui";
export type ServiceKeyToPrivilegesMap = Record<string, Privilege[]>;
export type PrivilegeWithoutPrice = Omit<PrivilegeWithAmount, "price">;
export type PrivilegeWithoutPrice = Omit<Privilege, "price">;

@ -1,249 +0,0 @@
import {
CartData,
Discount,
PrivilegeCartData,
Tariff,
TariffCartData,
findPrivilegeDiscount,
findDiscountFactor,
applyLoyaltyDiscount,
} from "@frontend/kitui";
function applyPrivilegeDiscounts(cartData: CartData, discounts: Discount[]) {
cartData.services.forEach((service) => {
const privMap = new Map();
service.tariffs.forEach((tariff) =>
tariff.privileges.forEach((p) => {
privMap.set(
p.privilegeId,
p.amount + (privMap.get(p.privilegeId) || 0),
);
}),
);
service.tariffs.forEach((tariff) => {
tariff.privileges.forEach((privilege) => {
const privilegeDiscount = findPrivilegeDiscount(
privilege.privilegeId,
privMap.get(privilege.privilegeId) || 0,
discounts,
);
if (!privilegeDiscount) return;
const discountAmount =
privilege.price * (1 - findDiscountFactor(privilegeDiscount));
privilege.price -= discountAmount;
cartData.allAppliedDiscounts.push(privilegeDiscount);
privilege.appliedPrivilegeDiscount = privilegeDiscount;
tariff.price -= discountAmount;
service.price -= discountAmount;
cartData.priceAfterDiscounts -= discountAmount;
});
});
});
}
function findServiceDiscount(
serviceKey: string,
currentPrice: number,
discounts: Discount[],
): Discount | null {
const applicableDiscounts = discounts.filter((discount) => {
return (
discount.Layer === 2 &&
discount.Condition.Group === serviceKey &&
currentPrice >= Number(discount.Condition.PriceFrom)
);
});
if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
return Number(current.Condition.PriceFrom) >
Number(prev.Condition.PriceFrom)
? current
: prev;
});
return maxValueDiscount;
}
function findCartDiscount(
cartPurchasesAmount: number,
discounts: Discount[],
): Discount | null {
const applicableDiscounts = discounts.filter((discount) => {
return (
discount.Layer === 3 &&
cartPurchasesAmount >= Number(discount.Condition.CartPurchasesAmount)
);
});
if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
return Number(current.Condition.CartPurchasesAmount) >
Number(prev.Condition.CartPurchasesAmount)
? current
: prev;
});
return maxValueDiscount;
}
function applyCartDiscount(cartData: CartData, discounts: Discount[]) {
const cartDiscount = findCartDiscount(
cartData.priceAfterDiscounts,
discounts,
);
if (!cartDiscount) return;
cartData.priceAfterDiscounts *= findDiscountFactor(cartDiscount);
cartData.allAppliedDiscounts.push(cartDiscount);
cartData.appliedCartPurchasesDiscount = cartDiscount;
}
function applyServiceDiscounts(cartData: CartData, discounts: Discount[]) {
const privMap = new Map();
cartData.services.forEach((service) => {
service.tariffs.forEach((tariff) =>
tariff.privileges.forEach((p) => {
privMap.set(p.serviceKey, p.price + (privMap.get(p.serviceKey) || 0));
}),
);
});
cartData.services.forEach((service) => {
service.tariffs.map((tariff) => {
tariff.privileges.forEach((privilege) => {
const privilegeDiscount = findServiceDiscount(
privilege.serviceKey,
privMap.get(privilege.serviceKey),
discounts,
);
if (!privilegeDiscount) return;
const discountAmount =
privilege.price * (1 - findDiscountFactor(privilegeDiscount));
privilege.price -= discountAmount;
cartData.allAppliedDiscounts.push(privilegeDiscount);
service.appliedServiceDiscount = privilegeDiscount;
tariff.price -= discountAmount;
service.price -= discountAmount;
cartData.priceAfterDiscounts -= discountAmount;
});
});
});
}
export function calcCart(
tariffs: Tariff[],
discounts: Discount[],
purchasesAmount: number,
isUserNko?: boolean,
): CartData {
const cartData: CartData = {
services: [],
priceBeforeDiscounts: 0,
priceAfterDiscounts: 0,
itemCount: 0,
appliedCartPurchasesDiscount: null,
appliedLoyaltyDiscount: null,
allAppliedDiscounts: [],
};
tariffs.forEach((tariff) => {
if (tariff.price !== undefined && tariff.privileges.length !== 1)
throw new Error("Price is defined for tariff with several");
let serviceData = cartData.services.find(
(service) => service.serviceKey === "custom" && tariff.isCustom,
);
if (!serviceData && !tariff.isCustom)
serviceData = cartData.services.find(
(service) => service.serviceKey === tariff.privileges[0].serviceKey,
);
if (!serviceData) {
serviceData = {
serviceKey: tariff.isCustom
? "custom"
: tariff.privileges[0].serviceKey,
tariffs: [],
price: 0,
appliedServiceDiscount: null,
};
cartData.services.push(serviceData);
}
const tariffCartData: TariffCartData = {
price: tariff.price ?? 0,
isCustom: tariff.isCustom,
privileges: [],
id: tariff._id,
name: tariff.name,
};
serviceData.tariffs.push(tariffCartData);
tariff.privileges.forEach((privilege) => {
let privilegePrice = privilege.amount * privilege.price;
if (!tariff.price) tariffCartData.price += privilegePrice;
else privilegePrice = tariff.price;
const privilegeCartData: PrivilegeCartData = {
serviceKey: privilege.serviceKey,
privilegeId: privilege.privilegeId,
description: privilege.description,
price: privilegePrice,
amount: privilege.amount,
appliedPrivilegeDiscount: null,
};
tariffCartData.privileges.push(privilegeCartData);
cartData.priceAfterDiscounts += privilegePrice;
cartData.itemCount++;
});
cartData.priceBeforeDiscounts += tariffCartData.price;
serviceData.price += tariffCartData.price;
});
const nkoDiscount = findNkoDiscount(discounts);
if (isUserNko && nkoDiscount) {
applyNkoDiscount(cartData, nkoDiscount);
} else {
applyPrivilegeDiscounts(cartData, discounts);
applyServiceDiscounts(cartData, discounts);
applyCartDiscount(cartData, discounts);
applyLoyaltyDiscount(cartData, discounts, purchasesAmount);
}
cartData.allAppliedDiscounts = Array.from(
new Set(cartData.allAppliedDiscounts),
);
return cartData;
}
function applyNkoDiscount(cartData: CartData, discount: Discount) {
cartData.priceAfterDiscounts *= discount.Target.Factor;
cartData.allAppliedDiscounts.push(discount);
}
export function findNkoDiscount(discounts: Discount[]): Discount | null {
const applicableDiscounts = discounts.filter(
(discount) => discount.Condition.UserType === "nko",
);
if (!applicableDiscounts.length) return null;
const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
return current.Condition.CartPurchasesAmount >
prev.Condition.CartPurchasesAmount
? current
: prev;
});
return maxValueDiscount;
}

@ -1,56 +0,0 @@
import { Discount, Tariff, findDiscountFactor } from "@frontend/kitui";
import { calcCart } from "./calcCart";
export function calcIndividualTariffPrices(
tariff: Tariff,
discounts: Discount[],
purchasesAmount: number,
currentTariffs: Tariff[],
isUserNko?: boolean,
): {
priceBeforeDiscounts: number;
priceAfterDiscounts: number;
} {
console.log("MAGIC", purchasesAmount);
const priceBeforeDiscounts =
tariff.price ||
tariff.privileges.reduce(
(sum, privilege) => sum + privilege.amount * privilege.price,
0,
);
let priceAfterDiscounts = 0;
const cart = calcCart(
[...currentTariffs, tariff],
discounts,
purchasesAmount,
isUserNko,
);
if (cart.allAppliedDiscounts[0]?.Target.Overhelm)
return {
priceBeforeDiscounts: priceBeforeDiscounts,
priceAfterDiscounts:
priceBeforeDiscounts * cart.allAppliedDiscounts[0].Target.Factor,
};
cart.services.forEach((s) => {
if (s.serviceKey === tariff.privileges[0].serviceKey) {
let processed = false;
s.tariffs.forEach((t) => {
if (t.id === tariff._id && !processed) {
processed = true;
t.privileges.forEach((p) => (priceAfterDiscounts += p.price));
}
});
priceAfterDiscounts *= findDiscountFactor(s.appliedServiceDiscount);
}
});
priceAfterDiscounts *= findDiscountFactor(cart.appliedLoyaltyDiscount);
priceAfterDiscounts *= findDiscountFactor(cart.appliedCartPurchasesDiscount);
console.log("OLOLOLOLO", cart, discounts, purchasesAmount, tariff);
// cart.allAppliedDiscounts.forEach((discount) => {
// priceAfterDiscounts *= findDiscountFactor(discount)
// })
//priceAfterDiscounts = cart.priceAfterDiscounts
return { priceBeforeDiscounts, priceAfterDiscounts };
}

@ -1,7 +1,6 @@
import { Tariff } from "@frontend/kitui";
import { Tariff, calcTariffPrice } from "@frontend/kitui";
import TariffCard from "./TariffCard";
import NumberIcon from "@icons/NumberIcon";
import { calcIndividualTariffPrices } from "./calcTariffPrices";
import { currencyFormatter } from "./currencyFormatter";
import FreeTariffCard from "./FreeTariffCard";
import { Typography } from "@mui/material";
@ -17,13 +16,13 @@ export const createTariffElements = (
.filter((tariff) => tariff.privileges.length > 0)
.map((tariff, index) => {
console.log("USSSSSES", user);
const { priceBeforeDiscounts, priceAfterDiscounts } =
calcIndividualTariffPrices(
const { priceBeforeDiscounts, priceAfterDiscounts } = calcTariffPrice(
tariff,
discounts,
user.wallet.spent,
[],
user.isUserNko,
user.id,
);
return (

@ -1119,7 +1119,7 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.20.1", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.24.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57"
integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==
@ -1376,13 +1376,6 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
"@emotion/is-prop-valid@^1.2.0":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337"
integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==
dependencies:
"@emotion/memoize" "^0.8.1"
"@emotion/is-prop-valid@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc"
@ -1516,10 +1509,10 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
"@frontend/kitui@^1.0.63":
version "1.0.63"
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.63.tgz#0be68741a7a340b79019b847a435c38e3880b82e"
integrity sha1-C+aHQaejQLeQGbhHpDXDjjiAuC4=
"@frontend/kitui@^1.0.74":
version "1.0.74"
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.74.tgz#de486f2a2f053f1f94e874917d6ff4904c4e4f15"
integrity sha1-3khvKi8FPx+U6HSRfW/0kExOTxU=
dependencies:
immer "^10.0.2"
reconnecting-eventsource "^1.6.2"
@ -1868,19 +1861,18 @@
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
"@mui/base@5.0.0-alpha.106":
version "5.0.0-alpha.106"
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.106.tgz#23e5f61639b5786318be873d7e6d26db412c5211"
integrity sha512-xJQQtwPCPwr6hGWTBdvDwHYwExn3Bw7nPQkN8Fuz8kHpZqoMVWQvvaFS557AIkkI2AFLV3DxVIMjbCvrIntBWg==
"@mui/base@5.0.0-beta.40":
version "5.0.0-beta.40"
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40.tgz#1f8a782f1fbf3f84a961e954c8176b187de3dae2"
integrity sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==
dependencies:
"@babel/runtime" "^7.20.1"
"@emotion/is-prop-valid" "^1.2.0"
"@mui/types" "^7.2.1"
"@mui/utils" "^5.10.14"
"@popperjs/core" "^2.11.6"
clsx "^1.2.1"
"@babel/runtime" "^7.23.9"
"@floating-ui/react-dom" "^2.0.8"
"@mui/types" "^7.2.14"
"@mui/utils" "^5.15.14"
"@popperjs/core" "^2.11.8"
clsx "^2.1.0"
prop-types "^15.8.1"
react-is "^18.2.0"
"@mui/base@^5.0.0-beta.22":
version "5.0.0-beta.36"
@ -1895,7 +1887,7 @@
clsx "^2.1.0"
prop-types "^15.8.1"
"@mui/core-downloads-tracker@^5.10.14":
"@mui/core-downloads-tracker@^5.15.14":
version "5.15.14"
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz#f7c57b261904831877220182303761c012d05046"
integrity sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==
@ -1907,20 +1899,20 @@
dependencies:
"@babel/runtime" "^7.23.9"
"@mui/material@5.10.14":
version "5.10.14"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.10.14.tgz#fcd687c92b22a71dc139376a5bc2d0bc578a172b"
integrity sha512-HWzKVAykePMx54WtxVwZyL1W4k3xlHYIqwMw0CaXAvgB3UE9yjABZuuGr8vG5Z6CSNWamzd+s1x8u7pQPFl9og==
"@mui/material@^5.10.14":
version "5.15.14"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.14.tgz#a40bd5eccfa9fc925535e1f4d70c6cef77fa3a75"
integrity sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==
dependencies:
"@babel/runtime" "^7.20.1"
"@mui/base" "5.0.0-alpha.106"
"@mui/core-downloads-tracker" "^5.10.14"
"@mui/system" "^5.10.14"
"@mui/types" "^7.2.1"
"@mui/utils" "^5.10.14"
"@types/react-transition-group" "^4.4.5"
clsx "^1.2.1"
csstype "^3.1.1"
"@babel/runtime" "^7.23.9"
"@mui/base" "5.0.0-beta.40"
"@mui/core-downloads-tracker" "^5.15.14"
"@mui/system" "^5.15.14"
"@mui/types" "^7.2.14"
"@mui/utils" "^5.15.14"
"@types/react-transition-group" "^4.4.10"
clsx "^2.1.0"
csstype "^3.1.3"
prop-types "^15.8.1"
react-is "^18.2.0"
react-transition-group "^4.4.5"
@ -1944,7 +1936,7 @@
csstype "^3.1.3"
prop-types "^15.8.1"
"@mui/system@^5.10.14":
"@mui/system@^5.15.14":
version "5.15.14"
resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.14.tgz#8a0c6571077eeb6b5f1ff7aa7ff6a3dc4a14200d"
integrity sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==
@ -1958,25 +1950,25 @@
csstype "^3.1.3"
prop-types "^15.8.1"
"@mui/types@^7.2.1", "@mui/types@^7.2.13", "@mui/types@^7.2.14":
"@mui/types@^7.2.13", "@mui/types@^7.2.14":
version "7.2.14"
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.14.tgz#8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9"
integrity sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==
"@mui/utils@^5.10.14", "@mui/utils@^5.15.14", "@mui/utils@^5.15.9":
version "5.15.14"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.14.tgz#e414d7efd5db00bfdc875273a40c0a89112ade3a"
integrity sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==
"@mui/utils@^5.14.16":
version "5.15.9"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.9.tgz#2bdf925e274d87cbe90c14eb52d0835318205e86"
integrity sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg==
dependencies:
"@babel/runtime" "^7.23.9"
"@types/prop-types" "^15.7.11"
prop-types "^15.8.1"
react-is "^18.2.0"
"@mui/utils@^5.14.16":
version "5.15.9"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.9.tgz#2bdf925e274d87cbe90c14eb52d0835318205e86"
integrity sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg==
"@mui/utils@^5.15.14", "@mui/utils@^5.15.9":
version "5.15.14"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.14.tgz#e414d7efd5db00bfdc875273a40c0a89112ade3a"
integrity sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==
dependencies:
"@babel/runtime" "^7.23.9"
"@types/prop-types" "^15.7.11"
@ -2059,7 +2051,7 @@
schema-utils "^3.0.0"
source-map "^0.7.3"
"@popperjs/core@^2.0.0", "@popperjs/core@^2.11.6", "@popperjs/core@^2.11.8":
"@popperjs/core@^2.0.0", "@popperjs/core@^2.11.8":
version "2.11.8"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
@ -2696,7 +2688,7 @@
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.5", "@types/react-transition-group@^4.4.8":
"@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.8":
version "4.4.10"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac"
integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==
@ -4020,7 +4012,7 @@ clone-deep@^4.0.1:
kind-of "^6.0.2"
shallow-clone "^3.0.0"
clsx@^1.1.0, clsx@^1.1.1, clsx@^1.2.1:
clsx@^1.1.0, clsx@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
@ -4485,7 +4477,7 @@ cssstyle@^2.3.0:
dependencies:
cssom "~0.3.6"
csstype@^3.0.2, csstype@^3.1.1, csstype@^3.1.3:
csstype@^3.0.2, csstype@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==