diff --git a/apps/admin/src/pages/WebRequests.tsx b/apps/admin/src/pages/WebRequests.tsx
index 06b522a..20cca32 100644
--- a/apps/admin/src/pages/WebRequests.tsx
+++ b/apps/admin/src/pages/WebRequests.tsx
@@ -72,7 +72,7 @@ export function WebRequests() {
{r.number}
{t('admin.webRequests.created', { date: dt(r.createdAt, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }) })}
- {dt(r.preferredAt, { weekday: 'short', day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })} |
+ {r.preferredAt ? dt(r.preferredAt, { weekday: 'short', day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }) : '—'} |
{t(`params.cleaning.cleaningType.${p.cleaningType ?? 'regular'}`)}
@@ -83,8 +83,8 @@ export function WebRequests() {
)}
|
- {t(`districts.${r.district.code}`)}
- {r.addressText}
+ {r.district ? t(`districts.${r.district.code}`) : '—'}
+ {r.addressText ?? '—'}
{r.note && {r.note} }
|
diff --git a/apps/api/package.json b/apps/api/package.json
index 4131ac8..3770787 100644
--- a/apps/api/package.json
+++ b/apps/api/package.json
@@ -16,7 +16,9 @@
"dev:demo": "tsx scripts/dev-demo.ts",
"dev:bo-demo": "tsx scripts/dev-backoffice-demo.ts",
"dev:chats-demo": "tsx scripts/dev-chats-demo.ts",
- "dev:crm-demo": "tsx scripts/dev-crm-demo.ts"
+ "dev:crm-demo": "tsx scripts/dev-crm-demo.ts",
+ "dev:partners-demo": "tsx scripts/dev-partners-demo.ts",
+ "dev:points-demo": "tsx scripts/dev-points-demo.ts"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1152.0",
diff --git a/apps/api/scripts/dev-partners-demo.ts b/apps/api/scripts/dev-partners-demo.ts
new file mode 100644
index 0000000..1b6ed41
--- /dev/null
+++ b/apps/api/scripts/dev-partners-demo.ts
@@ -0,0 +1,81 @@
+/**
+ * Локальная разработка: демо партнёра услуг (клининг) — заказы у партнёра, сотрудники, доход,
+ * и одноразовая ссылка на кабинет менеджера в браузере.
+ * pnpm --filter @barev/api dev:partners-demo
+ * Клиенты демо — telegramId 100003000+. Повторный запуск пересоздаёт их заказы.
+ */
+import { fromYerevan, toYerevan } from '@barev/core';
+import { getDb } from '@barev/db';
+import { createOrder, createProWebLogin, dispatcherAssign, giveConsent, markPaid, offerOrder, startClient, transitionOrder, type Ctx } from '@barev/services';
+import { env } from '../src/env.ts';
+
+if (env.isProd) throw new Error('Только для разработки');
+
+const db = getDb();
+const ctx: Ctx = { db, notify: { emit: async () => {} }, now: () => new Date() };
+const TG_FROM = 100003000n;
+const PRO_APP = process.env.PRO_WEB_URL ?? 'http://localhost:5187';
+
+// ── чистим прошлое демо ──
+const old = await db.user.findMany({ where: { telegramId: { gte: TG_FROM, lt: TG_FROM + 100n } }, include: { client: true } });
+const oldClients = old.map((u) => u.client?.id).filter((x): x is string => !!x);
+const oldOrders = (await db.order.findMany({ where: { clientId: { in: oldClients } }, select: { id: true } })).map((o) => o.id);
+await db.partnerEarning.deleteMany({ where: { orderId: { in: oldOrders } } });
+await db.agencyCommission.deleteMany({ where: { orderId: { in: oldOrders } } });
+await db.order.deleteMany({ where: { id: { in: oldOrders } } });
+
+let company = await db.providerCompany.findFirst({ where: { active: true, roles: { has: 'CLEANER' } } });
+if (!company) throw new Error('Нет компании-партнёра — запустите seed');
+company = await db.providerCompany.update({ where: { id: company.id }, data: { deal: 'PROFIT_SHARE', profitSharePct: 40, fotPct: null, taxPct: null } });
+const manager = await db.companyDispatcher.findFirstOrThrow({ where: { companyId: company.id } });
+const staff = await db.provider.findMany({ where: { companyId: company.id, active: true } });
+// график всем сотрудникам: каждый день 9–20, лимит 3 заказа в день у первого
+for (const [i, p] of staff.entries()) {
+ await db.providerSchedule.deleteMany({ where: { providerId: p.id } });
+ await db.providerSchedule.createMany({ data: [0, 1, 2, 3, 4, 5, 6].map((weekday) => ({ providerId: p.id, weekday, startMinute: 9 * 60, endMinute: 20 * 60 })) });
+ await db.provider.update({ where: { id: p.id }, data: { maxOrdersPerDay: i === 0 ? 3 : null, maxHoursPerDay: i === 0 ? 8 : null } });
+}
+const kentron = await db.district.findUniqueOrThrow({ where: { code: 'kentron' } });
+const admin = await db.adminUser.findFirstOrThrow({ where: { email: 'owner@barev.local' } });
+
+const at = (dayOffset: number, hour: number) => {
+ const p = toYerevan(new Date(Date.now() + dayOffset * 24 * 3600_000));
+ return fromYerevan(p.year, p.month, p.day, hour * 60);
+};
+const NAMES = ['Ольга', 'James', 'Ирина', 'Arpi', 'Лилит'];
+async function demoOrder(i: number, when: Date, rooms: number) {
+ const s = await startClient(ctx, { id: Number(TG_FROM) + i, first_name: NAMES[i % NAMES.length]!, language_code: i % 2 ? 'en' : 'ru' });
+ await giveConsent(ctx, s.clientId);
+ return createOrder(ctx, { clientId: s.clientId, serviceCode: 'cleaning', params: { cleaningType: 'regular', rooms, bathrooms: 1 }, scheduledAt: when, addressText: `Абовяна ${10 + i}`, districtId: kentron.id, allowBusySlot: true });
+}
+
+// 1) два заказа ждут назначения у партнёра
+for (const [i, d] of [
+ [0, 2],
+ [1, 3],
+] as const) {
+ const o = await demoOrder(i, at(d, 11), 2 + i);
+ await offerOrder(ctx, { orderId: o.id, adminId: admin.id, target: { kind: 'company', id: company.id } });
+}
+// 2) один назначен на сотрудника
+const assigned = await demoOrder(2, at(2, 15), 1);
+await offerOrder(ctx, { orderId: assigned.id, adminId: admin.id, target: { kind: 'company', id: company.id } });
+const linked = staff.find((p) => p.userId) ?? staff[0]!;
+await dispatcherAssign(ctx, { orderId: assigned.id, companyId: company.id, providerId: linked.id, dispatcherUserId: manager.userId });
+// 3) один выполнен и оплачен — доход партнёра
+const done = await demoOrder(3, at(1, 10), 3);
+await offerOrder(ctx, { orderId: done.id, adminId: admin.id, target: { kind: 'company', id: company.id } });
+await dispatcherAssign(ctx, { orderId: done.id, companyId: company.id, providerId: linked.id, dispatcherUserId: manager.userId });
+for (const to of ['EN_ROUTE', 'CLEANING'] as const) await transitionOrder(ctx, { orderId: done.id, to, actor: 'ADMIN', actorId: admin.id, event: 'demo' });
+await db.orderChecklistItem.updateMany({ where: { orderId: done.id }, data: { checkedAt: new Date() } });
+await db.order.update({ where: { id: done.id }, data: { status: 'DONE', completedAt: new Date() } });
+await markPaid(ctx, { orderId: done.id, by: { type: 'ADMIN', id: admin.id } });
+
+// 4) новый заказ без исполнителя — оператор выбирает, кому отдать (видно, что выгоднее)
+const fresh = await demoOrder(4, at(4, 12), 2);
+console.log(`Заказ для назначения: #${fresh.number} (${fresh.id})`);
+
+const code = await createProWebLogin(ctx, manager.userId);
+console.log(`Партнёр: ${company.name}`);
+console.log(`Кабинет менеджера в браузере (ссылка одноразовая, 15 минут):\n${PRO_APP}/?login=${code}#/company`);
+process.exit(0);
diff --git a/apps/api/scripts/dev-points-demo.ts b/apps/api/scripts/dev-points-demo.ts
new file mode 100644
index 0000000..acaf2c3
--- /dev/null
+++ b/apps/api/scripts/dev-points-demo.ts
@@ -0,0 +1,46 @@
+/**
+ * Локальная разработка: демо бариков у клиента «Анна» (telegramId 100000001):
+ * начисления (доступные и в ожидании), бонус, списание, открытый запрос и предложение системы.
+ * pnpm --filter @barev/api dev:points-demo
+ */
+import { DAY } from '@barev/core';
+import { getDb } from '@barev/db';
+import { accruePoints, redeemPoints, requestRedemption, type Ctx } from '@barev/services';
+import { env } from '../src/env.ts';
+
+if (env.isProd) throw new Error('Только для разработки');
+const db = getDb();
+const ctx: Ctx = { db, notify: { emit: async () => {} }, now: () => new Date() };
+const OWNER = { adminId: null, owner: true };
+
+const user = await db.user.findUniqueOrThrow({ where: { telegramId: 100000001n }, include: { client: true } });
+const clientId = user.client!.id;
+// чистим прошлое демо этого клиента
+await db.pointsRedemptionItem.deleteMany({ where: { redemption: { clientId } } });
+await db.pointsRedemption.deleteMany({ where: { clientId } });
+await db.pointsReversal.deleteMany({ where: { clientId } });
+await db.pointsSuggestion.deleteMany({ where: { clientId } });
+await db.pointsAccrual.deleteMany({ where: { clientId } });
+await db.client.update({ where: { id: clientId }, data: { pointsActive: 0, pointsPending: 0, pointsDebt: 0, streakCount: 0, streakLastAt: null, pointsActivityAt: null } });
+
+const cat = (code: string) => db.pointsCategory.findUniqueOrThrow({ where: { code } });
+const now = Date.now();
+const ago = (d: number) => new Date(now - d * DAY);
+const cleaning = await cat('cleaning');
+for (const [i, d] of [50, 25, 3].entries()) {
+ await accruePoints(ctx, { clientId, kind: 'ORDER', categoryId: cleaning.id, orderAmount: 18_000 + i * 2000, serviceDate: ago(d), orderRef: `DEMO-C${i}`, channel: 'WEB' }, OWNER);
+}
+await accruePoints(ctx, { clientId, kind: 'ORDER', categoryId: (await cat('documents')).id, orderAmount: 45_000, excludedAmount: 15_000, serviceDate: ago(10), orderRef: 'DEMO-D1', channel: 'WEB' }, OWNER);
+// ожидание 48 ч от даты услуги: старые уже доступны — активируем
+const { activatePendingPoints } = await import('@barev/services');
+await activatePendingPoints(ctx);
+// свежая уборка — ещё в ожидании
+await accruePoints(ctx, { clientId, kind: 'ORDER', categoryId: cleaning.id, orderAmount: 19_000, serviceDate: new Date(), orderRef: 'DEMO-C3', channel: 'AUTO' }, OWNER);
+const bonus = await db.pointsBonusType.findUniqueOrThrow({ where: { code: 'housewarming' } });
+await accruePoints(ctx, { clientId, kind: 'BONUS', bonusTypeId: bonus.id, amount: 5000, serviceDate: new Date(), channel: 'WEB', commentForClient: 'Yerevan Home' }, OWNER);
+await redeemPoints(ctx, { clientId, amount: 2000, orderAmount: 20_000, orderRef: 'DEMO-R1', reason: 'оплата по звонку', channel: 'WEB' }, OWNER);
+await requestRedemption(ctx, { clientId, amount: 1500, note: 'Уборка 30 октября, 18 000 ֏' });
+await db.pointsSuggestion.create({ data: { clientId, mechanic: 'first_month_route', dedupeKey: `route:${clientId}`, payload: { categories: ['cleaning', 'documents', 'learning'] }, suggestedAmount: 3000 } });
+const c = await db.client.findUniqueOrThrow({ where: { id: clientId } });
+console.log(`Анна: доступно ${c.pointsActive}, в ожидании ${c.pointsPending}, серия ${c.streakCount}`);
+process.exit(0);
diff --git a/apps/api/src/routers/backoffice/index.ts b/apps/api/src/routers/backoffice/index.ts
index c9fa6a5..3331fec 100644
--- a/apps/api/src/routers/backoffice/index.ts
+++ b/apps/api/src/routers/backoffice/index.ts
@@ -7,6 +7,7 @@ import { boOrdersRouter } from './orders.ts';
import { boProvidersRouter } from './providers.ts';
import { boCrmRouter } from './crm.ts';
import { boPartnersRouter } from './partners.ts';
+import { boPointsRouter } from './points.ts';
import { boProductsRouter } from './products.ts';
import { boMovesRouter, boRequestsRouter } from './moves.ts';
import { boBroadcastsRouter, boJournalRouter, boSettingsRouter } from './admin5.ts';
@@ -25,6 +26,7 @@ export const backofficeRouter = router({
providers: boProvidersRouter,
crm: boCrmRouter,
partners: boPartnersRouter,
+ points: boPointsRouter,
products: boProductsRouter,
broadcasts: boBroadcastsRouter,
journal: boJournalRouter,
diff --git a/apps/api/src/routers/backoffice/orders.ts b/apps/api/src/routers/backoffice/orders.ts
index d89c4c6..e1a7f40 100644
--- a/apps/api/src/routers/backoffice/orders.ts
+++ b/apps/api/src/routers/backoffice/orders.ts
@@ -9,6 +9,9 @@ import {
getServiceByCode,
getSettings,
markPaid,
+ previewOrderEdit,
+ editOrderComposition,
+ staffChecklistItem,
offerOrder,
orderPayout,
quoteForClient,
@@ -210,7 +213,7 @@ export const boOrdersRouter = router({
const pending = o.offers.find((x) => x.status === 'OFFERED');
const adminIds = [...new Set(o.offers.map((x) => x.createdById).filter((x): x is string => !!x))];
const admins = new Map((await ctx.db.adminUser.findMany({ where: { id: { in: adminIds } }, select: { id: true, name: true } })).map((a) => [a.id, a.name]));
- const payout = ctx.isSuper && o.provider ? orderPayout(o, o.provider) : null;
+ const payout = ctx.isSuper && o.provider ? orderPayout(o, o.provider, { fotPct: (await getSettings(ctx.db))['partner.fotPct'] }) : null;
const sub = o.client.subscriptions.find((s) => s.startsAt <= now && s.endsAt > now);
return {
id: o.id,
@@ -246,7 +249,7 @@ export const boOrdersRouter = router({
respondedAt: x.respondedAt,
})),
history: await historyView(ctx.db, o),
- checklist: o.checklist.map((c) => ({ code: c.code, done: !!c.checkedAt, requiresPhoto: c.requiresPhoto, fileId: c.fileId })),
+ checklist: o.checklist.map((c) => ({ code: c.code, done: !!c.checkedAt, requiresPhoto: c.requiresPhoto, fileId: c.fileId, waived: c.photoWaivedReason, byStaff: !!c.checkedByAdminId })),
photos: o.files.filter((f) => f.kind === 'PHOTO_REPORT').map((f) => f.id),
rating: o.rating ? { score: o.rating.score, comment: o.rating.comment } : null,
// деньги — только суперадмину; статус оплаты видят все (поддержка отмечает оплату наличными)
@@ -267,7 +270,7 @@ export const boOrdersRouter = router({
/** Подсказка: свободные кандидаты по рейтингу подбора и занятые */
candidates: ordersProcedure.input(idInput).query(async ({ ctx, input }) => {
- const { ranked, busy } = await assignmentCandidates(ctx.svc, input.id);
+ const { ranked, busy, bestId } = await assignmentCandidates(ctx.svc, input.id);
const tried = new Set((await ctx.db.orderOffer.findMany({ where: { orderId: input.id }, select: { providerId: true, companyId: true, status: true } })).filter((o) => o.status !== 'OFFERED').map((o) => o.providerId ?? o.companyId));
const view = (c: (typeof ranked)[number] | (typeof busy)[number]) => ({
kind: c.kind,
@@ -279,6 +282,12 @@ export const boOrdersRouter = router({
onShift: c.onShift,
reasons: 'reasons' in c ? c.reasons : [],
tried: tried.has(c.id),
+ /** самый выгодный для нас из доступных — подсвечивается всем; суммы видит только суперадмин */
+ best: `${c.kind}:${c.id}` === bestId,
+ cost: ctx.isSuper ? c.cost : null,
+ margin: ctx.isSuper ? c.margin : null,
+ partnerFree: c.partnerFree ?? null,
+ partnerStaff: c.partnerStaff ?? null,
});
return { free: ranked.map(view), busy: busy.map(view) };
}),
@@ -320,6 +329,16 @@ export const boOrdersRouter = router({
// ───── новый заказ за клиента ─────
/** Услуги, которые можно заказать сейчас, с формой параметров */
+ /** Изменить состав заказа: предпросмотр и сохранение (пересчёт цены или своя цена с причиной) */
+ editPreview: ordersProcedure.input(z.object({ id: z.string(), params: z.record(z.string(), z.unknown()) })).query(({ ctx, input }) => previewOrderEdit(ctx.svc, { orderId: input.id, params: input.params })),
+ edit: ordersProcedure
+ .input(z.object({ id: z.string(), params: z.record(z.string(), z.unknown()), totalPrice: z.number().int().min(0).nullable().optional(), reason: z.string().trim().max(500).nullable().optional(), notify: z.boolean().default(false) }))
+ .mutation(({ ctx, input }) => editOrderComposition(ctx.svc, { orderId: input.id, adminId: ctx.admin.id, params: input.params, totalPrice: input.totalPrice, reason: input.reason, notify: input.notify })),
+ /** Чек-лист за исполнителя */
+ checklist: ordersProcedure
+ .input(z.object({ id: z.string(), code: z.string().max(60), checked: z.boolean(), reason: z.string().trim().max(500).nullable().optional() }))
+ .mutation(({ ctx, input }) => staffChecklistItem(ctx.svc, { orderId: input.id, adminId: ctx.admin.id, code: input.code, checked: input.checked, reason: input.reason })),
+
services: ordersProcedure.query(async ({ ctx }) => {
const list = await ctx.db.service.findMany({ where: { active: true }, orderBy: { sortOrder: 'asc' }, select: { code: true } });
return Promise.all(
diff --git a/apps/api/src/routers/backoffice/partners.ts b/apps/api/src/routers/backoffice/partners.ts
index 5d81f79..3c8db3d 100644
--- a/apps/api/src/routers/backoffice/partners.ts
+++ b/apps/api/src/routers/backoffice/partners.ts
@@ -1,5 +1,5 @@
import { DAY, normalizeAgencyCode } from '@barev/core';
-import { agencyLink, createOwnerInvite, savePartnerOffer } from '@barev/services';
+import { agencyLink, createOwnerInvite, getSettings, managerInviteCode, partnerMoney, savePartnerOffer, termsOf } from '@barev/services';
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { router, superProcedure } from '../../trpc.ts';
@@ -39,6 +39,8 @@ export const boPartnersRouter = router({
code: a.code,
name: a.name,
commissionPct: a.commissionPct,
+ giftPlan: a.giftPlan,
+ giftMonths: a.giftMonths,
active: a.active,
sales: a.sales,
clients: a._count.clients,
@@ -72,6 +74,10 @@ export const boPartnersRouter = router({
code: a.code,
name: a.name,
commissionPct: a.commissionPct,
+ giftPlan: a.giftPlan,
+ giftMonths: a.giftMonths,
+ housewarmingPoints: a.housewarmingPoints,
+ housewarmingDays: a.housewarmingDays,
contact: a.contact,
note: a.note,
active: a.active,
@@ -92,7 +98,7 @@ export const boPartnersRouter = router({
}),
saveAgency: p
- .input(z.object({ id: z.string().optional(), code: z.string().max(32), name: z.string().trim().min(1).max(100), commissionPct: z.number().int().min(0).max(100), contact: z.string().max(200).nullable(), note: z.string().max(2000).nullable(), active: z.boolean(), salesId: z.string().nullable() }))
+ .input(z.object({ id: z.string().optional(), code: z.string().max(32), name: z.string().trim().min(1).max(100), commissionPct: z.number().int().min(0).max(100), giftPlan: z.enum(['BAREV_PLUS', 'ELITE']).nullable(), giftMonths: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(6), z.literal(12)]), housewarmingPoints: z.number().int().min(0).max(1_000_000).default(0), housewarmingDays: z.number().int().min(1).max(1000).default(60), contact: z.string().max(200).nullable(), note: z.string().max(2000).nullable(), active: z.boolean(), salesId: z.string().nullable() }))
.mutation(async ({ ctx, input }) => {
const code = normalizeAgencyCode(input.code);
if (!code) throw new TRPCError({ code: 'BAD_REQUEST', message: 'AGENCY_CODE_FORMAT' });
@@ -110,6 +116,122 @@ export const boPartnersRouter = router({
await ctx.db.payout.create({ data: { agencyId: input.id, amount: input.amount, status: 'PAID', paidAt: now, note: input.note, createdById: ctx.admin.id, periodStart: last?.periodEnd ?? monthStart(now), periodEnd: now } });
}),
+ // ───── партнёры услуг (клининговые компании) ─────
+
+ servicePartners: p.query(async ({ ctx }) => {
+ const settings = await getSettings(ctx.db);
+ const list = await ctx.db.providerCompany.findMany({
+ orderBy: [{ active: 'desc' }, { name: 'asc' }],
+ include: { _count: { select: { employees: { where: { active: true } }, dispatchers: true } } },
+ });
+ const ids = list.map((c) => c.id);
+ const now = ctx.svc.now();
+ const [active, month, accrued, paid] = await Promise.all([
+ ctx.db.order.groupBy({ by: ['companyId'], where: { companyId: { in: ids }, status: { notIn: ['CANCELLED', 'DONE', 'COMPLETED'] } }, _count: true }),
+ ctx.db.partnerEarning.groupBy({ by: ['companyId'], where: { companyId: { in: ids }, period: monthKey(now) }, _sum: { amount: true } }),
+ ctx.db.partnerEarning.groupBy({ by: ['companyId'], where: { companyId: { in: ids } }, _sum: { amount: true } }),
+ ctx.db.payout.groupBy({ by: ['companyId'], where: { companyId: { in: ids }, status: 'PAID' }, _sum: { amount: true } }),
+ ]);
+ const m = (rows: T[], f: (r: T) => number) => new Map(rows.map((r) => [r.companyId, f(r)]));
+ const act = m(active, (r) => r._count);
+ const mon = m(month, (r) => r._sum.amount ?? 0);
+ const acc = m(accrued, (r) => r._sum.amount ?? 0);
+ const pd = m(paid, (r) => r._sum.amount ?? 0);
+ return list.map((c) => ({
+ id: c.id,
+ name: c.name,
+ active: c.active,
+ deal: c.deal,
+ terms: termsOf(c, settings),
+ autoAssign: c.autoAssign,
+ staff: c._count.employees,
+ managers: c._count.dispatchers,
+ activeOrders: act.get(c.id) ?? 0,
+ thisMonth: mon.get(c.id) ?? 0,
+ balance: (acc.get(c.id) ?? 0) - (pd.get(c.id) ?? 0),
+ }));
+ }),
+
+ servicePartner: p.input(z.object({ id: z.string() })).query(async ({ ctx, input }) => {
+ const c = await ctx.db.providerCompany.findUnique({
+ where: { id: input.id },
+ include: { employees: { orderBy: [{ active: 'desc' }, { name: 'asc' }] }, dispatchers: { include: { user: true }, orderBy: { createdAt: 'asc' } } },
+ });
+ if (!c) throw new TRPCError({ code: 'NOT_FOUND' });
+ const settings = await getSettings(ctx.db);
+ const [money, activeOrders] = await Promise.all([
+ partnerMoney(ctx.db, c.id),
+ ctx.db.order.findMany({
+ where: { companyId: c.id, status: { notIn: ['CANCELLED', 'DONE', 'COMPLETED'] } },
+ orderBy: { scheduledAt: 'asc' },
+ take: 30,
+ include: { service: { select: { code: true } }, provider: { select: { name: true } } },
+ }),
+ ]);
+ return {
+ id: c.id,
+ name: c.name,
+ contactPhone: c.contactPhone,
+ note: c.note,
+ active: c.active,
+ deal: c.deal,
+ commissionPct: c.commissionPct,
+ profitSharePct: c.profitSharePct,
+ fotPct: c.fotPct,
+ taxPct: c.taxPct,
+ terms: termsOf(c, settings),
+ defaults: { fotPct: settings['partner.fotPct'], taxPct: settings['partner.taxPct'] },
+ autoAssign: c.autoAssign,
+ travelGapMinutes: c.travelGapMinutes,
+ createdAt: c.createdAt,
+ managerLink: proBotUrl(c.inviteCode),
+ managers: c.dispatchers.map((d) => ({ id: d.id, name: name(d.user), since: d.createdAt })),
+ staff: c.employees.map((e) => ({ id: e.id, name: e.name, phone: e.phone, active: e.active, linked: !!e.userId, maxOrdersPerDay: e.maxOrdersPerDay, maxHoursPerDay: e.maxHoursPerDay })),
+ orders: activeOrders.map((o) => ({ id: o.id, number: o.number, service: o.service.code, scheduledAt: o.scheduledAt, status: o.status, staff: o.provider?.name ?? null })),
+ money,
+ };
+ }),
+
+ saveServicePartner: p
+ .input(
+ z.object({
+ id: z.string().optional(),
+ name: z.string().trim().min(1).max(100),
+ contactPhone: z.string().trim().max(30).nullable(),
+ note: z.string().max(2000).nullable(),
+ active: z.boolean(),
+ deal: z.enum(['PROFIT_SHARE', 'COMMISSION']),
+ commissionPct: z.number().int().min(0).max(100),
+ profitSharePct: z.number().int().min(0).max(100),
+ fotPct: z.number().int().min(0).max(100).nullable(),
+ taxPct: z.number().int().min(0).max(100).nullable(),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ const { id, ...data } = input;
+ // пока партнёры услуг — только клининг
+ const c = id
+ ? await ctx.db.providerCompany.update({ where: { id }, data })
+ : await ctx.db.providerCompany.create({ data: { ...data, roles: ['CLEANER'], inviteCode: managerInviteCode() } });
+ return { id: c.id };
+ }),
+
+ /** Новая ссылка для менеджеров — старая перестаёт работать (уже подключённые остаются) */
+ resetManagerLink: p.input(z.object({ id: z.string() })).mutation(async ({ ctx, input }) => {
+ const c = await ctx.db.providerCompany.update({ where: { id: input.id }, data: { inviteCode: managerInviteCode() } });
+ return { link: proBotUrl(c.inviteCode) };
+ }),
+
+ removeManager: p.input(z.object({ id: z.string() })).mutation(async ({ ctx, input }) => {
+ await ctx.db.companyDispatcher.delete({ where: { id: input.id } });
+ }),
+
+ servicePartnerPayout: p.input(z.object({ id: z.string(), amount: z.number().int().min(1), note: z.string().max(300).optional() })).mutation(async ({ ctx, input }) => {
+ const now = ctx.svc.now();
+ const last = await ctx.db.payout.findFirst({ where: { companyId: input.id }, orderBy: { periodEnd: 'desc' } });
+ await ctx.db.payout.create({ data: { companyId: input.id, amount: input.amount, status: 'PAID', paidAt: now, note: input.note, createdById: ctx.admin.id, periodStart: last?.periodEnd ?? monthStart(now), periodEnd: now } });
+ }),
+
// ───── заведения ─────
venues: p.query(async ({ ctx }) => {
diff --git a/apps/api/src/routers/backoffice/points.ts b/apps/api/src/routers/backoffice/points.ts
new file mode 100644
index 0000000..519465a
--- /dev/null
+++ b/apps/api/src/routers/backoffice/points.ts
@@ -0,0 +1,398 @@
+import { DAY, membershipLevel } from '@barev/core';
+import type { Db } from '@barev/db';
+import {
+ acceptSuggestion,
+ accruePoints,
+ confirmRedemption,
+ getSettings,
+ pointsHistory,
+ previewAccrual,
+ redeemPoints,
+ rejectRedemption,
+ rejectSuggestion,
+ reverseAccrual,
+ reversePreview,
+ reverseRedemption,
+ type PointsActor,
+} from '@barev/services';
+import { TRPCError } from '@trpc/server';
+import { z } from 'zod';
+import { rolesProcedure, router, superProcedure } from '../../trpc.ts';
+
+/**
+ * Барики в новой админке. Управляет суперадмин; поддержка — только если включено в настройках,
+ * с лимитами на операцию и на сутки (выше — подтверждение суперадмина).
+ */
+const pointsProcedure = rolesProcedure('SUPPORT').use(async ({ ctx, next }) => {
+ if (!ctx.isSuper && !(await getSettings(ctx.db))['points.supportCanManage']) throw new TRPCError({ code: 'FORBIDDEN', message: 'ROLE_FORBIDDEN' });
+ return next({ ctx: { actor: { adminId: ctx.admin.id, owner: ctx.isSuper } satisfies PointsActor } });
+});
+
+const name = (u: { firstName: string | null; lastName: string | null; username: string | null }) => [u.firstName, u.lastName].filter(Boolean).join(' ') || (u.username ? `@${u.username}` : '—');
+const L5 = z.object({ ru: z.string().max(100), en: z.string().max(100), zh: z.string().max(100), hy: z.string().max(100), es: z.string().max(100) });
+const idem = z.string().min(8).max(80).optional();
+
+/** Клиент по телефону, @username, имени или ID */
+async function findClients(db: Db, q: string) {
+ const s = q.trim().replace(/^@/, '');
+ const digits = s.replace(/[^\d]/g, '');
+ return db.client.findMany({
+ where: {
+ OR: [
+ { id: s },
+ { cardCode: s.toUpperCase() },
+ { user: { username: { equals: s, mode: 'insensitive' } } },
+ { user: { firstName: { contains: s, mode: 'insensitive' } } },
+ { user: { lastName: { contains: s, mode: 'insensitive' } } },
+ ...(digits.length >= 5 ? [{ user: { phone: { contains: digits } } }] : []),
+ ],
+ },
+ include: { user: true, subscriptions: { where: { status: 'ACTIVE' } } },
+ take: 20,
+ orderBy: { createdAt: 'desc' },
+ });
+}
+
+export const boPointsRouter = router({
+ /** Справочники формы: категории, типы бонусов, правила */
+ dictionaries: pointsProcedure.query(async ({ ctx }) => {
+ const [categories, bonusTypes, s] = await Promise.all([
+ ctx.db.pointsCategory.findMany({ orderBy: { sortOrder: 'asc' } }),
+ ctx.db.pointsBonusType.findMany({ orderBy: { sortOrder: 'asc' } }),
+ getSettings(ctx.db),
+ ]);
+ return {
+ categories: categories.map((c) => ({ ...c, name: c.name as Record })),
+ bonusTypes: bonusTypes.map((b) => ({ ...b, name: b.name as Record })),
+ rules: { pendingHours: s['points.pendingHours'], sharePct: s['points.maxSharePct'], min: s['points.minRedeem'], burnDays: s['points.burnDays'], diffPct: s['points.diffHighlightPct'] },
+ owner: ctx.isSuper,
+ };
+ }),
+
+ search: pointsProcedure.input(z.object({ q: z.string().trim().min(1).max(100) })).query(async ({ ctx, input }) => {
+ const now = ctx.svc.now();
+ return (await findClients(ctx.db, input.q)).map((c) => ({
+ id: c.id,
+ name: name(c.user),
+ username: c.user.username,
+ phone: c.user.phone,
+ tier: membershipLevel(c.subscriptions, now),
+ balance: c.pointsActive,
+ pending: c.pointsPending,
+ }));
+ }),
+
+ /** Карточка клиента: баланс, ожидание, сгорание, источник, флаг проверки, последние операции */
+ client: pointsProcedure.input(z.object({ id: z.string() })).query(async ({ ctx, input }) => {
+ const s = await getSettings(ctx.db);
+ const now = ctx.svc.now();
+ const c = await ctx.db.client.findUnique({ where: { id: input.id }, include: { user: true, agency: { select: { name: true } }, subscriptions: { where: { status: 'ACTIVE' } } } });
+ if (!c) throw new TRPCError({ code: 'NOT_FOUND' });
+ const [history, reversed30, pendingNext] = await Promise.all([
+ pointsHistory(ctx.db, c.id, { take: 10 }),
+ ctx.db.pointsReversal.count({ where: { clientId: c.id, targetType: 'ACCRUAL', createdAt: { gte: new Date(now.getTime() - 30 * DAY) } } }),
+ ctx.db.pointsAccrual.findFirst({ where: { clientId: c.id, status: 'PENDING' }, orderBy: { availableAt: 'asc' } }),
+ ]);
+ return {
+ id: c.id,
+ name: name(c.user),
+ phone: c.user.phone,
+ username: c.user.username,
+ tier: membershipLevel(c.subscriptions, now),
+ agency: c.agency?.name ?? null,
+ balance: c.pointsActive,
+ pending: c.pointsPending,
+ pendingNextAt: pendingNext?.availableAt ?? null,
+ debt: c.pointsDebt,
+ burnAt: c.pointsActive > 0 && c.pointsActivityAt ? new Date(c.pointsActivityAt.getTime() + s['points.burnDays'] * DAY) : null,
+ streak: c.streakCount,
+ flagged: reversed30 > 2,
+ history,
+ };
+ }),
+
+ preview: pointsProcedure
+ .input(z.object({ clientId: z.string(), categoryId: z.string(), orderAmount: z.number().int().min(0), excludedAmount: z.number().int().min(0).default(0), paidWithPoints: z.number().int().min(0).default(0), serviceDate: z.coerce.date() }))
+ .query(async ({ ctx, input }) => previewAccrual(ctx.db, input, await getSettings(ctx.db), ctx.svc.now())),
+
+ /** Начисление по заказу или бонус */
+ accrue: pointsProcedure
+ .input(
+ z.object({
+ clientId: z.string(),
+ kind: z.enum(['ORDER', 'BONUS']),
+ categoryId: z.string().optional(),
+ bonusTypeId: z.string().optional(),
+ orderRef: z.string().trim().max(60).nullable().optional(),
+ orderAmount: z.number().int().min(0).optional(),
+ excludedAmount: z.number().int().min(0).optional(),
+ paidWithPoints: z.number().int().min(0).optional(),
+ serviceDate: z.coerce.date(),
+ amount: z.number().int().min(1).max(10_000_000).optional(),
+ reason: z.string().trim().max(500).nullable().optional(),
+ commentForClient: z.string().trim().max(300).nullable().optional(),
+ noWait: z.boolean().optional(),
+ ttlDays: z.number().int().min(1).max(1000).nullable().optional(),
+ idempotencyKey: idem,
+ }),
+ )
+ .mutation(({ ctx, input }) => accruePoints(ctx.svc, { ...input, channel: 'WEB' }, ctx.actor)),
+
+ /** Списание командой: по заказу вне системы или по звонку (с причиной) */
+ redeem: pointsProcedure
+ .input(z.object({ clientId: z.string(), amount: z.number().int().min(1), orderRef: z.string().trim().max(60).nullable().optional(), orderAmount: z.number().int().min(1).nullable().optional(), reason: z.string().trim().min(1).max(500), idempotencyKey: idem }))
+ .mutation(({ ctx, input }) => redeemPoints(ctx.svc, { ...input, channel: 'WEB' }, ctx.actor)),
+
+ /** Запросы клиентов «Оплатить бариками» */
+ requests: pointsProcedure.query(async ({ ctx }) => {
+ const list = await ctx.db.pointsRedemption.findMany({ where: { status: 'REQUESTED' }, orderBy: { requestedAt: 'asc' }, include: { client: { include: { user: true } }, order: { select: { id: true, number: true, totalPrice: true, pointsUsed: true } } } });
+ return list.map((r) => ({ id: r.id, clientId: r.clientId, name: name(r.client.user), balance: r.client.pointsActive, amount: r.amount, note: r.note, order: r.order, requestedAt: r.requestedAt, expiresAt: r.expiresAt }));
+ }),
+ confirm: pointsProcedure
+ .input(z.object({ id: z.string(), orderAmount: z.number().int().min(1), amount: z.number().int().min(1).optional() }))
+ .mutation(({ ctx, input }) => confirmRedemption(ctx.svc, { redemptionId: input.id, orderAmount: input.orderAmount, amount: input.amount }, ctx.actor)),
+ reject: pointsProcedure.input(z.object({ id: z.string(), reason: z.string().trim().min(1).max(500) })).mutation(({ ctx, input }) => rejectRedemption(ctx.svc, { redemptionId: input.id, reason: input.reason }, ctx.actor)),
+
+ reversePreview: pointsProcedure.input(z.object({ type: z.enum(['ACCRUAL', 'REDEMPTION']), id: z.string() })).query(({ ctx, input }) => reversePreview(ctx.db, input)),
+ reverse: pointsProcedure
+ .input(z.object({ type: z.enum(['ACCRUAL', 'REDEMPTION']), id: z.string(), reason: z.string().trim().min(1).max(500) }))
+ .mutation(async ({ ctx, input }) => {
+ if (input.type === 'ACCRUAL') await reverseAccrual(ctx.svc, { accrualId: input.id, reason: input.reason, channel: 'WEB' }, ctx.actor);
+ else await reverseRedemption(ctx.svc, { redemptionId: input.id, reason: input.reason, channel: 'WEB' }, ctx.actor);
+ }),
+
+ /** Журнал: все операции с автором и каналом; фильтры; выгрузка — на клиенте */
+ ledger: pointsProcedure
+ .input(
+ z.object({
+ clientId: z.string().optional(),
+ adminId: z.string().optional(),
+ type: z.enum(['accrual', 'bonus', 'redemption', 'reversal']).optional(),
+ categoryId: z.string().optional(),
+ channel: z.enum(['WEB', 'BOT', 'CSV', 'AUTO', 'CLIENT']).optional(),
+ from: z.coerce.date().optional(),
+ to: z.coerce.date().optional(),
+ take: z.number().int().min(1).max(2000).default(200),
+ }),
+ )
+ .query(async ({ ctx, input }) => {
+ const s = await getSettings(ctx.db);
+ const at = input.from || input.to ? { gte: input.from, lt: input.to } : undefined;
+ const want = (t: string) => !input.type || input.type === t;
+ const [acc, red, rev, admins] = await Promise.all([
+ want('accrual') || want('bonus')
+ ? ctx.db.pointsAccrual.findMany({
+ where: { clientId: input.clientId, createdById: input.adminId, categoryId: input.categoryId, channel: input.channel, createdAt: at, ...(input.type === 'accrual' ? { kind: 'ORDER' } : input.type === 'bonus' ? { kind: 'BONUS' } : {}) },
+ include: { client: { include: { user: true } }, category: true, bonusType: true },
+ orderBy: { createdAt: 'desc' },
+ take: input.take,
+ })
+ : [],
+ want('redemption') && !input.categoryId
+ ? ctx.db.pointsRedemption.findMany({ where: { clientId: input.clientId, confirmedById: input.adminId, channel: input.channel, status: { in: ['CONFIRMED', 'REVERSED', 'REJECTED'] }, requestedAt: at }, include: { client: { include: { user: true } }, order: { select: { number: true } } }, orderBy: { requestedAt: 'desc' }, take: input.take })
+ : [],
+ want('reversal') && !input.categoryId ? ctx.db.pointsReversal.findMany({ where: { clientId: input.clientId, createdById: input.adminId, channel: input.channel, createdAt: at }, orderBy: { createdAt: 'desc' }, take: input.take }) : [],
+ ctx.db.adminUser.findMany({ select: { id: true, name: true } }),
+ ]);
+ const adminName = new Map(admins.map((a) => [a.id, a.name]));
+ const revClients = rev.length ? new Map((await ctx.db.client.findMany({ where: { id: { in: [...new Set(rev.map((r) => r.clientId))] } }, include: { user: true } })).map((c) => [c.id, name(c.user)])) : new Map();
+ const rows = [
+ ...acc.map((a) => {
+ const diff = a.suggestedAmount ? Math.abs(a.amount - a.suggestedAmount) / Math.max(1, a.suggestedAmount) : 0;
+ return {
+ id: a.id,
+ at: a.createdAt,
+ type: a.kind === 'BONUS' ? ('bonus' as const) : ('accrual' as const),
+ clientId: a.clientId,
+ client: name(a.client.user),
+ amount: a.amount,
+ suggested: a.suggestedAmount,
+ highlight: a.kind === 'ORDER' && diff * 100 > s['points.diffHighlightPct'],
+ status: a.status as string,
+ what: a.kind === 'BONUS' ? ((a.bonusType?.name as Record) ?? null) : ((a.category?.name as Record) ?? null),
+ orderRef: a.orderRef,
+ orderAmount: a.orderAmount,
+ tier: a.tier,
+ ratePct: a.ratePct,
+ author: a.createdById ? (adminName.get(a.createdById) ?? '—') : null,
+ channel: a.channel as string,
+ reason: a.reason,
+ comment: a.commentForClient,
+ canReverse: a.status === 'PENDING' || a.status === 'ACTIVE',
+ };
+ }),
+ ...red.map((r) => ({
+ id: r.id,
+ at: r.confirmedAt ?? r.requestedAt,
+ type: 'redemption' as const,
+ clientId: r.clientId,
+ client: name(r.client.user),
+ amount: -r.amount,
+ suggested: null,
+ highlight: false,
+ status: r.status as string,
+ what: null,
+ orderRef: r.order ? `#${r.order.number}` : r.orderRef,
+ orderAmount: r.orderAmount,
+ tier: null,
+ ratePct: null,
+ author: r.confirmedById ? (adminName.get(r.confirmedById) ?? '—') : null,
+ channel: r.channel as string,
+ reason: r.reason,
+ comment: r.note,
+ canReverse: r.status === 'CONFIRMED',
+ })),
+ ...rev.map((r) => ({
+ id: r.id,
+ at: r.createdAt,
+ type: 'reversal' as const,
+ clientId: r.clientId,
+ client: revClients.get(r.clientId) ?? '—',
+ amount: r.targetType === 'ACCRUAL' ? -r.amount : r.amount,
+ suggested: null,
+ highlight: r.debt > 0,
+ status: r.targetType,
+ what: null,
+ orderRef: null,
+ orderAmount: null,
+ tier: null,
+ ratePct: null,
+ author: r.createdById ? (adminName.get(r.createdById) ?? '—') : null,
+ channel: r.channel as string,
+ reason: r.reason,
+ comment: r.debt > 0 ? `debt:${r.debt}` : null,
+ canReverse: false,
+ })),
+ ];
+ return rows.sort((a, b) => b.at.getTime() - a.at.getTime()).slice(0, input.take);
+ }),
+
+ /** CSV: телефон, категория, сумма заказа, дата, номер заказа. dryRun — предпросмотр с ошибками */
+ import: pointsProcedure
+ .input(z.object({ dryRun: z.boolean(), rows: z.array(z.object({ phone: z.string().max(40), category: z.string().max(40), orderAmount: z.number().int().min(0), date: z.string().max(20), orderRef: z.string().max(60) })).max(1000) }))
+ .mutation(async ({ ctx, input }) => {
+ const s = await getSettings(ctx.db);
+ const now = ctx.svc.now();
+ const cats = await ctx.db.pointsCategory.findMany();
+ const seen = new Set();
+ const out: { line: number; clientId?: string; client?: string; amount?: number; error?: string }[] = [];
+ for (const [i, r] of input.rows.entries()) {
+ const line = i + 1;
+ const digits = r.phone.replace(/[^\d]/g, '');
+ const cat = cats.find((c) => c.code === r.category.trim().toLowerCase() || Object.values(c.name as Record).some((n) => n.toLowerCase() === r.category.trim().toLowerCase()));
+ const date = new Date(`${r.date.trim()}T12:00:00+04:00`);
+ const ref = r.orderRef.trim();
+ if (!cat) {
+ out.push({ line, error: 'category' });
+ continue;
+ }
+ if (Number.isNaN(date.getTime())) {
+ out.push({ line, error: 'date' });
+ continue;
+ }
+ const users = digits.length >= 8 ? await ctx.db.user.findMany({ where: { phone: { endsWith: digits.slice(-8) } }, include: { client: true } }) : [];
+ const cl = users.find((u) => u.client)?.client;
+ if (!cl) {
+ out.push({ line, error: 'client' });
+ continue;
+ }
+ if (!ref || seen.has(ref) || (await ctx.db.pointsAccrual.findFirst({ where: { orderRef: ref, status: { not: 'REVERSED' } } }))) {
+ out.push({ line, error: 'duplicate' });
+ continue;
+ }
+ seen.add(ref);
+ const p = await previewAccrual(ctx.db, { clientId: cl.id, categoryId: cat.id, orderAmount: r.orderAmount, serviceDate: date }, s, now);
+ const u = users.find((x) => x.client)!;
+ if (!input.dryRun) {
+ await accruePoints(ctx.svc, { clientId: cl.id, kind: 'ORDER', categoryId: cat.id, orderAmount: r.orderAmount, orderRef: ref, serviceDate: date, channel: 'CSV', idempotencyKey: `csv:${ref}` }, ctx.actor);
+ }
+ out.push({ line, clientId: cl.id, client: name(u), amount: p.suggested });
+ }
+ return { rows: out, total: out.reduce((sum, r) => sum + (r.amount ?? 0), 0), errors: out.filter((r) => r.error).length };
+ }),
+
+ /** Очередь «Предложено системой» */
+ suggestions: pointsProcedure.query(async ({ ctx }) => {
+ const list = await ctx.db.pointsSuggestion.findMany({ where: { status: 'OPEN' }, orderBy: { createdAt: 'asc' }, include: { client: { include: { user: true } } }, take: 200 });
+ const admins = new Map((await ctx.db.adminUser.findMany({ select: { id: true, name: true } })).map((a) => [a.id, a.name]));
+ return list.map((x) => {
+ const p = x.payload as Record;
+ return { id: x.id, clientId: x.clientId, name: name(x.client.user), mechanic: x.mechanic, amount: x.suggestedAmount, payload: p, by: typeof p.adminId === 'string' ? (admins.get(p.adminId) ?? null) : null, createdAt: x.createdAt };
+ });
+ }),
+ acceptSuggestion: superProcedure
+ .input(z.object({ id: z.string(), amount: z.number().int().min(1).optional(), reason: z.string().trim().max(500).nullable().optional() }))
+ .mutation(({ ctx, input }) => acceptSuggestion(ctx.svc, input, { adminId: ctx.admin.id, owner: true })),
+ rejectSuggestion: superProcedure.input(z.object({ id: z.string(), reason: z.string().trim().min(1).max(500) })).mutation(({ ctx, input }) => rejectSuggestion(ctx.svc, input, { adminId: ctx.admin.id, owner: true })),
+
+ /** Справочники — только суперадмин */
+ saveCategory: superProcedure
+ .input(z.object({ id: z.string().optional(), code: z.string().trim().regex(/^[a-z_]{2,30}$/), name: L5, rateBarev: z.number().int().min(0).max(100), ratePlus: z.number().int().min(0).max(100), rateElite: z.number().int().min(0).max(100), active: z.boolean(), sortOrder: z.number().int().default(0) }))
+ .mutation(async ({ ctx, input }) => {
+ const { id, ...data } = input;
+ return id ? ctx.db.pointsCategory.update({ where: { id }, data }) : ctx.db.pointsCategory.create({ data });
+ }),
+ saveBonusType: superProcedure
+ .input(z.object({ id: z.string().optional(), code: z.string().trim().regex(/^[a-z_]{2,30}$/), name: L5, defaultAmount: z.number().int().min(0), ttlDays: z.number().int().min(1).max(1000).nullable(), active: z.boolean(), sortOrder: z.number().int().default(0) }))
+ .mutation(async ({ ctx, input }) => {
+ const { id, ...data } = input;
+ return id ? ctx.db.pointsBonusType.update({ where: { id }, data }) : ctx.db.pointsBonusType.create({ data });
+ }),
+
+ /** Отчёт за период: начислено, потрачено, сгорело, отменено, обязательства, redemption rate, повторные заказы, топы */
+ report: superProcedure
+ .input(z.object({ from: z.coerce.date(), to: z.coerce.date(), categoryId: z.string().optional(), agencyId: z.string().optional() }))
+ .query(async ({ ctx, input }) => {
+ const at = { gte: input.from, lt: input.to };
+ const clientWhere = input.agencyId ? { agencyId: input.agencyId } : {};
+ const accWhere = { createdAt: at, categoryId: input.categoryId, client: clientWhere };
+ const [accrued, spent, expired, reversed, liabilities, byCategory, topClients, topAgencies, payers] = await Promise.all([
+ ctx.db.pointsAccrual.aggregate({ where: accWhere, _sum: { amount: true } }),
+ ctx.db.pointsRedemption.aggregate({ where: { status: 'CONFIRMED', confirmedAt: at, client: clientWhere }, _sum: { amount: true } }),
+ // сгоревшее — по начислениям этого периода (дату сгорания журнал хранит в статусе)
+ ctx.db.pointsAccrual.aggregate({ where: { ...accWhere, expiredAmount: { gt: 0 } }, _sum: { expiredAmount: true } }),
+ ctx.db.pointsReversal.aggregate({ where: { targetType: 'ACCRUAL', createdAt: at }, _sum: { amount: true } }),
+ ctx.db.pointsAccrual.aggregate({ where: { status: { in: ['ACTIVE', 'PENDING'] }, categoryId: input.categoryId, client: clientWhere }, _sum: { remaining: true } }),
+ ctx.db.$queryRaw<{ code: string; name: Record; points: number; revenue: number }[]>`
+ SELECT pc.code, pc.name, COALESCE(SUM(a.amount),0)::int AS points, COALESCE(SUM(COALESCE(a."orderAmount",0) - a."excludedAmount" - a."paidWithPoints"),0)::int AS revenue
+ FROM "PointsAccrual" a JOIN "PointsCategory" pc ON pc.id = a."categoryId"
+ WHERE a.kind = 'ORDER' AND a.status <> 'REVERSED' AND a."createdAt" >= ${input.from} AND a."createdAt" < ${input.to}
+ GROUP BY pc.code, pc.name`,
+ ctx.db.client.findMany({ where: { pointsActive: { gt: 0 }, ...clientWhere }, orderBy: { pointsActive: 'desc' }, take: 10, include: { user: true } }),
+ ctx.db.$queryRaw<{ name: string; n: number }[]>`
+ SELECT ag.name, COUNT(*)::int AS n FROM "PointsAccrual" a
+ JOIN "PointsBonusType" bt ON bt.id = a."bonusTypeId" AND bt.code = 'housewarming'
+ JOIN "Client" c ON c.id = a."clientId" JOIN "Agency" ag ON ag.id = c."agencyId"
+ WHERE a."createdAt" >= ${input.from} AND a."createdAt" < ${input.to}
+ GROUP BY ag.name ORDER BY n DESC LIMIT 10`,
+ // повторный заказ за 30 дней: у клиентов с бариками и без
+ ctx.db.$queryRaw<{ with_points: boolean; clients: number; repeat: number; multi: number }[]>`
+ WITH firsts AS (
+ SELECT o."clientId", MIN(o."createdAt") AS first_at, COUNT(DISTINCT s."pointsCategoryId") AS cats
+ FROM "Order" o JOIN "Service" s ON s.id = o."serviceId"
+ WHERE o.status <> 'CANCELLED' AND o."createdAt" >= ${input.from} AND o."createdAt" < ${input.to}
+ GROUP BY o."clientId"
+ )
+ SELECT (c."pointsActive" + c."pointsPending" > 0 OR EXISTS (SELECT 1 FROM "PointsAccrual" a WHERE a."clientId" = f."clientId")) AS with_points,
+ COUNT(*)::int AS clients,
+ COUNT(*) FILTER (WHERE EXISTS (SELECT 1 FROM "Order" o2 WHERE o2."clientId" = f."clientId" AND o2.status <> 'CANCELLED' AND o2."createdAt" > f.first_at AND o2."createdAt" <= f.first_at + interval '30 days'))::int AS repeat,
+ COUNT(*) FILTER (WHERE f.cats >= 2)::int AS multi
+ FROM firsts f JOIN "Client" c ON c.id = f."clientId"
+ GROUP BY 1`,
+ ]);
+ const a = accrued._sum.amount ?? 0;
+ const sp = spent._sum.amount ?? 0;
+ return {
+ accrued: a,
+ spent: sp,
+ expired: expired._sum.expiredAmount ?? 0,
+ reversed: reversed._sum.amount ?? 0,
+ liabilities: liabilities._sum.remaining ?? 0,
+ redemptionRate: a ? Math.round((sp / a) * 1000) / 10 : 0,
+ byCategory: byCategory.map((c) => ({ ...c, costPct: c.revenue ? Math.round((c.points / c.revenue) * 1000) / 10 : 0 })),
+ topClients: topClients.map((c) => ({ id: c.id, name: name(c.user), balance: c.pointsActive })),
+ topAgencies,
+ retention: payers.map((p) => ({ withPoints: p.with_points, clients: p.clients, repeatPct: p.clients ? Math.round((p.repeat / p.clients) * 1000) / 10 : 0, multi: p.multi })),
+ };
+ }),
+});
diff --git a/apps/api/src/routers/backoffice/providers.ts b/apps/api/src/routers/backoffice/providers.ts
index bca09ae..a4828e0 100644
--- a/apps/api/src/routers/backoffice/providers.ts
+++ b/apps/api/src/routers/backoffice/providers.ts
@@ -2,7 +2,7 @@ import { randomBytes } from 'node:crypto';
import { averageRating, DAY, LOCALES, PROVIDER_ROLES, startOfYerevanDay } from '@barev/core';
import type { Prisma } from '@barev/db';
-import { orderPayout, rateLabel } from '@barev/services';
+import { getSettings, orderPayout, rateLabel } from '@barev/services';
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { env } from '../../env.ts';
@@ -30,7 +30,7 @@ const profileInput = z.object({
rate: z.object({ rateType: z.enum(['FIXED', 'PERCENT']), rateValue: z.number().int().min(0), payoutPresetId: z.string().nullable() }).optional(),
});
-const payoutInclude = { company: { select: { rateType: true, rateValue: true } }, payoutPreset: { select: { name: true, rules: true } } } as const;
+const payoutInclude = { company: { select: { deal: true, fotPct: true } }, payoutPreset: { select: { name: true, rules: true } } } as const;
export const boProvidersRouter = router({
list: providersProcedure
@@ -97,7 +97,7 @@ export const boProvidersRouter = router({
where: { id: input.id },
include: {
...payoutInclude,
- company: { select: { id: true, name: true, rateType: true, rateValue: true } },
+ company: { select: { id: true, name: true, deal: true, fotPct: true } },
user: { select: { username: true, firstName: true } },
districts: true,
schedule: { orderBy: [{ weekday: 'asc' }, { startMinute: 'asc' }] },
@@ -127,19 +127,20 @@ export const boProvidersRouter = router({
// деньги: заработано (по ставке исполнителя) минус выплачено = к выплате
let money = null;
if (ctx.isSuper) {
+ const fot = { fotPct: (await getSettings(ctx.db))['partner.fotPct'] };
const monthStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
const prevMonthStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, 1));
const [doneAll, payouts] = await Promise.all([
ctx.db.order.findMany({ where: { providerId: p.id, ...DONE }, select: { completedAt: true, totalPrice: true, basePrice: true, params: true, priceBreakdown: true, service: { select: { pricing: true, paramsSchema: true } } } }),
ctx.db.payout.findMany({ where: { providerId: p.id }, orderBy: { createdAt: 'desc' } }),
]);
- const earn = doneAll.map((o) => ({ at: o.completedAt!, sum: orderPayout(o, p) }));
+ const earn = doneAll.map((o) => ({ at: o.completedAt!, sum: orderPayout(o, p, fot) }));
const sum = (f: (x: (typeof earn)[number]) => boolean) => earn.filter(f).reduce((s, x) => s + x.sum, 0);
const earnedTotal = sum(() => true);
const paidTotal = payouts.filter((x) => x.status === 'PAID').reduce((s, x) => s + x.amount, 0);
const admins = new Map((await ctx.db.adminUser.findMany({ where: { id: { in: payouts.map((x) => x.createdById).filter((x): x is string => !!x) } }, select: { id: true, name: true } })).map((a) => [a.id, a.name]));
money = {
- rate: rateLabel(p),
+ rate: rateLabel(p, fot),
thisMonth: sum((x) => x.at >= monthStart),
prevMonth: sum((x) => x.at >= prevMonthStart && x.at < monthStart),
earnedTotal,
diff --git a/apps/api/src/routers/client.ts b/apps/api/src/routers/client.ts
index f71f130..7b85c70 100644
--- a/apps/api/src/routers/client.ts
+++ b/apps/api/src/routers/client.ts
@@ -1,5 +1,9 @@
import { defaultParams, discountFor, LOCALES } from '@barev/core';
import { rateOrder,
+ clientPoints,
+ pointsHistory,
+ redeemQuote,
+ requestRedemption,
applyAgencyCode,
availableSlots,
cancelByClient,
@@ -54,6 +58,8 @@ export const clientRouter = router({
membership,
agencyName: agency?.name ?? null,
giftUsed: !!ctx.client.giftUsedAt,
+ /** барики: доступный баланс */
+ points: ctx.client.pointsActive,
cardCode: ctx.client.cardCode,
barevPlusPrice: settings['barevPlus.monthlyPrice'],
freeCancelHours: settings['cancel.freeHours'],
@@ -185,7 +191,9 @@ export const clientRouter = router({
.input(z.object({ serviceCode: z.string(), params: paramsInput, promoCode: z.string().trim().max(40).optional() }))
.query(async ({ ctx, input }) => {
const r = await quoteForClient(ctx.svc, ctx.client.id, input.serviceCode, input.params, input.promoCode);
- return { ...r.quote, promo: r.promo ? { code: r.promo.code, discountPct: r.promo.discountPct } : null };
+ // барики: сколько можно списать в этом заказе (с промокодом — нельзя)
+ const points = await redeemQuote(ctx.db, ctx.client.id, r.quote.totalPrice, await getSettings(ctx.db));
+ return { ...r.quote, promo: r.promo ? { code: r.promo.code, discountPct: r.promo.discountPct } : null, points };
}),
/** ORD-3 */
@@ -212,6 +220,8 @@ export const clientRouter = router({
repeatOfId: z.string().optional(),
/** промокод: применится, если выгоднее скидки подписки */
promoCode: z.string().trim().max(40).optional(),
+ /** оплатить часть бариками (с промокодом нельзя) */
+ usePoints: z.number().int().min(0).max(10_000_000).optional(),
}),
)
.mutation(async ({ ctx, input }) => {
@@ -219,6 +229,18 @@ export const clientRouter = router({
return { id: order.id, number: order.number };
}),
+ /** Барики: экран, история, запрос на оплату заказа вне приложения или уже созданного заказа */
+ points: router({
+ summary: clientProcedure.query(({ ctx }) => clientPoints(ctx.svc, ctx.client.id)),
+ history: clientProcedure.input(z.object({ before: z.date().optional() }).optional()).query(({ ctx, input }) => pointsHistory(ctx.db, ctx.client.id, { take: 30, before: input?.before })),
+ request: consentedClientProcedure
+ .input(z.object({ amount: z.number().int().min(1).max(10_000_000), orderId: z.string().optional(), note: z.string().trim().max(300).optional() }))
+ .mutation(async ({ ctx, input }) => {
+ const r = await requestRedemption(ctx.svc, { clientId: ctx.client.id, ...input });
+ return { id: r.id };
+ }),
+ }),
+
orders: router({
list: clientProcedure.query(({ ctx }) => listClientOrders(ctx.db, ctx.client.id)),
get: clientProcedure.input(z.object({ id: z.string() })).query(({ ctx, input }) => clientOrder(ctx.db, ctx.client.id, input.id)),
diff --git a/apps/api/src/routers/pro.ts b/apps/api/src/routers/pro.ts
index e525108..75b73c9 100644
--- a/apps/api/src/routers/pro.ts
+++ b/apps/api/src/routers/pro.ts
@@ -16,13 +16,38 @@ import {
partnerCabinet,
redeemOffer,
removePartnerMember,
+ companyStaffCandidates,
+ exchangeProWebLogin,
+ getSettings,
+ partnerAddStaff,
+ partnerCabinetData,
+ partnerDeclineOrder,
+ partnerRemoveManager,
+ partnerResetStaffInvite,
+ partnerSaveSettings,
+ partnerUnassign,
+ partnerUpdateStaff,
+ revokeProWebSession,
} from '@barev/services';
+import { LOCALES } from '@barev/core';
+import { env } from '../env.ts';
import { TRPCError } from '@trpc/server';
import { z } from 'zod';
import { signedUrl } from '../infra.ts';
-import { proUserProcedure, providerProcedure, router } from '../trpc.ts';
+import { proUserProcedure, providerProcedure, publicProcedure, router } from '../trpc.ts';
const dateKey = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
+const botLink = (code: string) => `https://t.me/${env.PRO_BOT_USERNAME}?start=${code}`;
+const staffInput = z.object({
+ name: z.string().trim().min(1).max(100),
+ phone: z.string().trim().max(30).nullable().optional(),
+ languages: z.array(z.enum(LOCALES)).min(1),
+ districtIds: z.array(z.string()).max(30),
+ schedule: z.array(z.object({ weekday: z.number().int().min(0).max(6), startMinute: z.number().int().min(0).max(1440), endMinute: z.number().int().min(0).max(1440) })).max(21),
+ maxOrdersPerDay: z.number().int().min(0).max(20).nullable().optional(),
+ maxHoursPerDay: z.number().int().min(0).max(24).nullable().optional(),
+});
+const co = z.object({ companyId: z.string() });
/** Кабинет партнёра клуба: собственник и сотрудники */
const partnerRouter = router({
@@ -50,6 +75,7 @@ export const proRouter = router({
: null,
companies: ctx.identity.companies.map((c) => ({ id: c.id, name: c.name })),
partners: ctx.identity.partners,
+ web: ctx.web,
};
}),
@@ -98,15 +124,52 @@ export const proRouter = router({
return { url: await signedUrl(file.storageKey) };
}),
- /** PRO-7: диспетчер компании */
+ /** Вход в кабинет из браузера: одноразовый код из бота → токен на 30 дней */
+ webLogin: publicProcedure.input(z.object({ code: z.string().min(10).max(100) })).mutation(async ({ ctx, input }) => ({ token: await exchangeProWebLogin(ctx.svc, input.code) })),
+ webLogout: publicProcedure.mutation(async ({ ctx }) => {
+ const auth = ctx.req.headers.authorization;
+ if (auth?.startsWith('pro ')) await revokeProWebSession(ctx.db, auth.slice(4));
+ }),
+
+ /** PRO-7: менеджер партнёра (диспетчер компании) */
dispatcher: router({
board: proUserProcedure.input(z.object({ companyId: z.string() })).query(({ ctx, input }) => companyBoard(ctx.svc, input.companyId, ctx.identity.user.id)),
+ /** Кабинет: заказы, сотрудники, доход, настройки */
+ cabinet: proUserProcedure.input(co).query(async ({ ctx, input }) => {
+ const d = await partnerCabinetData(ctx.svc, input.companyId, ctx.identity.user.id);
+ return {
+ ...d,
+ company: { ...d.company, managerInvite: undefined, managerLink: botLink(d.company.managerInvite) },
+ staff: d.staff.map((p) => ({ ...p, inviteCode: undefined, inviteLink: p.inviteCode ? botLink(p.inviteCode) : null })),
+ };
+ }),
staffForOrder: proUserProcedure.input(z.object({ companyId: z.string(), orderId: z.string() })).query(async ({ ctx, input }) => {
if (!ctx.identity.companies.some((c) => c.id === input.companyId)) throw new TRPCError({ code: 'FORBIDDEN' });
- return companyStaffForOrder(ctx.svc, input.companyId, input.orderId);
+ const order = await ctx.db.order.findUnique({ where: { id: input.orderId }, select: { companyId: true } });
+ if (order?.companyId !== input.companyId) throw new TRPCError({ code: 'NOT_FOUND' });
+ return companyStaffCandidates(ctx.db, input.companyId, input.orderId, await getSettings(ctx.db));
}),
assign: proUserProcedure
.input(z.object({ companyId: z.string(), orderId: z.string(), providerId: z.string() }))
.mutation(({ ctx, input }) => dispatcherAssign(ctx.svc, { ...input, dispatcherUserId: ctx.identity.user.id })),
+ /** Отказаться от заказа — он вернётся оператору */
+ decline: proUserProcedure.input(co.extend({ orderId: z.string() })).mutation(({ ctx, input }) => partnerDeclineOrder(ctx.svc, { ...input, userId: ctx.identity.user.id })),
+ /** Снять сотрудника с заказа (переназначить) */
+ unassign: proUserProcedure.input(co.extend({ orderId: z.string() })).mutation(({ ctx, input }) => partnerUnassign(ctx.svc, { ...input, userId: ctx.identity.user.id })),
+ addStaff: proUserProcedure.input(co.extend({ staff: staffInput })).mutation(async ({ ctx, input }) => {
+ const r = await partnerAddStaff(ctx.svc, { companyId: input.companyId, userId: ctx.identity.user.id, staff: input.staff });
+ return { id: r.id, inviteLink: botLink(r.inviteCode) };
+ }),
+ updateStaff: proUserProcedure
+ .input(co.extend({ providerId: z.string(), staff: staffInput, active: z.boolean().optional() }))
+ .mutation(({ ctx, input }) => partnerUpdateStaff(ctx.svc, { ...input, userId: ctx.identity.user.id })),
+ resetStaffInvite: proUserProcedure.input(co.extend({ providerId: z.string() })).mutation(async ({ ctx, input }) => {
+ const r = await partnerResetStaffInvite(ctx.svc, { ...input, userId: ctx.identity.user.id });
+ return { inviteLink: botLink(r.inviteCode) };
+ }),
+ saveSettings: proUserProcedure
+ .input(co.extend({ autoAssign: z.boolean(), travelGapMinutes: z.number().int().min(0).max(240) }))
+ .mutation(({ ctx, input }) => partnerSaveSettings(ctx.svc, { ...input, userId: ctx.identity.user.id })),
+ removeManager: proUserProcedure.input(co.extend({ managerId: z.string() })).mutation(({ ctx, input }) => partnerRemoveManager(ctx.svc, { ...input, userId: ctx.identity.user.id })),
}),
});
diff --git a/apps/api/src/routers/public.ts b/apps/api/src/routers/public.ts
index bfb79d4..17d3dd7 100644
--- a/apps/api/src/routers/public.ts
+++ b/apps/api/src/routers/public.ts
@@ -83,9 +83,10 @@ export const publicRouter = router({
.input(
z.object({
params: z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.record(z.string(), z.number().int().min(0))])),
- preferredAt: z.iso.datetime().transform((v) => new Date(v)),
- districtCode: z.string().max(40),
- addressText: z.string().max(300),
+ // обязательны только параметры уборки и телефон; остальное бот доспросит или уточнит оператор
+ preferredAt: z.iso.datetime().transform((v) => new Date(v)).optional(),
+ districtCode: z.string().max(40).optional(),
+ addressText: z.string().max(300).optional(),
note: z.string().max(1000).optional(),
phone: z.string().max(30),
name: z.string().max(80).optional(),
diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts
index 4ebce3c..9b0b3b6 100644
--- a/apps/api/src/server.ts
+++ b/apps/api/src/server.ts
@@ -4,7 +4,7 @@ import multipart, { type MultipartFile } from '@fastify/multipart';
import * as Sentry from '@sentry/node';
import { fastifyTRPCPlugin, type FastifyTRPCPluginOptions } from '@trpc/server/adapters/fastify';
import { getFlow } from '@barev/core';
-import { DomainError, getClientByTelegramId, proIdentity, receiveMessage, setChecklistItem, staffSend, startTextOverrides } from '@barev/services';
+import { DomainError, getClientByTelegramId, proIdentity, receiveMessage, setChecklistItem, staffChecklistItem, staffSend, startTextOverrides } from '@barev/services';
import { getFile, putFile } from '@barev/services/storage';
import { TelegramSender } from '@barev/services/telegram';
import Fastify, { type FastifyReply, type FastifyRequest } from 'fastify';
@@ -187,6 +187,29 @@ app.post<{ Params: { providerId: string } }>('/files/bo/provider-doc/:providerId
return { id: doc.id };
});
+/** Команда загружает фото к пункту чек-листа за исполнителя и отмечает пункт */
+app.post<{ Params: { orderId: string } }>('/files/bo/checklist-photo/:orderId', async (req, reply) => {
+ const staff = await staffFromCookie(req);
+ if (!staff || !canDispatch(staff)) return reply.code(staff ? 403 : 401).send({ error: staff ? 'ROLE_FORBIDDEN' : 'ADMIN_LOGIN_REQUIRED' });
+ const order = await db.order.findUnique({ where: { id: req.params.orderId } });
+ if (!order) return reply.code(404).send({ error: 'NOT_FOUND' });
+ const part = await req.file();
+ if (!part) return reply.code(400).send({ error: 'NO_FILE' });
+ const code = multipartField(part, 'code');
+ if (!code) return reply.code(400).send({ error: 'BAD_INPUT' });
+ if (!IMAGE_TYPES.has(part.mimetype)) return reply.code(400).send({ error: 'BAD_FILE_TYPE' });
+ const body = await part.toBuffer();
+ const key = await putObject(`orders/${order.id}`, body, part.mimetype);
+ const file = await db.orderFile.create({ data: { orderId: order.id, kind: 'PHOTO_REPORT', storageKey: key, mime: part.mimetype, size: body.length, uploadedBy: 'ADMIN', uploadedById: staff.admin.id } });
+ try {
+ await staffChecklistItem(svc, { orderId: order.id, adminId: staff.admin.id, code, checked: true, fileId: file.id });
+ } catch (e) {
+ if (e instanceof DomainError) return reply.code(400).send({ error: e.code });
+ throw e;
+ }
+ return { fileId: file.id };
+});
+
app.get<{ Params: { docId: string } }>('/files/bo/provider-doc-file/:docId', async (req, reply) => {
const staff = await staffFromCookie(req);
if (!staff || !canDispatch(staff)) return reply.code(404).send({ error: 'NOT_FOUND' });
diff --git a/apps/api/src/trpc.ts b/apps/api/src/trpc.ts
index 58bd2c3..b624320 100644
--- a/apps/api/src/trpc.ts
+++ b/apps/api/src/trpc.ts
@@ -2,7 +2,7 @@
import type {} from '@fastify/cookie';
import type { FastifyReply, FastifyRequest } from 'fastify';
import { initTRPC, TRPCError } from '@trpc/server';
-import { DomainError, getClientByTelegramId, proIdentity, startClient } from '@barev/services';
+import { DomainError, getClientByTelegramId, proIdentity, proWebSessionUser, startClient } from '@barev/services';
import superjson from 'superjson';
import { ZodError } from 'zod';
import { ADMIN_COOKIE, findSession } from './auth/admin.ts';
@@ -86,12 +86,21 @@ export const consentedClientProcedure = clientProcedure.use(async ({ ctx, next }
/** Mini App исполнителя: initData бота исполнителей; пользователь должен быть привязан инвайтом */
export const proUserProcedure = publicProcedure.use(async ({ ctx, next }) => {
+ // кабинет менеджера партнёра в браузере: токен вместо initData (вход по одноразовой ссылке из бота)
+ const auth = ctx.req.headers.authorization;
+ if (auth?.startsWith('pro ')) {
+ const telegramId = await proWebSessionUser(ctx.db, auth.slice(4), ctx.svc.now());
+ if (!telegramId) throw new TRPCError({ code: 'UNAUTHORIZED', message: 'WEB_SESSION_EXPIRED' });
+ const identity = await proIdentity(ctx.db, telegramId);
+ if (!identity || (!identity.provider && identity.companies.length === 0 && identity.partners.length === 0)) throw new TRPCError({ code: 'FORBIDDEN', message: 'NOT_LINKED' });
+ return next({ ctx: { tgUser: { id: Number(telegramId), first_name: identity.user.firstName ?? '' }, identity, web: true } });
+ }
const init = checkInitData(ctx.req, env.proBotToken);
const identity = await proIdentity(ctx.db, BigInt(init.user.id));
if (!identity || (!identity.provider && identity.companies.length === 0 && identity.partners.length === 0)) {
throw new TRPCError({ code: 'FORBIDDEN', message: 'NOT_LINKED' });
}
- return next({ ctx: { tgUser: init.user, identity } });
+ return next({ ctx: { tgUser: init.user, identity, web: false } });
});
export const providerProcedure = proUserProcedure.use(async ({ ctx, next }) => {
diff --git a/apps/backoffice/src/App.tsx b/apps/backoffice/src/App.tsx
index 358e639..35a4e4c 100644
--- a/apps/backoffice/src/App.tsx
+++ b/apps/backoffice/src/App.tsx
@@ -19,6 +19,8 @@ import { Crm } from './pages/Crm.tsx';
import { LeadCard } from './pages/LeadCard.tsx';
import { AgencyCard, Agencies } from './pages/Agencies.tsx';
import { VenueCard, Venues } from './pages/Venues.tsx';
+import { ServicePartnerCard, ServicePartners } from './pages/ServicePartners.tsx';
+import { Points } from './pages/Points.tsx';
import { Products, ServiceEditor } from './pages/Products.tsx';
import { Broadcasts, Journal, Settings } from './pages/Admin5.tsx';
import { MoveCard, Moves, Requests } from './pages/Moves.tsx';
@@ -57,7 +59,9 @@ const NAV: NavItem[] = [
{ path: '/chats', key: 'nav.chats', icon: 'chats', roles: ['SUPPORT', 'CONCIERGE'], count: 'chats' },
{ path: '/orders', key: 'nav.orders', icon: 'orders', roles: ['SUPPORT', 'CONCIERGE'], count: 'orders' },
{ path: '/providers', key: 'nav.providers', icon: 'providers', roles: ['SUPPORT'], group: 'work' },
+ { path: '/points', key: 'nav.points', icon: 'gift', roles: [], group: 'work' },
{ path: '/agencies', key: 'nav.agencies', icon: 'agencies', roles: [], group: 'partners' },
+ { path: '/service-partners', key: 'nav.servicePartners', icon: 'providers', roles: [], group: 'partners' },
{ path: '/venues', key: 'nav.venues', icon: 'venues', roles: [], group: 'partners' },
{ path: '/crm', key: 'nav.crm', icon: 'crm', roles: ['SALES'], group: 'partners' },
{ path: '/products', key: 'nav.products', icon: 'products', roles: ['SUPPORT'], group: 'setup' },
@@ -95,6 +99,7 @@ function Shell({ me }: { me: Me }) {
const leadId = match('/crm/:id', path)?.id;
const agencyId = match('/agencies/:id', path)?.id;
const venueId = match('/venues/:id', path)?.id;
+ const servicePartnerId = match('/service-partners/:id', path)?.id;
const canCrm = items.some((n) => n.path === '/crm');
const productId = match('/products/:id', path)?.id;
const canProducts = items.some((n) => n.path === '/products');
@@ -112,6 +117,9 @@ function Shell({ me }: { me: Me }) {
else if (leadId && canCrm) page = ;
else if (path === '/agencies' && isSuper) page = ;
else if (agencyId && isSuper) page = ;
+ else if (path === '/points' && isSuper) page = ;
+ else if (path === '/service-partners' && isSuper) page = ;
+ else if (servicePartnerId && isSuper) page = ;
else if (path === '/venues' && isSuper) page = ;
else if (venueId && isSuper) page = ;
else if (path === '/products' && canProducts) page = ;
diff --git a/apps/backoffice/src/admin5.css b/apps/backoffice/src/admin5.css
index 316cbfa..703f8dc 100644
--- a/apps/backoffice/src/admin5.css
+++ b/apps/backoffice/src/admin5.css
@@ -123,3 +123,40 @@
border-radius: 16px;
background: var(--bo-soft);
}
+
+/* ───── барики ───── */
+.bo-pt-tabs {
+ margin-bottom: 16px;
+ overflow-x: auto;
+}
+.bo-pt-tabs button {
+ flex: none;
+ padding: 0 14px;
+}
+.bo-pt-pick {
+ cursor: pointer;
+ border-radius: 14px;
+}
+.bo-pt-pick[data-on] {
+ background: var(--bo-soft);
+}
+.bo-pt-filters {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ align-items: center;
+ padding: 8px;
+}
+.bo-pt-filters .bo-select,
+.bo-pt-filters .bo-input {
+ width: auto;
+ min-width: 140px;
+}
+.bo-table tr[data-hl] td {
+ background: color-mix(in srgb, var(--bc-perks) 45%, transparent);
+}
+.bo-alert--warn {
+ background: var(--bc-perks);
+ color: var(--bc-perks-ink);
+ cursor: default;
+}
diff --git a/apps/backoffice/src/i18n.tsx b/apps/backoffice/src/i18n.tsx
index 2f579fd..887ed82 100644
--- a/apps/backoffice/src/i18n.tsx
+++ b/apps/backoffice/src/i18n.tsx
@@ -43,8 +43,8 @@ const ru = {
'nav.chats': 'Чаты',
'nav.orders': 'Заказы',
'nav.providers': 'Исполнители',
- 'nav.agencies': 'Агентства',
- 'nav.venues': 'Заведения',
+ 'nav.agencies': 'Риэлторские агентства',
+ 'nav.venues': 'Партнёры клуба',
'nav.crm': 'CRM',
'nav.products': 'Продукты',
'nav.journal': 'Журнал',
@@ -656,7 +656,7 @@ const ru = {
'st.saveN': 'Сохранить ({n})',
'st.group.orders': 'Заказы',
'st.group.subs': 'Подписка',
- 'st.group.agencies': 'Агентства',
+ 'st.group.agencies': 'Риэлторские агентства',
'st.group.sales': 'Бонус продажников',
'st.group.site': 'Цены на сайте',
'st.group.other': 'Прочее',
@@ -809,22 +809,22 @@ const ru = {
'venue.cat.shop': 'Магазин',
'venue.cat.beauty': 'Красота',
'venue.cat.other': 'Другое',
- 'ag.title': 'Агентства',
- 'ag.add': 'Новое агентство',
- 'ag.editTitle': 'Агентство',
- 'ag.empty': 'Агентств пока нет.',
- 'ag.col.name': 'Агентство',
+ 'ag.title': 'Риэлторские агентства',
+ 'ag.add': 'Новое риэлторское агентство',
+ 'ag.editTitle': 'Риэлторское агентство',
+ 'ag.empty': 'Риэлторских агентств пока нет.',
+ 'ag.col.name': 'Риэлторское агентство',
'ag.col.clients': 'Клиенты',
'ag.col.gifts': 'Подарки',
'ag.col.month': 'Вознаграждение, месяц',
'ag.col.balance': 'К выплате',
'ag.hint': 'Вознаграждение — % от оплаченных заказов клиентов агентства, пока они закреплены за ним.',
'ag.inactive': 'выключено',
- 'ag.back': 'Все агентства',
+ 'ag.back': 'Все риэлторские агентства',
'ag.pct': '{n}% с заказов клиентов',
'ag.byS': 'подключил(а) {name}',
'ag.link': 'Ссылка для клиентов',
- 'ag.linkHint': 'По ссылке клиент открывает бота, получает подарочный месяц и закрепляется за агентством. Или вводит код {code} командой /code.',
+ 'ag.linkHint': 'По ссылке клиент открывает бота, получает подарок агентства и закрепляется за ним. Или вводит код {code} командой /code.',
'ag.clients': 'Клиенты',
'ag.giftsN': 'подарков: {n}',
'ag.noClients': 'Клиентов пока нет.',
@@ -838,7 +838,7 @@ const ru = {
'ag.sales': 'Подключил продажник',
'ag.contactPh': 'Имя, телефон, Telegram',
'ag.active': 'Агентство работает (код принимается)',
- 'vn.title': 'Заведения',
+ 'vn.title': 'Партнёры клуба',
'vn.add': 'Новое заведение',
'vn.editTitle': 'Заведение',
'vn.empty': 'Заведений пока нет.',
@@ -1169,6 +1169,279 @@ const ru = {
'audit.bo.chats.openFor': 'открыл(а) чат с клиентом',
'audit.bo.chats.templates.save': 'изменил(а) шаблон ответа',
'audit.bo.chats.templates.remove': 'удалил(а) шаблон ответа',
+ 'nav.servicePartners': 'Партнёры услуг',
+ 'st.group.partners': 'Партнёры услуг',
+ 'ag.giftPlan': 'Подарок новым клиентам',
+ 'ag.giftMonths': 'На сколько',
+ 'ag.giftHint': 'Действует для новых клиентов; у тех, кто уже получил подарок, ничего не меняется.',
+ 'ag.noGift': 'без подарка',
+ 'ag.giftValue': '{plan} на {n} мес.',
+ 'ag.monthsN': '{n} мес.',
+ 'ord.partner': 'партнёр',
+ 'ord.best': 'выгоднее всего',
+ 'ord.partnerFree': 'свободно {n} из {of}',
+ 'ord.candMoney': 'Платим {cost} · нам остаётся {margin}',
+ 'prv.ratePartnerPays': 'Зарплату платит партнёр',
+ 'rq.missing': 'не хватает данных',
+ 'rq.noTime': 'не указано',
+ 'rq.noDistrict': 'район не указан',
+ 'rq.noAddress': 'адрес не указан',
+ 'sp.title': 'Партнёры услуг',
+ 'sp.add': 'Новый партнёр',
+ 'sp.editTitle': 'Партнёр услуг',
+ 'sp.lead': 'Клининговые компании со своими сотрудниками. Менеджер партнёра получает ссылку, сам добавляет сотрудников и распределяет заказы. Заказ партнёру назначает оператор в карточке заказа.',
+ 'sp.empty': 'Партнёров пока нет.',
+ 'sp.col.name': 'Партнёр',
+ 'sp.col.staff': 'Сотрудники',
+ 'sp.col.active': 'Заказы в работе',
+ 'sp.col.month': 'Доход партнёра, месяц',
+ 'sp.col.balance': 'К выплате',
+ 'sp.noManager': 'нет менеджера',
+ 'sp.auto': 'автораспределение',
+ 'sp.back': 'Все партнёры услуг',
+ 'sp.terms.COMMISSION': 'как Uber: наши {pct}% с заказа',
+ 'sp.terms.PROFIT_SHARE': 'расходы наши: ФОТ {fot}%, налог {tax}%, партнёру {pct}% прибыли',
+ 'sp.managerLink': 'Ссылка для менеджера',
+ 'sp.managerLinkHint': 'Отдайте ссылку менеджеру партнёра: он откроет рабочий бот и получит кабинет — заказы, сотрудники, автораспределение, доход. Кабинет открывается и на компьютере (кнопка в боте).',
+ 'sp.resetLink': 'Новая ссылка',
+ 'sp.resetConfirm': 'Сделать новую ссылку? Старая перестанет работать, подключённые менеджеры останутся.',
+ 'sp.linkReset': 'Ссылка обновлена',
+ 'sp.managers': 'Менеджеры',
+ 'sp.noManagers': 'Менеджер ещё не подключился по ссылке.',
+ 'sp.managerSince': 'с {date}',
+ 'sp.remove': 'Убрать',
+ 'sp.removeManagerConfirm': 'Убрать {name} из менеджеров партнёра?',
+ 'sp.staff': 'Сотрудники',
+ 'sp.staffHint': 'добавляет менеджер партнёра',
+ 'sp.noStaff': 'Сотрудников пока нет.',
+ 'sp.limitOrders': 'до {n} заказов в день',
+ 'sp.limitHours': 'до {n} ч в день',
+ 'sp.notLinked': 'не вошёл в бот',
+ 'sp.off': 'выключен',
+ 'sp.orders': 'Заказы в работе',
+ 'sp.noOrders': 'Сейчас заказов у партнёра нет.',
+ 'sp.waitingStaff': 'ждёт сотрудника',
+ 'sp.toPay': 'Доход партнёра к выплате',
+ 'sp.byOrder': 'Доход по заказам',
+ 'sp.noIncome': 'Доход появится, когда клиент оплатит выполненный заказ.',
+ 'sp.paid': 'оплачено {sum}',
+ 'sp.fotTax': 'ФОТ {fot}, налог {tax}',
+ 'sp.payoutTitle': 'Выплата партнёру',
+ 'sp.phone': 'Телефон',
+ 'sp.service': 'Услуга',
+ 'sp.cleaningOnly': 'Клининг (пока только он)',
+ 'sp.deal': 'Модель сотрудничества',
+ 'sp.deal.COMMISSION': 'Как Uber: наш % с заказа',
+ 'sp.deal.PROFIT_SHARE': 'Расходы наши: % партнёру',
+ 'sp.dealHint.COMMISSION': 'Мы забираем свой % с оплаченного заказа, остальное — партнёру. Зарплаты сотрудникам и расходы — его.',
+ 'sp.dealHint.PROFIT_SHARE': 'ФОТ клинеру и налог платим мы; партнёру — его % от того, что осталось: оплачено − ФОТ − налог.',
+ 'sp.commissionPct': 'Наш %, с оплаченного заказа',
+ 'sp.profitSharePct': '% партнёра от прибыли',
+ 'sp.fotPct': 'ФОТ клинера, % от заказа',
+ 'sp.taxPct': 'Налог, %',
+ 'sp.defaultHint': 'пусто — из настроек ({n}%)',
+ 'sp.exampleCOMMISSION': 'Пример: заказ оплачен на {sum} → нам {ours}, партнёру {partner}.',
+ 'sp.examplePROFIT_SHARE': 'Пример: оплачено {sum} − ФОТ {fot} − налог {tax} = {profit}; партнёру {partner}, нам {ours}.',
+ 'sp.activeLabel': 'Партнёр работает (можно назначать заказы)',
+ 'nav.points': 'Барики',
+ 'st.group.points': 'Барики (кэшбек)',
+ 'ag.hwPoints': 'Барики на новоселье',
+ 'ag.hwDays': 'Срок, дней',
+ 'ag.hwHint': '0 — не дарим. Начисляются один раз, сразу доступны.',
+ 'ag.hwValue': '{n} бариков на {days} дн.',
+ 'pt.title': 'Барики',
+ 'pt.tab.accrue': 'Начислить',
+ 'pt.tab.requests': 'Запросы',
+ 'pt.tab.suggestions': 'Предложено системой',
+ 'pt.tab.ledger': 'Журнал',
+ 'pt.tab.report': 'Отчёт',
+ 'pt.tab.import': 'Импорт CSV',
+ 'pt.tab.setup': 'Ставки и бонусы',
+ 'pt.search': 'Клиент',
+ 'pt.searchPh': 'Телефон, @username, имя или ID',
+ 'pt.notFound': 'Никого не нашли',
+ 'pt.pickClient': 'Найдите клиента слева — здесь появится форма начисления.',
+ 'pt.flagged': 'проверить: много отмен',
+ 'pt.balance': 'Доступно',
+ 'pt.pending': 'В ожидании',
+ 'pt.availableFrom': 'с {date}',
+ 'pt.tier': 'Уровень',
+ 'pt.burnAt': 'Сгорят',
+ 'pt.agency': 'Агентство',
+ 'pt.streak': 'Серия уборок',
+ 'pt.debt': 'Долг',
+ 'pt.redeem': 'Списать',
+ 'pt.redeemBtn': 'Списать',
+ 'pt.redeemed': 'Списано',
+ 'pt.allOps': 'Все операции',
+ 'pt.noOps': 'Операций пока нет.',
+ 'pt.reverse': 'Отменить',
+ 'pt.accrueTitle': 'Начисление',
+ 'pt.kind.ORDER': 'За заказ',
+ 'pt.kind.BONUS': 'Бонус',
+ 'pt.f.category': 'Категория',
+ 'pt.f.orderAmount': 'Сумма заказа, ֏',
+ 'pt.f.excluded': 'Не облагается, ֏',
+ 'pt.f.excludedHint': 'пошлины, материалы, чаевые',
+ 'pt.f.paidWithPoints': 'Оплачено бариками',
+ 'pt.f.serviceDate': 'Дата услуги',
+ 'pt.f.orderRef': 'Номер заказа',
+ 'pt.f.orderRefHint': 'второй раз по тому же номеру начислить нельзя',
+ 'pt.f.bonusType': 'Тип бонуса',
+ 'pt.f.ttl': 'Срок жизни, дней',
+ 'pt.f.ttlDefault': 'по умолчанию {n}',
+ 'pt.f.ttlNone': 'пусто — общее правило сгорания',
+ 'pt.f.amount': 'Сумма бариков',
+ 'pt.f.amountHint': 'подсказка: {n}',
+ 'pt.f.reason': 'Причина',
+ 'pt.f.reasonRequired': 'Причина (обязательно)',
+ 'pt.f.comment': 'Комментарий для клиента',
+ 'pt.f.commentPh': 'Увидит в истории',
+ 'pt.f.noWait': 'Без ожидания — сразу доступны',
+ 'pt.f.noWaitReason': 'Без ожидания (нужна причина)',
+ 'pt.f.redeemAmount': 'Сколько списать',
+ 'pt.f.defaultAmount': 'Сумма по умолчанию',
+ 'pt.formula': '{tier}: {rate}%{extra} → {n} бариков',
+ 'pt.accrueBtn': 'Начислить',
+ 'pt.confirmTitle': 'Проверьте',
+ 'pt.edit': 'Изменить',
+ 'pt.confirmOrder': 'Начислить {n} бариков {name} за {what} {sum} ֏ ({tier}, {rate}%). Станут доступны {date}.',
+ 'pt.confirmBonus': 'Начислить {n} бариков {name}: {what}, {until}.',
+ 'pt.now': 'сразу',
+ 'pt.forDays': 'на {n} дн.',
+ 'pt.noTtl': 'без своего срока',
+ 'pt.changedNote': 'Сумма изменена против подсказки ({n}) — попадёт в журнал с вашей причиной.',
+ 'pt.accrued': 'Начислено {n}',
+ 'pt.needsApproval': 'Выше лимита — отправлено суперадмину на подтверждение',
+ 'pt.zero': 'Сумма 0 — начислять нечего',
+ 'pt.reverseAccrual': 'Отменить начисление',
+ 'pt.reverseRedemption': 'Отменить списание',
+ 'pt.reverseAccrualText': 'Начисление {n} бариков будет отменено. Исходная запись останется в журнале.',
+ 'pt.reverseRedemptionText': '{n} бариков вернутся в исходные начисления с их сроками.',
+ 'pt.debtWarn': 'Из начисления уже потрачено {spent} — баланс уйдёт в минус: {after}. Минус погасится следующими начислениями.',
+ 'pt.reasonPh': 'Возврат денег, ошибка…',
+ 'pt.reverseHint': 'Поддержка отменяет только свои операции и только в течение 24 часов.',
+ 'pt.reversed': 'Отменено',
+ 'pt.maxHint': 'максимум {max} ({share}% заказа и не больше баланса), минимум {min}',
+ 'pt.redeemReasonPh': 'По звонку, заказ вне приложения…',
+ 'pt.toPay': 'К доплате: {sum} ֏',
+ 'pt.noRequests': 'Запросов нет.',
+ 'pt.wants': 'хочет списать {n}',
+ 'pt.forOrder': 'заказ №{n}',
+ 'pt.noOrder': 'заказ вне приложения',
+ 'pt.balanceN': 'баланс {n}',
+ 'pt.confirm': 'Подтвердить',
+ 'pt.confirmN': 'Списать {n}',
+ 'pt.confirmed': 'Списано {n}',
+ 'pt.reject': 'Отклонить',
+ 'pt.rejectReason': 'Причина — её увидит клиент',
+ 'pt.noSuggestions': 'Предложений нет.',
+ 'pt.suggestionsHint': 'Система нашла, кому положен бонус. Начислите, измените сумму или отклоните.',
+ 'pt.mech.first_month_route': 'Маршрут первого месяца',
+ 'pt.mech.photo_review': 'Отзыв с фото',
+ 'pt.mech.over_limit': 'Выше лимита поддержки',
+ 'pt.why.first_month_route': '3 разные категории за первые 30 дней',
+ 'pt.why.photo_review': 'прислал фото после заказа №{n}',
+ 'pt.why.over_limit': '{by}: {op}',
+ 'pt.op.accrual': 'начисление',
+ 'pt.op.redemption': 'списание',
+ 'pt.approve': 'Подтвердить',
+ 'pt.changeAmount': 'Изменить сумму',
+ 'pt.allTypes': 'Все типы',
+ 'pt.allCategories': 'Все категории',
+ 'pt.allChannels': 'Все каналы',
+ 'pt.allClients': 'Все клиенты',
+ 'pt.type.accrual': 'Начисление',
+ 'pt.type.bonus': 'Бонус',
+ 'pt.type.redemption': 'Списание',
+ 'pt.type.request': 'Запрос клиента',
+ 'pt.type.reversal': 'Отмена',
+ 'pt.channel.WEB': 'админка',
+ 'pt.channel.BOT': 'бот',
+ 'pt.channel.CSV': 'CSV',
+ 'pt.channel.AUTO': 'авто',
+ 'pt.channel.CLIENT': 'клиент',
+ 'pt.status.PENDING': 'в ожидании',
+ 'pt.status.ACTIVE': 'активно',
+ 'pt.status.SPENT': 'потрачено',
+ 'pt.status.EXPIRED': 'сгорело',
+ 'pt.status.REVERSED': 'отменено',
+ 'pt.status.REQUESTED': 'ждёт',
+ 'pt.status.CONFIRMED': 'списано',
+ 'pt.status.REJECTED': 'отклонено',
+ 'pt.status.ACCRUAL': 'начисления',
+ 'pt.status.REDEMPTION': 'списания',
+ 'pt.col.date': 'Когда',
+ 'pt.col.client': 'Клиент',
+ 'pt.col.what': 'Что',
+ 'pt.col.amount': 'Барики',
+ 'pt.col.status': 'Статус',
+ 'pt.col.author': 'Кто',
+ 'pt.system': 'система',
+ 'pt.suggestedN': 'подсказка {n}',
+ 'pt.debtN': 'в долг {n}',
+ 'pt.rep.accrued': 'Начислено',
+ 'pt.rep.spent': 'Потрачено',
+ 'pt.rep.expired': 'Сгорело',
+ 'pt.rep.reversed': 'Отменено',
+ 'pt.rep.liabilities': 'Обязательства сейчас',
+ 'pt.rep.rate': 'Доля потраченных',
+ 'pt.rep.byCategory': 'Стоимость программы по категориям',
+ 'pt.rep.cost': '{pct}% от выручки {revenue} ֏',
+ 'pt.rep.retention': 'Повторный заказ за 30 дней',
+ 'pt.rep.with': 'С бариками',
+ 'pt.rep.without': 'Без бариков',
+ 'pt.rep.clientsN': 'клиентов {n}, с 2+ категориями {multi}',
+ 'pt.rep.topClients': 'Топ по балансу',
+ 'pt.rep.topAgencies': 'Агентства: активации новоселья',
+ 'pt.importHint': 'CSV: телефон, категория (cleaning, documents, learning, repair, transfer), сумма заказа, дата (ГГГГ-ММ-ДД), номер заказа. Сначала — предпросмотр, начисление только после подтверждения.',
+ 'pt.importRows': 'Строк',
+ 'pt.importTotal': 'Бариков всего',
+ 'pt.importErr.client': 'клиент не найден',
+ 'pt.importErr.category': 'нет такой категории',
+ 'pt.importErr.date': 'неверная дата',
+ 'pt.importErr.duplicate': 'дубль заказа',
+ 'pt.importCommit': 'Начислить {n} строк',
+ 'pt.importDone': 'Начислено по {n} строкам',
+ 'pt.categories': 'Категории и ставки',
+ 'pt.bonusTypes': 'Типы бонусов',
+ 'pt.code': 'Код',
+ 'pt.activeLabel': 'Работает',
+ 'pt.rulesHint': 'Доступны через {hours} ч после услуги · оплатить можно до {share}% заказа, минимум {min} · сгорают через {burn} дней без активности. Меняется в «Настройках».',
+ 'err.POINTS_DUPLICATE_ORDER': 'За этот заказ барики уже начислены.',
+ 'err.POINTS_REASON_REQUIRED': 'Укажите причину.',
+ 'err.POINTS_BELOW_MIN': 'Меньше минимальной суммы списания.',
+ 'err.POINTS_NOT_ENOUGH': 'Не хватает бариков.',
+ 'err.POINTS_OVER_SHARE': 'Больше допустимой доли заказа.',
+ 'err.POINTS_OVER_LIMIT': 'Выше вашего лимита — нужно подтверждение суперадмина.',
+ 'err.POINTS_FINAL': 'Эту операцию уже нельзя отменить.',
+ 'err.POINTS_REQUEST_CLOSED': 'Запрос уже обработан или истёк.',
+ 'err.POINTS_WITH_PROMO': 'Барики нельзя вместе с промокодом.',
+ 'pt.formulaStreak': ' + серия уборок {streak}: +{bonus}%',
+ 'ord.editComposition': 'Изменить состав',
+ 'ord.editTitle': 'Состав заказа №{n}',
+ 'ord.editPrice': 'Цена: было {was} → станет {now} (скидка {pct}%, как при оформлении)',
+ 'ord.editDuration': 'Длительность: {was} → {now} мин',
+ 'ord.editBusy': 'Заказ стал дольше, а у исполнителя в это время другой заказ — проверьте график.',
+ 'ord.editPaid': 'Заказ уже оплачен: пересчитаем вознаграждение агентства, доход партнёра и барики. Разницу в деньгах решите с клиентом.',
+ 'ord.editOwnPrice': 'Своя итоговая цена, ֏',
+ 'ord.editOwnPriceHint': 'пусто — по прайсу: {n}',
+ 'ord.editReason': 'Причина',
+ 'ord.editReasonRequired': 'Причина (обязательно для своей цены)',
+ 'ord.editReasonPh': 'На месте добавили окна…',
+ 'ord.editNotify': 'Сообщить клиенту и исполнителю',
+ 'ord.edited': 'Состав заказа изменён',
+ 'ord.editedBusy': 'Изменено. Внимание: исполнитель может не успеть — проверьте график',
+ 'ord.uncheck': 'Снять отметку',
+ 'ord.checkForProvider': 'Отметить за исполнителя',
+ 'ord.noPhotoReason': 'без фото: {reason}',
+ 'ord.byStaff': 'отметила команда',
+ 'ord.checkNoPhoto': 'Отметить без фото',
+ 'ord.photoHint': 'Для этого пункта нужно фото. Загрузите его или отметьте без фото с причиной.',
+ 'ord.uploadPhoto': 'Загрузить фото',
+ 'ord.noPhotoField': 'Или причина, почему без фото',
+ 'ord.noPhotoPh': 'Клинер прислал фото в чат…',
+ 'err.PHOTO_REQUIRED': 'Нужно фото или причина, почему без него.',
};
export type BoKey = keyof typeof ru;
@@ -1211,8 +1484,8 @@ const en: Dict = {
'nav.chats': 'Chats',
'nav.orders': 'Orders',
'nav.providers': 'Providers',
- 'nav.agencies': 'Agencies',
- 'nav.venues': 'Venues',
+ 'nav.agencies': 'Real estate agencies',
+ 'nav.venues': 'Club partners',
'nav.crm': 'CRM',
'nav.products': 'Products',
'nav.journal': 'Activity log',
@@ -1824,7 +2097,7 @@ const en: Dict = {
'st.saveN': 'Save ({n})',
'st.group.orders': 'Orders',
'st.group.subs': 'Membership',
- 'st.group.agencies': 'Agencies',
+ 'st.group.agencies': 'Real estate agencies',
'st.group.sales': 'Sales bonus',
'st.group.site': 'Website prices',
'st.group.other': 'Other',
@@ -1977,22 +2250,22 @@ const en: Dict = {
'venue.cat.shop': 'Shop',
'venue.cat.beauty': 'Beauty',
'venue.cat.other': 'Other',
- 'ag.title': 'Agencies',
- 'ag.add': 'New agency',
- 'ag.editTitle': 'Agency',
- 'ag.empty': 'No agencies yet.',
- 'ag.col.name': 'Agency',
+ 'ag.title': 'Real estate agencies',
+ 'ag.add': 'New real estate agency',
+ 'ag.editTitle': 'Real estate agency',
+ 'ag.empty': 'No real estate agencies yet.',
+ 'ag.col.name': 'Real estate agency',
'ag.col.clients': 'Clients',
'ag.col.gifts': 'Gifts',
'ag.col.month': 'Reward, month',
'ag.col.balance': 'To pay',
'ag.hint': 'Reward = % of paid orders of the agency’s clients while they’re attached.',
'ag.inactive': 'inactive',
- 'ag.back': 'All agencies',
+ 'ag.back': 'All real estate agencies',
'ag.pct': '{n}% of client orders',
'ag.byS': 'connected by {name}',
'ag.link': 'Client link',
- 'ag.linkHint': 'The client opens the bot, gets a gift month and is attached to the agency. Or types code {code} via /code.',
+ 'ag.linkHint': 'The client opens the bot, gets the agency gift and is attached to the agency. Or types code {code} via /code.',
'ag.clients': 'Clients',
'ag.giftsN': 'gifts: {n}',
'ag.noClients': 'No clients yet.',
@@ -2006,7 +2279,7 @@ const en: Dict = {
'ag.sales': 'Connected by',
'ag.contactPh': 'Name, phone, Telegram',
'ag.active': 'Agency active (code accepted)',
- 'vn.title': 'Venues',
+ 'vn.title': 'Club partners',
'vn.add': 'New venue',
'vn.editTitle': 'Venue',
'vn.empty': 'No venues yet.',
@@ -2337,6 +2610,279 @@ const en: Dict = {
'audit.bo.chats.openFor': 'opened a chat with a client',
'audit.bo.chats.templates.save': 'edited a reply template',
'audit.bo.chats.templates.remove': 'deleted a reply template',
+ 'nav.servicePartners': 'Service partners',
+ 'st.group.partners': 'Service partners',
+ 'ag.giftPlan': 'Gift for new clients',
+ 'ag.giftMonths': 'For how long',
+ 'ag.giftHint': 'Applies to new clients; those who already got a gift keep theirs.',
+ 'ag.noGift': 'no gift',
+ 'ag.giftValue': '{plan} for {n} mo',
+ 'ag.monthsN': '{n} mo',
+ 'ord.partner': 'partner',
+ 'ord.best': 'best for us',
+ 'ord.partnerFree': '{n} of {of} free',
+ 'ord.candMoney': 'We pay {cost} · we keep {margin}',
+ 'prv.ratePartnerPays': 'Paid by the partner',
+ 'rq.missing': 'missing details',
+ 'rq.noTime': 'not given',
+ 'rq.noDistrict': 'no district',
+ 'rq.noAddress': 'no address',
+ 'sp.title': 'Service partners',
+ 'sp.add': 'New partner',
+ 'sp.editTitle': 'Service partner',
+ 'sp.lead': 'Cleaning companies with their own staff. The partner’s manager gets a link, adds staff and assigns orders. An operator gives an order to a partner from the order card.',
+ 'sp.empty': 'No partners yet.',
+ 'sp.col.name': 'Partner',
+ 'sp.col.staff': 'Staff',
+ 'sp.col.active': 'Active orders',
+ 'sp.col.month': 'Partner income, month',
+ 'sp.col.balance': 'To pay',
+ 'sp.noManager': 'no manager',
+ 'sp.auto': 'auto-assign',
+ 'sp.back': 'All service partners',
+ 'sp.terms.COMMISSION': 'Uber-style: we take {pct}%',
+ 'sp.terms.PROFIT_SHARE': 'our costs: payroll {fot}%, tax {tax}%, partner gets {pct}% of profit',
+ 'sp.managerLink': 'Manager link',
+ 'sp.managerLinkHint': 'Give this link to the partner’s manager: they open the work bot and get the cabinet — orders, staff, auto-assignment, income. It also opens on a computer (button in the bot).',
+ 'sp.resetLink': 'New link',
+ 'sp.resetConfirm': 'Make a new link? The old one stops working; connected managers stay.',
+ 'sp.linkReset': 'Link updated',
+ 'sp.managers': 'Managers',
+ 'sp.noManagers': 'No manager has joined via the link yet.',
+ 'sp.managerSince': 'since {date}',
+ 'sp.remove': 'Remove',
+ 'sp.removeManagerConfirm': 'Remove {name} from the partner’s managers?',
+ 'sp.staff': 'Staff',
+ 'sp.staffHint': 'added by the partner’s manager',
+ 'sp.noStaff': 'No staff yet.',
+ 'sp.limitOrders': 'up to {n} orders a day',
+ 'sp.limitHours': 'up to {n} h a day',
+ 'sp.notLinked': 'not in the bot',
+ 'sp.off': 'off',
+ 'sp.orders': 'Active orders',
+ 'sp.noOrders': 'The partner has no orders right now.',
+ 'sp.waitingStaff': 'waiting for staff',
+ 'sp.toPay': 'Partner income to pay',
+ 'sp.byOrder': 'Income by order',
+ 'sp.noIncome': 'Income appears once a client pays for a completed order.',
+ 'sp.paid': 'paid {sum}',
+ 'sp.fotTax': 'payroll {fot}, tax {tax}',
+ 'sp.payoutTitle': 'Payout to partner',
+ 'sp.phone': 'Phone',
+ 'sp.service': 'Service',
+ 'sp.cleaningOnly': 'Cleaning (only this for now)',
+ 'sp.deal': 'Deal model',
+ 'sp.deal.COMMISSION': 'Uber-style: our % of order',
+ 'sp.deal.PROFIT_SHARE': 'Our costs: % to partner',
+ 'sp.dealHint.COMMISSION': 'We keep our % of each paid order, the rest goes to the partner. Wages and costs are theirs.',
+ 'sp.dealHint.PROFIT_SHARE': 'We pay the cleaner and the tax; the partner gets their % of what’s left: paid − payroll − tax.',
+ 'sp.commissionPct': 'Our %, of paid order',
+ 'sp.profitSharePct': 'Partner’s % of profit',
+ 'sp.fotPct': 'Cleaner payroll, % of order',
+ 'sp.taxPct': 'Tax, %',
+ 'sp.defaultHint': 'empty — from settings ({n}%)',
+ 'sp.exampleCOMMISSION': 'Example: order paid {sum} → we keep {ours}, partner gets {partner}.',
+ 'sp.examplePROFIT_SHARE': 'Example: paid {sum} − payroll {fot} − tax {tax} = {profit}; partner {partner}, us {ours}.',
+ 'sp.activeLabel': 'Partner active (orders can be assigned)',
+ 'nav.points': 'Bariki',
+ 'st.group.points': 'Bariki (cashback)',
+ 'ag.hwPoints': 'Housewarming bariki',
+ 'ag.hwDays': 'Valid, days',
+ 'ag.hwHint': '0 — none. Credited once, available right away.',
+ 'ag.hwValue': '{n} bariki for {days} days',
+ 'pt.title': 'Bariki',
+ 'pt.tab.accrue': 'Credit',
+ 'pt.tab.requests': 'Requests',
+ 'pt.tab.suggestions': 'Suggested',
+ 'pt.tab.ledger': 'Log',
+ 'pt.tab.report': 'Report',
+ 'pt.tab.import': 'CSV import',
+ 'pt.tab.setup': 'Rates & bonuses',
+ 'pt.search': 'Client',
+ 'pt.searchPh': 'Phone, @username, name or ID',
+ 'pt.notFound': 'No one found',
+ 'pt.pickClient': 'Find a client on the left — the credit form appears here.',
+ 'pt.flagged': 'check: many reversals',
+ 'pt.balance': 'Available',
+ 'pt.pending': 'Pending',
+ 'pt.availableFrom': 'from {date}',
+ 'pt.tier': 'Level',
+ 'pt.burnAt': 'Expire on',
+ 'pt.agency': 'Agency',
+ 'pt.streak': 'Cleaning streak',
+ 'pt.debt': 'Debt',
+ 'pt.redeem': 'Redeem',
+ 'pt.redeemBtn': 'Redeem',
+ 'pt.redeemed': 'Redeemed',
+ 'pt.allOps': 'All operations',
+ 'pt.noOps': 'No operations yet.',
+ 'pt.reverse': 'Reverse',
+ 'pt.accrueTitle': 'Credit',
+ 'pt.kind.ORDER': 'For an order',
+ 'pt.kind.BONUS': 'Bonus',
+ 'pt.f.category': 'Category',
+ 'pt.f.orderAmount': 'Order amount, ֏',
+ 'pt.f.excluded': 'Not eligible, ֏',
+ 'pt.f.excludedHint': 'fees, materials, tips',
+ 'pt.f.paidWithPoints': 'Paid with bariki',
+ 'pt.f.serviceDate': 'Service date',
+ 'pt.f.orderRef': 'Order number',
+ 'pt.f.orderRefHint': 'the same number can’t be credited twice',
+ 'pt.f.bonusType': 'Bonus type',
+ 'pt.f.ttl': 'Valid for, days',
+ 'pt.f.ttlDefault': 'default {n}',
+ 'pt.f.ttlNone': 'empty — general expiry rule',
+ 'pt.f.amount': 'Bariki amount',
+ 'pt.f.amountHint': 'suggested: {n}',
+ 'pt.f.reason': 'Reason',
+ 'pt.f.reasonRequired': 'Reason (required)',
+ 'pt.f.comment': 'Comment for the client',
+ 'pt.f.commentPh': 'Shown in their history',
+ 'pt.f.noWait': 'No waiting — available now',
+ 'pt.f.noWaitReason': 'No waiting (reason required)',
+ 'pt.f.redeemAmount': 'How much to redeem',
+ 'pt.f.defaultAmount': 'Default amount',
+ 'pt.formula': '{tier}: {rate}%{extra} → {n} bariki',
+ 'pt.accrueBtn': 'Credit',
+ 'pt.confirmTitle': 'Please check',
+ 'pt.edit': 'Edit',
+ 'pt.confirmOrder': 'Credit {n} bariki to {name} for {what} {sum} ֏ ({tier}, {rate}%). Available {date}.',
+ 'pt.confirmBonus': 'Credit {n} bariki to {name}: {what}, {until}.',
+ 'pt.now': 'right away',
+ 'pt.forDays': 'for {n} days',
+ 'pt.noTtl': 'no own expiry',
+ 'pt.changedNote': 'Amount differs from the suggestion ({n}) — logged with your reason.',
+ 'pt.accrued': 'Credited {n}',
+ 'pt.needsApproval': 'Above the limit — sent to a super admin',
+ 'pt.zero': 'Amount is 0 — nothing to credit',
+ 'pt.reverseAccrual': 'Reverse credit',
+ 'pt.reverseRedemption': 'Reverse redemption',
+ 'pt.reverseAccrualText': 'The credit of {n} bariki will be reversed. The original stays in the log.',
+ 'pt.reverseRedemptionText': '{n} bariki return to the original credits with their expiry.',
+ 'pt.debtWarn': '{spent} of this credit is already spent — balance goes negative: {after}. Future credits will cover it.',
+ 'pt.reasonPh': 'Refund, mistake…',
+ 'pt.reverseHint': 'Support can reverse only their own operations within 24 hours.',
+ 'pt.reversed': 'Reversed',
+ 'pt.maxHint': 'max {max} ({share}% of the order, within balance), min {min}',
+ 'pt.redeemReasonPh': 'By phone, order outside the app…',
+ 'pt.toPay': 'Left to pay: {sum} ֏',
+ 'pt.noRequests': 'No requests.',
+ 'pt.wants': 'wants to use {n}',
+ 'pt.forOrder': 'order #{n}',
+ 'pt.noOrder': 'order outside the app',
+ 'pt.balanceN': 'balance {n}',
+ 'pt.confirm': 'Confirm',
+ 'pt.confirmN': 'Redeem {n}',
+ 'pt.confirmed': 'Redeemed {n}',
+ 'pt.reject': 'Decline',
+ 'pt.rejectReason': 'Reason — the client will see it',
+ 'pt.noSuggestions': 'No suggestions.',
+ 'pt.suggestionsHint': 'The system found who qualifies for a bonus. Credit, change the amount or decline.',
+ 'pt.mech.first_month_route': 'First-month route',
+ 'pt.mech.photo_review': 'Photo review',
+ 'pt.mech.over_limit': 'Above support limit',
+ 'pt.why.first_month_route': '3 different categories in the first 30 days',
+ 'pt.why.photo_review': 'sent a photo after order #{n}',
+ 'pt.why.over_limit': '{by}: {op}',
+ 'pt.op.accrual': 'credit',
+ 'pt.op.redemption': 'redemption',
+ 'pt.approve': 'Approve',
+ 'pt.changeAmount': 'Change amount',
+ 'pt.allTypes': 'All types',
+ 'pt.allCategories': 'All categories',
+ 'pt.allChannels': 'All channels',
+ 'pt.allClients': 'All clients',
+ 'pt.type.accrual': 'Credit',
+ 'pt.type.bonus': 'Bonus',
+ 'pt.type.redemption': 'Redemption',
+ 'pt.type.request': 'Client request',
+ 'pt.type.reversal': 'Reversal',
+ 'pt.channel.WEB': 'admin',
+ 'pt.channel.BOT': 'bot',
+ 'pt.channel.CSV': 'CSV',
+ 'pt.channel.AUTO': 'auto',
+ 'pt.channel.CLIENT': 'client',
+ 'pt.status.PENDING': 'pending',
+ 'pt.status.ACTIVE': 'active',
+ 'pt.status.SPENT': 'spent',
+ 'pt.status.EXPIRED': 'expired',
+ 'pt.status.REVERSED': 'reversed',
+ 'pt.status.REQUESTED': 'waiting',
+ 'pt.status.CONFIRMED': 'redeemed',
+ 'pt.status.REJECTED': 'declined',
+ 'pt.status.ACCRUAL': 'of a credit',
+ 'pt.status.REDEMPTION': 'of a redemption',
+ 'pt.col.date': 'When',
+ 'pt.col.client': 'Client',
+ 'pt.col.what': 'What',
+ 'pt.col.amount': 'Bariki',
+ 'pt.col.status': 'Status',
+ 'pt.col.author': 'Who',
+ 'pt.system': 'system',
+ 'pt.suggestedN': 'suggested {n}',
+ 'pt.debtN': 'debt {n}',
+ 'pt.rep.accrued': 'Credited',
+ 'pt.rep.spent': 'Spent',
+ 'pt.rep.expired': 'Expired',
+ 'pt.rep.reversed': 'Reversed',
+ 'pt.rep.liabilities': 'Outstanding now',
+ 'pt.rep.rate': 'Redemption rate',
+ 'pt.rep.byCategory': 'Programme cost by category',
+ 'pt.rep.cost': '{pct}% of {revenue} ֏ revenue',
+ 'pt.rep.retention': 'Repeat order within 30 days',
+ 'pt.rep.with': 'With bariki',
+ 'pt.rep.without': 'Without bariki',
+ 'pt.rep.clientsN': '{n} clients, {multi} with 2+ categories',
+ 'pt.rep.topClients': 'Top by balance',
+ 'pt.rep.topAgencies': 'Agencies: housewarming activations',
+ 'pt.importHint': 'CSV: phone, category (cleaning, documents, learning, repair, transfer), order amount, date (YYYY-MM-DD), order number. Preview first; credited only after you confirm.',
+ 'pt.importRows': 'Rows',
+ 'pt.importTotal': 'Total bariki',
+ 'pt.importErr.client': 'client not found',
+ 'pt.importErr.category': 'unknown category',
+ 'pt.importErr.date': 'bad date',
+ 'pt.importErr.duplicate': 'duplicate order',
+ 'pt.importCommit': 'Credit {n} rows',
+ 'pt.importDone': 'Credited {n} rows',
+ 'pt.categories': 'Categories and rates',
+ 'pt.bonusTypes': 'Bonus types',
+ 'pt.code': 'Code',
+ 'pt.activeLabel': 'Active',
+ 'pt.rulesHint': 'Available {hours} h after the service · up to {share}% of an order, min {min} · expire after {burn} days of inactivity. Change in Settings.',
+ 'err.POINTS_DUPLICATE_ORDER': 'Bariki for this order were already credited.',
+ 'err.POINTS_REASON_REQUIRED': 'Please give a reason.',
+ 'err.POINTS_BELOW_MIN': 'Below the minimum redemption.',
+ 'err.POINTS_NOT_ENOUGH': 'Not enough bariki.',
+ 'err.POINTS_OVER_SHARE': 'More than the allowed share of the order.',
+ 'err.POINTS_OVER_LIMIT': 'Above your limit — needs a super admin.',
+ 'err.POINTS_FINAL': 'This can no longer be reversed.',
+ 'err.POINTS_REQUEST_CLOSED': 'Request already handled or expired.',
+ 'err.POINTS_WITH_PROMO': 'Bariki can’t be combined with a promo code.',
+ 'pt.formulaStreak': ' + cleaning streak {streak}: +{bonus}%',
+ 'ord.editComposition': 'Edit composition',
+ 'ord.editTitle': 'Order #{n} composition',
+ 'ord.editPrice': 'Price: was {was} → now {now} ({pct}% discount, as when booked)',
+ 'ord.editDuration': 'Duration: {was} → {now} min',
+ 'ord.editBusy': 'The order got longer and the provider has another job then — check the schedule.',
+ 'ord.editPaid': 'Already paid: agency reward, partner income and bariki will be recalculated. Settle the money difference with the client.',
+ 'ord.editOwnPrice': 'Custom total, ֏',
+ 'ord.editOwnPriceHint': 'empty — price list: {n}',
+ 'ord.editReason': 'Reason',
+ 'ord.editReasonRequired': 'Reason (required for a custom price)',
+ 'ord.editReasonPh': 'Added windows on site…',
+ 'ord.editNotify': 'Notify the client and the provider',
+ 'ord.edited': 'Order updated',
+ 'ord.editedBusy': 'Updated. The provider may not have time — check the schedule',
+ 'ord.uncheck': 'Uncheck',
+ 'ord.checkForProvider': 'Check for the provider',
+ 'ord.noPhotoReason': 'no photo: {reason}',
+ 'ord.byStaff': 'checked by the team',
+ 'ord.checkNoPhoto': 'Check without photo',
+ 'ord.photoHint': 'This item needs a photo. Upload one or check it without a photo and a reason.',
+ 'ord.uploadPhoto': 'Upload photo',
+ 'ord.noPhotoField': 'Or why there is no photo',
+ 'ord.noPhotoPh': 'The cleaner sent it in the chat…',
+ 'err.PHOTO_REQUIRED': 'A photo or a reason is required.',
};
const hy: Dict = {
@@ -2376,8 +2922,8 @@ const hy: Dict = {
'nav.chats': 'Չատեր',
'nav.orders': 'Պատվերներ',
'nav.providers': 'Կատարողներ',
- 'nav.agencies': 'Գործակալություններ',
- 'nav.venues': 'Հաստատություններ',
+ 'nav.agencies': 'Անշարժ գույքի գործակալություններ',
+ 'nav.venues': 'Ակումբի գործընկերներ',
'nav.crm': 'CRM',
'nav.products': 'Ապրանքներ',
'nav.journal': 'Մատյան',
@@ -2989,7 +3535,7 @@ const hy: Dict = {
'st.saveN': 'Պահպանել ({n})',
'st.group.orders': 'Պատվերներ',
'st.group.subs': 'Բաժանորդագրություն',
- 'st.group.agencies': 'Գործակալություններ',
+ 'st.group.agencies': 'Անշարժ գույքի գործակալություններ',
'st.group.sales': 'Վաճառողների բոնուս',
'st.group.site': 'Կայքի գներ',
'st.group.other': 'Այլ',
@@ -3142,10 +3688,10 @@ const hy: Dict = {
'venue.cat.shop': 'Խանութ',
'venue.cat.beauty': 'Գեղեցկություն',
'venue.cat.other': 'Այլ',
- 'ag.title': 'Գործակալություններ',
- 'ag.add': 'Նոր գործակալություն',
- 'ag.editTitle': 'Գործակալություն',
- 'ag.empty': 'Գործակալություններ դեռ չկան։',
+ 'ag.title': 'Անշարժ գույքի գործակալություններ',
+ 'ag.add': 'Նոր անշարժ գույքի գործակալություն',
+ 'ag.editTitle': 'Անշարժ գույքի գործակալություն',
+ 'ag.empty': 'Անշարժ գույքի գործակալություններ դեռ չկան։',
'ag.col.name': 'Գործակալություն',
'ag.col.clients': 'Հաճախորդներ',
'ag.col.gifts': 'Նվերներ',
@@ -3157,7 +3703,7 @@ const hy: Dict = {
'ag.pct': '{n}% հաճախորդների պատվերներից',
'ag.byS': 'միացրել է {name}',
'ag.link': 'Հղում հաճախորդների համար',
- 'ag.linkHint': 'Հաճախորդը բացում է բոտը և ստանում նվեր ամիս։ Կամ մուտքագրում է {code} կոդը։',
+ 'ag.linkHint': 'Հաճախորդը բացում է բոտը, ստանում գործակալության նվերը և կցվում նրան։ Կամ մուտքագրում է {code} կոդը /code հրամանով։',
'ag.clients': 'Հաճախորդներ',
'ag.giftsN': 'նվերներ՝ {n}',
'ag.noClients': 'Հաճախորդներ դեռ չկան։',
@@ -3170,8 +3716,8 @@ const hy: Dict = {
'ag.pctLabel': 'Պարգև, %',
'ag.sales': 'Միացրել է',
'ag.contactPh': 'Անուն, հեռախոս, Telegram',
- 'ag.active': 'Գործակալությունն աշխատում է',
- 'vn.title': 'Հաստատություններ',
+ 'ag.active': 'Գործակալությունն աշխատում է (կոդն ընդունվում է)',
+ 'vn.title': 'Ակումբի գործընկերներ',
'vn.add': 'Նոր հաստատություն',
'vn.editTitle': 'Հաստատություն',
'vn.empty': 'Հաստատություններ դեռ չկան։',
@@ -3502,6 +4048,279 @@ const hy: Dict = {
'audit.bo.chats.openFor': 'բացեց զրույց հաճախորդի հետ',
'audit.bo.chats.templates.save': 'փոխեց պատասխանի ձևանմուշը',
'audit.bo.chats.templates.remove': 'ջնջեց պատասխանի ձևանմուշը',
+ 'nav.servicePartners': 'Ծառայությունների գործընկերներ',
+ 'st.group.partners': 'Ծառայությունների գործընկերներ',
+ 'ag.giftPlan': 'Նվեր նոր հաճախորդներին',
+ 'ag.giftMonths': 'Որքան ժամանակով',
+ 'ag.giftHint': 'Գործում է նոր հաճախորդների համար․ արդեն նվեր ստացածների մոտ ոչինչ չի փոխվում։',
+ 'ag.noGift': 'առանց նվերի',
+ 'ag.giftValue': '{plan}՝ {n} ամիս',
+ 'ag.monthsN': '{n} ամիս',
+ 'ord.partner': 'գործընկեր',
+ 'ord.best': 'ամենաշահավետը',
+ 'ord.partnerFree': 'ազատ է {n}-ը {of}-ից',
+ 'ord.candMoney': 'Վճարում ենք {cost} · մեզ մնում է {margin}',
+ 'prv.ratePartnerPays': 'Աշխատավարձը վճարում է գործընկերը',
+ 'rq.missing': 'տվյալներ չեն բավարարում',
+ 'rq.noTime': 'նշված չէ',
+ 'rq.noDistrict': 'շրջանը նշված չէ',
+ 'rq.noAddress': 'հասցեն նշված չէ',
+ 'sp.title': 'Ծառայությունների գործընկերներ',
+ 'sp.add': 'Նոր գործընկեր',
+ 'sp.editTitle': 'Ծառայությունների գործընկեր',
+ 'sp.lead': 'Մաքրման ընկերություններ՝ իրենց աշխատակիցներով։ Գործընկերոջ մենեջերը ստանում է հղում, ինքն է ավելացնում աշխատակիցներին և բաշխում պատվերները։ Պատվերը գործընկերոջը նշանակում է օպերատորը։',
+ 'sp.empty': 'Գործընկերներ դեռ չկան։',
+ 'sp.col.name': 'Գործընկեր',
+ 'sp.col.staff': 'Աշխատակիցներ',
+ 'sp.col.active': 'Ընթացիկ պատվերներ',
+ 'sp.col.month': 'Գործընկերոջ եկամուտը, ամիս',
+ 'sp.col.balance': 'Վճարման ենթակա',
+ 'sp.noManager': 'մենեջեր չկա',
+ 'sp.auto': 'ավտոբաշխում',
+ 'sp.back': 'Բոլոր գործընկերները',
+ 'sp.terms.COMMISSION': 'Uber-ի պես՝ մեր {pct}%-ը',
+ 'sp.terms.PROFIT_SHARE': 'ծախսերը մերն են՝ աշխ. {fot}%, հարկ {tax}%, գործընկերոջը՝ շահույթի {pct}%',
+ 'sp.managerLink': 'Մենեջերի հղումը',
+ 'sp.managerLinkHint': 'Տվեք հղումը գործընկերոջ մենեջերին․ նա կբացի աշխատանքային բոտը և կստանա կաբինետ՝ պատվերներ, աշխատակիցներ, ավտոբաշխում, եկամուտ։ Կաբինետը բացվում է նաև համակարգչում (կոճակը բոտում)։',
+ 'sp.resetLink': 'Նոր հղում',
+ 'sp.resetConfirm': 'Ստեղծե՞լ նոր հղում։ Հինը կդադարի աշխատել, միացված մենեջերները կմնան։',
+ 'sp.linkReset': 'Հղումը թարմացված է',
+ 'sp.managers': 'Մենեջերներ',
+ 'sp.noManagers': 'Մենեջերը դեռ չի միացել հղումով։',
+ 'sp.managerSince': '{date}-ից',
+ 'sp.remove': 'Հեռացնել',
+ 'sp.removeManagerConfirm': 'Հեռացնե՞լ {name}-ին մենեջերներից։',
+ 'sp.staff': 'Աշխատակիցներ',
+ 'sp.staffHint': 'ավելացնում է գործընկերոջ մենեջերը',
+ 'sp.noStaff': 'Աշխատակիցներ դեռ չկան։',
+ 'sp.limitOrders': 'օրական մինչև {n} պատվեր',
+ 'sp.limitHours': 'օրական մինչև {n} ժ',
+ 'sp.notLinked': 'բոտ չի մտել',
+ 'sp.off': 'անջատված',
+ 'sp.orders': 'Ընթացիկ պատվերներ',
+ 'sp.noOrders': 'Գործընկերը հիմա պատվեր չունի։',
+ 'sp.waitingStaff': 'սպասում է աշխատակցի',
+ 'sp.toPay': 'Գործընկերոջ եկամուտը վճարման',
+ 'sp.byOrder': 'Եկամուտն ըստ պատվերների',
+ 'sp.noIncome': 'Եկամուտը կհայտնվի, երբ հաճախորդը վճարի կատարված պատվերի համար։',
+ 'sp.paid': 'վճարված՝ {sum}',
+ 'sp.fotTax': 'աշխ. {fot}, հարկ {tax}',
+ 'sp.payoutTitle': 'Վճարում գործընկերոջը',
+ 'sp.phone': 'Հեռախոս',
+ 'sp.service': 'Ծառայություն',
+ 'sp.cleaningOnly': 'Մաքրում (առայժմ միայն այն)',
+ 'sp.deal': 'Համագործակցության մոդել',
+ 'sp.deal.COMMISSION': 'Uber-ի պես՝ մեր %-ը',
+ 'sp.deal.PROFIT_SHARE': 'Ծախսերը մերն են՝ % գործընկերոջը',
+ 'sp.dealHint.COMMISSION': 'Վճարված պատվերից վերցնում ենք մեր %-ը, մնացածը՝ գործընկերոջը։ Աշխատավարձն ու ծախսերը նրանն են։',
+ 'sp.dealHint.PROFIT_SHARE': 'Մաքրողի աշխատավարձը և հարկը վճարում ենք մենք․ գործընկերոջը՝ մնացորդի իր %-ը՝ վճարված − աշխ. − հարկ։',
+ 'sp.commissionPct': 'Մեր %-ը՝ վճարված պատվերից',
+ 'sp.profitSharePct': 'Գործընկերոջ %-ը շահույթից',
+ 'sp.fotPct': 'Մաքրողի աշխ., պատվերի %',
+ 'sp.taxPct': 'Հարկ, %',
+ 'sp.defaultHint': 'դատարկ՝ կարգավորումներից ({n}%)',
+ 'sp.exampleCOMMISSION': 'Օրինակ՝ վճարվել է {sum} → մեզ {ours}, գործընկերոջը {partner}։',
+ 'sp.examplePROFIT_SHARE': 'Օրինակ՝ վճարված {sum} − աշխ. {fot} − հարկ {tax} = {profit}․ գործընկերոջը {partner}, մեզ {ours}։',
+ 'sp.activeLabel': 'Գործընկերն աշխատում է (կարելի է նշանակել պատվերներ)',
+ 'nav.points': 'Բարիկներ',
+ 'st.group.points': 'Բարիկներ (քեշբեք)',
+ 'ag.hwPoints': 'Բարիկներ բնակարանամուտին',
+ 'ag.hwDays': 'Ժամկետ, օր',
+ 'ag.hwHint': '0՝ չենք նվիրում։ Մեկ անգամ, անմիջապես հասանելի։',
+ 'ag.hwValue': '{n} բարիկ {days} օրով',
+ 'pt.title': 'Բարիկներ',
+ 'pt.tab.accrue': 'Հաշվեգրել',
+ 'pt.tab.requests': 'Հայտեր',
+ 'pt.tab.suggestions': 'Համակարգի առաջարկներ',
+ 'pt.tab.ledger': 'Մատյան',
+ 'pt.tab.report': 'Հաշվետվություն',
+ 'pt.tab.import': 'CSV ներմուծում',
+ 'pt.tab.setup': 'Տոկոսներ և բոնուսներ',
+ 'pt.search': 'Հաճախորդ',
+ 'pt.searchPh': 'Հեռախոս, @username, անուն կամ ID',
+ 'pt.notFound': 'Ոչ ոք չգտնվեց',
+ 'pt.pickClient': 'Գտեք հաճախորդին ձախից․ այստեղ կհայտնվի ձևը։',
+ 'pt.flagged': 'ստուգել՝ շատ չեղարկումներ',
+ 'pt.balance': 'Հասանելի',
+ 'pt.pending': 'Սպասման մեջ',
+ 'pt.availableFrom': '{date}-ից',
+ 'pt.tier': 'Մակարդակ',
+ 'pt.burnAt': 'Կայրվեն',
+ 'pt.agency': 'Գործակալություն',
+ 'pt.streak': 'Մաքրումների շարք',
+ 'pt.debt': 'Պարտք',
+ 'pt.redeem': 'Դուրս գրել',
+ 'pt.redeemBtn': 'Դուրս գրել',
+ 'pt.redeemed': 'Դուրս է գրված',
+ 'pt.allOps': 'Բոլոր գործողությունները',
+ 'pt.noOps': 'Գործողություններ դեռ չկան։',
+ 'pt.reverse': 'Չեղարկել',
+ 'pt.accrueTitle': 'Հաշվեգրում',
+ 'pt.kind.ORDER': 'Պատվերի համար',
+ 'pt.kind.BONUS': 'Բոնուս',
+ 'pt.f.category': 'Կատեգորիա',
+ 'pt.f.orderAmount': 'Պատվերի գումար, ֏',
+ 'pt.f.excluded': 'Չի հաշվարկվում, ֏',
+ 'pt.f.excludedHint': 'տուրքեր, նյութեր, թեյավճար',
+ 'pt.f.paidWithPoints': 'Վճարված բարիկներով',
+ 'pt.f.serviceDate': 'Ծառայության ամսաթիվ',
+ 'pt.f.orderRef': 'Պատվերի համար',
+ 'pt.f.orderRefHint': 'նույն համարով երկրորդ անգամ չի կարելի',
+ 'pt.f.bonusType': 'Բոնուսի տեսակ',
+ 'pt.f.ttl': 'Ժամկետ, օր',
+ 'pt.f.ttlDefault': 'լռելյայն՝ {n}',
+ 'pt.f.ttlNone': 'դատարկ՝ ընդհանուր կանոն',
+ 'pt.f.amount': 'Բարիկների գումար',
+ 'pt.f.amountHint': 'առաջարկ՝ {n}',
+ 'pt.f.reason': 'Պատճառ',
+ 'pt.f.reasonRequired': 'Պատճառ (պարտադիր)',
+ 'pt.f.comment': 'Մեկնաբանություն հաճախորդի համար',
+ 'pt.f.commentPh': 'Կտեսնի պատմության մեջ',
+ 'pt.f.noWait': 'Առանց սպասման՝ անմիջապես',
+ 'pt.f.noWaitReason': 'Առանց սպասման (պատճառ պետք է)',
+ 'pt.f.redeemAmount': 'Որքան դուրս գրել',
+ 'pt.f.defaultAmount': 'Լռելյայն գումար',
+ 'pt.formula': '{tier}՝ {rate}%{extra} → {n} բարիկ',
+ 'pt.accrueBtn': 'Հաշվեգրել',
+ 'pt.confirmTitle': 'Ստուգեք',
+ 'pt.edit': 'Փոխել',
+ 'pt.confirmOrder': 'Հաշվեգրել {n} բարիկ {name}-ին՝ {what} {sum} ֏ ({tier}, {rate}%)։ Հասանելի՝ {date}։',
+ 'pt.confirmBonus': 'Հաշվեգրել {n} բարիկ {name}-ին՝ {what}, {until}։',
+ 'pt.now': 'անմիջապես',
+ 'pt.forDays': '{n} օրով',
+ 'pt.noTtl': 'առանց ժամկետի',
+ 'pt.changedNote': 'Գումարը տարբերվում է առաջարկից ({n})՝ կգրանցվի ձեր պատճառով։',
+ 'pt.accrued': 'Հաշվեգրված է {n}',
+ 'pt.needsApproval': 'Գերազանցում է սահմանաչափը՝ ուղարկված է սուպերադմինին',
+ 'pt.zero': 'Գումարը 0 է',
+ 'pt.reverseAccrual': 'Չեղարկել հաշվեգրումը',
+ 'pt.reverseRedemption': 'Չեղարկել դուրսգրումը',
+ 'pt.reverseAccrualText': '{n} բարիկի հաշվեգրումը կչեղարկվի։ Սկզբնական գրառումը կմնա մատյանում։',
+ 'pt.reverseRedemptionText': '{n} բարիկը կվերադառնա սկզբնական հաշվեգրումներին։',
+ 'pt.debtWarn': 'Արդեն ծախսված է {spent}՝ մնացորդը կդառնա բացասական՝ {after}։ Կծածկվի հաջորդ հաշվեգրումներով։',
+ 'pt.reasonPh': 'Վերադարձ, սխալ…',
+ 'pt.reverseHint': 'Աջակցությունը չեղարկում է միայն իր գործողությունները 24 ժամում։',
+ 'pt.reversed': 'Չեղարկված է',
+ 'pt.maxHint': 'առավելագույնը {max} ({share}%), նվազագույնը {min}',
+ 'pt.redeemReasonPh': 'Զանգով, պատվեր հավելվածից դուրս…',
+ 'pt.toPay': 'Մնաց վճարել՝ {sum} ֏',
+ 'pt.noRequests': 'Հայտեր չկան։',
+ 'pt.wants': 'ուզում է դուրս գրել {n}',
+ 'pt.forOrder': 'պատվեր №{n}',
+ 'pt.noOrder': 'պատվեր հավելվածից դուրս',
+ 'pt.balanceN': 'մնացորդ {n}',
+ 'pt.confirm': 'Հաստատել',
+ 'pt.confirmN': 'Դուրս գրել {n}',
+ 'pt.confirmed': 'Դուրս է գրված {n}',
+ 'pt.reject': 'Մերժել',
+ 'pt.rejectReason': 'Պատճառը՝ կտեսնի հաճախորդը',
+ 'pt.noSuggestions': 'Առաջարկներ չկան։',
+ 'pt.suggestionsHint': 'Համակարգը գտել է, ում է հասնում բոնուս։ Հաշվեգրեք, փոխեք գումարը կամ մերժեք։',
+ 'pt.mech.first_month_route': 'Առաջին ամսվա երթուղի',
+ 'pt.mech.photo_review': 'Կարծիք լուսանկարով',
+ 'pt.mech.over_limit': 'Աջակցության սահմանաչափից բարձր',
+ 'pt.why.first_month_route': 'առաջին 30 օրում 3 տարբեր կատեգորիա',
+ 'pt.why.photo_review': 'լուսանկար է ուղարկել №{n}-ից հետո',
+ 'pt.why.over_limit': '{by}՝ {op}',
+ 'pt.op.accrual': 'հաշվեգրում',
+ 'pt.op.redemption': 'դուրսգրում',
+ 'pt.approve': 'Հաստատել',
+ 'pt.changeAmount': 'Փոխել գումարը',
+ 'pt.allTypes': 'Բոլոր տեսակները',
+ 'pt.allCategories': 'Բոլոր կատեգորիաները',
+ 'pt.allChannels': 'Բոլոր ալիքները',
+ 'pt.allClients': 'Բոլոր հաճախորդները',
+ 'pt.type.accrual': 'Հաշվեգրում',
+ 'pt.type.bonus': 'Բոնուս',
+ 'pt.type.redemption': 'Դուրսգրում',
+ 'pt.type.request': 'Հաճախորդի հայտ',
+ 'pt.type.reversal': 'Չեղարկում',
+ 'pt.channel.WEB': 'ադմին',
+ 'pt.channel.BOT': 'բոտ',
+ 'pt.channel.CSV': 'CSV',
+ 'pt.channel.AUTO': 'ավտո',
+ 'pt.channel.CLIENT': 'հաճախորդ',
+ 'pt.status.PENDING': 'սպասման մեջ',
+ 'pt.status.ACTIVE': 'ակտիվ',
+ 'pt.status.SPENT': 'ծախսված',
+ 'pt.status.EXPIRED': 'այրված',
+ 'pt.status.REVERSED': 'չեղարկված',
+ 'pt.status.REQUESTED': 'սպասում է',
+ 'pt.status.CONFIRMED': 'դուրս գրված',
+ 'pt.status.REJECTED': 'մերժված',
+ 'pt.status.ACCRUAL': 'հաշվեգրման',
+ 'pt.status.REDEMPTION': 'դուրսգրման',
+ 'pt.col.date': 'Երբ',
+ 'pt.col.client': 'Հաճախորդ',
+ 'pt.col.what': 'Ինչ',
+ 'pt.col.amount': 'Բարիկներ',
+ 'pt.col.status': 'Կարգավիճակ',
+ 'pt.col.author': 'Ով',
+ 'pt.system': 'համակարգ',
+ 'pt.suggestedN': 'առաջարկ {n}',
+ 'pt.debtN': 'պարտք {n}',
+ 'pt.rep.accrued': 'Հաշվեգրված',
+ 'pt.rep.spent': 'Ծախսված',
+ 'pt.rep.expired': 'Այրված',
+ 'pt.rep.reversed': 'Չեղարկված',
+ 'pt.rep.liabilities': 'Պարտավորություններ',
+ 'pt.rep.rate': 'Ծախսման տոկոս',
+ 'pt.rep.byCategory': 'Ծրագրի արժեքը ըստ կատեգորիաների',
+ 'pt.rep.cost': 'հասույթի {pct}%՝ {revenue} ֏',
+ 'pt.rep.retention': 'Կրկնակի պատվեր 30 օրում',
+ 'pt.rep.with': 'Բարիկներով',
+ 'pt.rep.without': 'Առանց բարիկների',
+ 'pt.rep.clientsN': '{n} հաճախորդ, 2+ կատեգորիայով՝ {multi}',
+ 'pt.rep.topClients': 'Թոփ ըստ մնացորդի',
+ 'pt.rep.topAgencies': 'Գործակալություններ՝ բնակարանամուտի ակտիվացումներ',
+ 'pt.importHint': 'CSV՝ հեռախոս, կատեգորիա, պատվերի գումար, ամսաթիվ (ՏՏՏՏ-ԱԱ-ՕՕ), պատվերի համար։ Նախ՝ նախադիտում։',
+ 'pt.importRows': 'Տողեր',
+ 'pt.importTotal': 'Ընդամենը բարիկ',
+ 'pt.importErr.client': 'հաճախորդը չգտնվեց',
+ 'pt.importErr.category': 'անհայտ կատեգորիա',
+ 'pt.importErr.date': 'սխալ ամսաթիվ',
+ 'pt.importErr.duplicate': 'կրկնվող պատվեր',
+ 'pt.importCommit': 'Հաշվեգրել {n} տող',
+ 'pt.importDone': 'Հաշվեգրված է {n} տող',
+ 'pt.categories': 'Կատեգորիաներ և տոկոսներ',
+ 'pt.bonusTypes': 'Բոնուսների տեսակներ',
+ 'pt.code': 'Կոդ',
+ 'pt.activeLabel': 'Ակտիվ',
+ 'pt.rulesHint': 'Հասանելի՝ {hours} ժ հետո · մինչև {share}%, նվազագույնը {min} · այրվում են {burn} օր անգործությունից հետո։',
+ 'err.POINTS_DUPLICATE_ORDER': 'Այս պատվերի համար արդեն հաշվեգրվել է։',
+ 'err.POINTS_REASON_REQUIRED': 'Նշեք պատճառը։',
+ 'err.POINTS_BELOW_MIN': 'Նվազագույնից քիչ է։',
+ 'err.POINTS_NOT_ENOUGH': 'Բարիկները չեն բավարարում։',
+ 'err.POINTS_OVER_SHARE': 'Ավելի է թույլատրելի մասից։',
+ 'err.POINTS_OVER_LIMIT': 'Սահմանաչափից բարձր է։',
+ 'err.POINTS_FINAL': 'Այլևս հնարավոր չէ չեղարկել։',
+ 'err.POINTS_REQUEST_CLOSED': 'Հայտն արդեն մշակված է։',
+ 'err.POINTS_WITH_PROMO': 'Բարիկները չեն համատեղվում պրոմոկոդի հետ։',
+ 'pt.formulaStreak': ' + շարք {streak}՝ +{bonus}%',
+ 'ord.editComposition': 'Փոխել կազմը',
+ 'ord.editTitle': '№{n} պատվերի կազմը',
+ 'ord.editPrice': 'Գինը՝ {was} → {now} (զեղչ {pct}%)',
+ 'ord.editDuration': 'Տևողություն՝ {was} → {now} րոպե',
+ 'ord.editBusy': 'Պատվերը երկարեց, իսկ կատարողն այդ ժամին զբաղված է։',
+ 'ord.editPaid': 'Արդեն վճարված է․ կվերահաշվարկվեն պարգևը, գործընկերոջ եկամուտը և բարիկները։',
+ 'ord.editOwnPrice': 'Սեփական գին, ֏',
+ 'ord.editOwnPriceHint': 'դատարկ՝ գնացուցակով՝ {n}',
+ 'ord.editReason': 'Պատճառ',
+ 'ord.editReasonRequired': 'Պատճառ (պարտադիր)',
+ 'ord.editReasonPh': 'Տեղում ավելացրին պատուհաններ…',
+ 'ord.editNotify': 'Տեղեկացնել հաճախորդին և կատարողին',
+ 'ord.edited': 'Պատվերը փոխված է',
+ 'ord.editedBusy': 'Փոխված է։ Ստուգեք կատարողի գրաֆիկը',
+ 'ord.uncheck': 'Հանել նշումը',
+ 'ord.checkForProvider': 'Նշել կատարողի փոխարեն',
+ 'ord.noPhotoReason': 'առանց լուսանկարի՝ {reason}',
+ 'ord.byStaff': 'նշել է թիմը',
+ 'ord.checkNoPhoto': 'Նշել առանց լուսանկարի',
+ 'ord.photoHint': 'Այս կետի համար պետք է լուսանկար։',
+ 'ord.uploadPhoto': 'Վերբեռնել լուսանկար',
+ 'ord.noPhotoField': 'Կամ պատճառը, թե ինչու առանց լուսանկարի',
+ 'ord.noPhotoPh': 'Մաքրողն ուղարկել է զրույցում…',
+ 'err.PHOTO_REQUIRED': 'Պետք է լուսանկար կամ պատճառ։',
};
const DICTS: Record = { ru, en, hy };
diff --git a/apps/backoffice/src/orders.css b/apps/backoffice/src/orders.css
index 0792153..5bdad6e 100644
--- a/apps/backoffice/src/orders.css
+++ b/apps/backoffice/src/orders.css
@@ -379,8 +379,12 @@
margin: 0;
padding: 0;
display: grid;
+ grid-template-columns: minmax(0, 1fr);
gap: 6px;
}
+.bo-cands .bo-small {
+ overflow-wrap: anywhere;
+}
.bo-cands li {
display: flex;
align-items: center;
@@ -393,6 +397,15 @@
background: var(--bc-home);
color: var(--bc-home-ink);
}
+/* самый выгодный для нас из доступных — обводка, чтобы оператор видел его и среди первых по подбору */
+.bo-cands li[data-best] {
+ outline: 2px solid var(--bc-plum);
+ outline-offset: -2px;
+}
+.bo-cands li[data-best] .bo-chip--ok {
+ background: var(--bc-plum);
+ color: #fff;
+}
.bo-cands__rank {
width: 26px;
height: 26px;
@@ -698,3 +711,23 @@
display: none;
}
}
+
+/* чек-лист: команда отмечает за исполнителя */
+.bo-checks__toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ border: 0;
+ background: none;
+ padding: 0;
+ font: inherit;
+ color: inherit;
+ cursor: pointer;
+ text-align: left;
+}
+.bo-checks__toggle:disabled {
+ cursor: default;
+}
+.bo-checks__toggle:hover:not(:disabled) .bo-checks__box {
+ border-color: var(--bc-accent);
+}
diff --git a/apps/backoffice/src/pages/Admin5.tsx b/apps/backoffice/src/pages/Admin5.tsx
index 8ac2332..96f5a97 100644
--- a/apps/backoffice/src/pages/Admin5.tsx
+++ b/apps/backoffice/src/pages/Admin5.tsx
@@ -261,8 +261,11 @@ export function Journal() {
const GROUPS: { key: string; keys: string[] }[] = [
{ key: 'orders', keys: ['cancel.freeHours', 'offer.acceptTimeoutMinutes', 'assign.auto', 'assign.maxAutoOffers'] },
- { key: 'subs', keys: ['barevPlus.monthlyPrice', 'barevPlus.maxDiscountPct', 'barevPlus.giftDays', 'elite.monthlyPrice', 'elite.maxDiscountPct'] },
- { key: 'agencies', keys: ['agency.attributionMonths', 'agency.defaultCommissionPct'] },
+ { key: 'subs', keys: ['barevPlus.monthlyPrice', 'barevPlus.maxDiscountPct', 'elite.monthlyPrice', 'elite.maxDiscountPct'] },
+ // подарок новым клиентам задаётся у каждого агентства; giftDays — только число в текстах лендинга
+ { key: 'agencies', keys: ['agency.attributionMonths', 'agency.defaultCommissionPct', 'barevPlus.giftDays'] },
+ { key: 'points', keys: ['points.pendingHours', 'points.maxSharePct', 'points.minRedeem', 'points.burnDays', 'points.warnDays1', 'points.warnDays2', 'points.requestTtlHours', 'points.streakGapDays', 'points.diffHighlightPct', 'points.supportCanManage', 'points.opMaxPerOperation', 'points.opMaxPerDay'] },
+ { key: 'partners', keys: ['partner.fotPct', 'partner.taxPct', 'partner.minTravelGapMinutes', 'partner.acceptTimeoutMinutes'] },
{ key: 'sales', keys: ['sales.bonusPerVenue', 'sales.bonusPerAgency', 'sales.bonusAgencyPct', 'sales.bonusAgencyMonths'] },
{ key: 'site', keys: ['relocation.hotelWithPlus', 'relocation.hotelBase', 'relocation.consultation', 'docs.fromPrice', 'docs.socialCardPrice', 'residence.escortFrom', 'residence.stateFee', 'transfer.standardPrice', 'transfer.premiumPrice'] },
{ key: 'other', keys: ['chat.closeAfterHours', 'files.retentionDays', 'consent.version'] },
diff --git a/apps/backoffice/src/pages/Agencies.tsx b/apps/backoffice/src/pages/Agencies.tsx
index 834b092..e58a05a 100644
--- a/apps/backoffice/src/pages/Agencies.tsx
+++ b/apps/backoffice/src/pages/Agencies.tsx
@@ -26,6 +26,15 @@ function CopyLink({ url }: { url: string }) {
}
export { CopyLink };
+const GIFT_MONTHS = [1, 2, 3, 6, 12] as const;
+type GiftMonths = (typeof GIFT_MONTHS)[number];
+const PLAN_NAME = { BAREV_PLUS: 'Barev+', ELITE: 'Barev Elite' } as const;
+
+/** «Barev+ на 3 мес.» или «без подарка» */
+function giftText(t: ReturnType['t'], a: { giftPlan: 'BAREV_PLUS' | 'ELITE' | null; giftMonths: number }) {
+ return a.giftPlan ? t('ag.giftValue', { plan: PLAN_NAME[a.giftPlan], n: a.giftMonths }) : t('ag.noGift');
+}
+
export function Agencies() {
const { t, amd } = useT();
const trpc = useTRPC();
@@ -64,7 +73,7 @@ export function Agencies() {
{a.name}
- {[a.code, `${a.commissionPct}%`, a.sales?.name].filter(Boolean).join(' · ')}
+ {[a.code, `${a.commissionPct}%`, giftText(t, a), a.sales?.name].filter(Boolean).join(' · ')}
{!a.active && {t('ag.inactive')}}
@@ -125,6 +134,8 @@ export function AgencyCard({ id }: { id: string }) {
{d.code}
{t('ag.pct', { n: d.commissionPct })}
+ 🎁 {giftText(t, d)}
+ {d.housewarmingPoints > 0 && 🪙 {t('ag.hwValue', { n: new Intl.NumberFormat('ru-RU').format(d.housewarmingPoints), days: d.housewarmingDays })}}
{d.sales && {t('ag.byS', { name: d.sales.name })}}
{t('prv.since', { date: date(d.createdAt) })}
{!d.active && {t('ag.inactive')}}
@@ -227,7 +238,7 @@ export function AgencyCard({ id }: { id: string }) {
);
}
-function AgencyDialog({ agency, onClose, onDone }: { agency?: { id: string; code: string; name: string; commissionPct: number; contact: string | null; note: string | null; active: boolean; sales: { id: string } | null }; onClose: () => void; onDone?: () => void }) {
+function AgencyDialog({ agency, onClose, onDone }: { agency?: { id: string; code: string; name: string; commissionPct: number; giftPlan: 'BAREV_PLUS' | 'ELITE' | null; giftMonths: number; housewarmingPoints: number; housewarmingDays: number; contact: string | null; note: string | null; active: boolean; sales: { id: string } | null }; onClose: () => void; onDone?: () => void }) {
const { t } = useT();
const trpc = useTRPC();
const qc = useQueryClient();
@@ -237,6 +248,10 @@ function AgencyDialog({ agency, onClose, onDone }: { agency?: { id: string; code
code: agency?.code ?? '',
name: agency?.name ?? '',
commissionPct: String(agency?.commissionPct ?? 10),
+ giftPlan: (agency ? (agency.giftPlan ?? 'NONE') : 'BAREV_PLUS') as 'BAREV_PLUS' | 'ELITE' | 'NONE',
+ giftMonths: (GIFT_MONTHS.includes(agency?.giftMonths as GiftMonths) ? agency!.giftMonths : 1) as GiftMonths,
+ hwPoints: String(agency?.housewarmingPoints ?? 0),
+ hwDays: String(agency?.housewarmingDays ?? 60),
contact: agency?.contact ?? '',
note: agency?.note ?? '',
active: agency?.active ?? true,
@@ -267,7 +282,7 @@ function AgencyDialog({ agency, onClose, onDone }: { agency?: { id: string; code
type="button"
className="bo-btn"
disabled={!f.name.trim() || !f.code.trim() || save.isPending}
- onClick={() => save.mutate({ id: agency?.id, code: f.code, name: f.name, commissionPct: Math.min(100, Number(f.commissionPct) || 0), contact: f.contact || null, note: f.note || null, active: f.active, salesId: f.salesId || null })}
+ onClick={() => save.mutate({ id: agency?.id, code: f.code, name: f.name, commissionPct: Math.min(100, Number(f.commissionPct) || 0), giftPlan: f.giftPlan === 'NONE' ? null : f.giftPlan, giftMonths: f.giftMonths, housewarmingPoints: Number(f.hwPoints) || 0, housewarmingDays: Number(f.hwDays) || 60, contact: f.contact || null, note: f.note || null, active: f.active, salesId: f.salesId || null })}
>
{t('ui.save')}
@@ -297,6 +312,32 @@ function AgencyDialog({ agency, onClose, onDone }: { agency?: { id: string; code
+
+
+
+
+
+
+
+
+
+
+ setF({ ...f, hwPoints: e.target.value.replace(/\D/g, '').slice(0, 7) })} />
+
+
+ setF({ ...f, hwDays: e.target.value.replace(/\D/g, '').slice(0, 4) })} />
+
+
setF({ ...f, contact: e.target.value })} placeholder={t('ag.contactPh')} />
diff --git a/apps/backoffice/src/pages/ClientCard.tsx b/apps/backoffice/src/pages/ClientCard.tsx
index d322ad1..c121b39 100644
--- a/apps/backoffice/src/pages/ClientCard.tsx
+++ b/apps/backoffice/src/pages/ClientCard.tsx
@@ -1,3 +1,4 @@
+import { ClientPoints } from './Points.tsx';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { navigate, useToast, useTRPC } from '@barev/web';
import { myChannels } from './Chats.tsx';
@@ -234,6 +235,7 @@ export function ClientCard({ id, me }: { id: string; me: Me }) {
+ {isSuper && }
{d.money && (
diff --git a/apps/backoffice/src/pages/Moves.tsx b/apps/backoffice/src/pages/Moves.tsx
index 5f7a78c..30c5b2e 100644
--- a/apps/backoffice/src/pages/Moves.tsx
+++ b/apps/backoffice/src/pages/Moves.tsx
@@ -519,14 +519,17 @@ export function Requests({ me }: { me: Me }) {
№{r.number} {shared(`services.${r.service.code}.name`)}
- {shared(`admin.webRequests.status_${r.status}`)}
+
+ {r.status !== 'ORDERED' && r.status !== 'CANCELLED' && (!r.preferredAt || !r.district || !r.addressText) && {t('rq.missing')}}
+ {shared(`admin.webRequests.status_${r.status}`)}
+
{paramsSummary(sharedT, r.service.code, r.params as Record)}
- {t('rq.wish')}: {dateTime(r.preferredAt)} · {t('rq.price')}: {amd(r.totalPrice)}
+ {t('rq.wish')}: {r.preferredAt ? dateTime(r.preferredAt) : t('rq.noTime')} · {t('rq.price')}: {amd(r.totalPrice)}
- {shared(`districts.${r.district.code}`)}, {r.addressText}
+ {[r.district ? shared(`districts.${r.district.code}`) : t('rq.noDistrict'), r.addressText ?? t('rq.noAddress')].join(', ')}
diff --git a/apps/backoffice/src/pages/NewOrder.tsx b/apps/backoffice/src/pages/NewOrder.tsx
index 0643357..13376b2 100644
--- a/apps/backoffice/src/pages/NewOrder.tsx
+++ b/apps/backoffice/src/pages/NewOrder.tsx
@@ -5,7 +5,7 @@ import { useEffect, useMemo, useState } from 'react';
import { errText, useT } from '../i18n.tsx';
import { Avatar, Dialog, Field, I, PlanBadge } from '../components/kit.tsx';
-type ParamField =
+export type ParamField =
| { key: string; type: 'select'; options: string[]; default?: string }
| { key: string; type: 'int'; min: number; max: number; default?: number }
| { key: string; type: 'text'; maxLength: number; required?: boolean }
@@ -262,7 +262,7 @@ export function NewOrderDialog({ clientId: fixedClient, onClose }: { clientId?:
);
}
-function ParamsForm({ service, fields, value, onChange }: { service: string; fields: ParamField[]; value: Params; onChange: (v: Params) => void }) {
+export function ParamsForm({ service, fields, value, onChange }: { service: string; fields: ParamField[]; value: Params; onChange: (v: Params) => void }) {
const { t, shared } = useT();
const label = (k: string) => {
const key = `params.${service}.${k}.label`;
diff --git a/apps/backoffice/src/pages/OrderCard.tsx b/apps/backoffice/src/pages/OrderCard.tsx
index bf5d6f3..cde03cc 100644
--- a/apps/backoffice/src/pages/OrderCard.tsx
+++ b/apps/backoffice/src/pages/OrderCard.tsx
@@ -5,7 +5,7 @@ import type { Me } from '../App.tsx';
import { errText, useT } from '../i18n.tsx';
import { Avatar, Dialog, Field, I, PlanBadge, Skeleton } from '../components/kit.tsx';
import { GROUP_DOT, statusLabel } from './Orders.tsx';
-import { SlotPicker } from './NewOrder.tsx';
+import { ParamsForm, SlotPicker, type ParamField } from './NewOrder.tsx';
const MIN = 60_000;
@@ -15,7 +15,8 @@ export function OrderCard({ id, me }: { id: string; me: Me }) {
const qc = useQueryClient();
const toast = useToast();
const o = useQuery({ ...trpc.bo.orders.get.queryOptions({ id }), refetchInterval: 15_000 });
- const [dlg, setDlg] = useState<'reschedule' | 'cancel' | null>(null);
+ const [dlg, setDlg] = useState<'reschedule' | 'cancel' | 'edit' | null>(null);
+ const [check, setCheck] = useState<{ code: string; requiresPhoto: boolean } | null>(null);
const refresh = () => {
qc.invalidateQueries({ queryKey: trpc.bo.orders.get.queryKey({ id }) });
qc.invalidateQueries({ queryKey: trpc.bo.orders.candidates.queryKey({ id }) });
@@ -26,6 +27,7 @@ export function OrderCard({ id, me }: { id: string; me: Me }) {
const onError = (e: unknown) => toast(errText(t, e), 'error');
const transition = useMutation(trpc.bo.orders.transition.mutationOptions({ onSuccess: () => (refresh(), toast(t('ord.statusChanged'))), onError }));
const markPaid = useMutation(trpc.bo.orders.markPaid.mutationOptions({ onSuccess: () => (refresh(), toast(t('ord.paidDone'))), onError }));
+ const setChecklist = useMutation(trpc.bo.orders.checklist.mutationOptions({ onSuccess: refresh, onError }));
const chat = useMutation(trpc.bo.chats.openFor.mutationOptions({ onSuccess: (r) => navigate(`/chats/${r.id}`), onError }));
const canChat = me.roles.some((r) => r === 'SUPERADMIN' || r === 'SUPPORT' || r === 'CONCIERGE');
@@ -92,6 +94,11 @@ export function OrderCard({ id, me }: { id: string; me: Me }) {
{t('ord.details')}
+ {d.status !== 'CANCELLED' && (
+
+ )}
- {t('ord.when')}
@@ -143,9 +150,19 @@ export function OrderCard({ id, me }: { id: string; me: Me }) {
{d.checklist.map((c) => (
-
- {c.done && }
- {shared(`checklist.${c.code}`)}
- {c.requiresPhoto && !c.fileId && · {t('ord.needsPhoto')}}
+
+ {c.requiresPhoto && !c.fileId && !c.waived && · {t('ord.needsPhoto')}}
+ {c.waived && · {t('ord.noPhotoReason', { reason: c.waived })}}
+ {c.byStaff && · {t('ord.byStaff')}}
))}
@@ -332,6 +349,8 @@ export function OrderCard({ id, me }: { id: string; me: Me }) {
{dlg === 'reschedule' && setDlg(null)} onDone={refresh} />}
+ {dlg === 'edit' && setDlg(null)} onDone={refresh} />}
+ {check && setCheck(null)} onDone={refresh} />}
{dlg === 'cancel' && setDlg(null)} onDone={refresh} />}
>
);
@@ -379,7 +398,7 @@ function useOrderData(id: string) {
}
function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onChanged: () => void; canChat: boolean }) {
- const { t, shared } = useT();
+ const { t, shared, amd } = useT();
const trpc = useTRPC();
const toast = useToast();
const [showBusy, setShowBusy] = useState(false);
@@ -464,15 +483,28 @@ function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onC
) : (
{cands.data.free.map((c, i) => (
- -
+
-
{i + 1}
{c.name}
- {c.kind === 'company' && {t('ord.company')}}
+ {c.kind === 'company' && {t('ord.partner')}}
+ {c.best && {t('ord.best')}}
{c.tried && {t('ord.tried')}}
- {[c.rating != null ? `★ ${c.rating}` : null, c.languages.join(', ').toUpperCase(), ...c.reasons.map((r) => shared(`admin.reasons.${r}`)), t('ord.load', { n: c.load })].filter(Boolean).join(' · ')}
+ {[
+ c.rating != null ? `★ ${c.rating}` : null,
+ c.languages.join(', ').toUpperCase(),
+ ...c.reasons.map((r) => shared(`admin.reasons.${r}`)),
+ c.kind === 'company' && c.partnerFree != null ? t('ord.partnerFree', { n: c.partnerFree, of: c.partnerStaff ?? 0 }) : t('ord.load', { n: c.load }),
+ ]
+ .filter(Boolean)
+ .join(' · ')}
+ {c.margin != null && (
+
+ {t('ord.candMoney', { cost: amd(c.cost ?? 0), margin: amd(c.margin) })}
+
+ )}
+ }
+ >
+
+ setF({ ...f, code: e.target.value.toLowerCase().replace(/[^a-z_]/g, '') })} />
+
+ setF({ ...f, name })} />
+
+ {(['rateBarev', 'ratePlus', 'rateElite'] as const).map((k) => (
+
+ setF({ ...f, [k]: e.target.value.replace(/\D/g, '').slice(0, 3) })} />
+
+ ))}
+
+
+
+ );
+}
+
+function BonusDialog({ row, onClose }: { row: Dict['bonusTypes'][number] | null; onClose: () => void }) {
+ const { t } = useT();
+ const trpc = useTRPC();
+ const qc = useQueryClient();
+ const toast = useToast();
+ const [f, setF] = useState({ code: row?.code ?? '', name: l5(row?.name), defaultAmount: String(row?.defaultAmount ?? 1000), ttlDays: row?.ttlDays ? String(row.ttlDays) : '', active: row?.active ?? true });
+ const save = useMutation(trpc.bo.points.saveBonusType.mutationOptions({ onSuccess: () => (void qc.invalidateQueries(), onClose()), onError: (e) => toast(errText(t, e), 'error') }));
+ return (
+
+ );
+}
diff --git a/apps/backoffice/src/pages/ProviderCard.tsx b/apps/backoffice/src/pages/ProviderCard.tsx
index 12e1d34..da52d07 100644
--- a/apps/backoffice/src/pages/ProviderCard.tsx
+++ b/apps/backoffice/src/pages/ProviderCard.tsx
@@ -299,8 +299,10 @@ export function ProviderCard({ id, me }: { id: string; me: Me }) {
);
}
-function rateText(t: ReturnType['t'], r: { kind: 'company' | 'preset' | 'own'; type?: string; value?: number; name?: string }) {
+function rateText(t: ReturnType['t'], r: { kind: 'company' | 'preset' | 'own'; type?: string; value?: number | null; name?: string }) {
if (r.kind === 'preset') return t('prv.ratePreset', { name: r.name ?? '' });
+ // сотрудник партнёра «как Uber» — зарплату ему платит партнёр
+ if (r.kind === 'company' && r.value == null) return t('prv.ratePartnerPays');
const v = r.type === 'PERCENT' ? `${r.value}%` : `${r.value} ֏`;
return r.kind === 'company' ? t('prv.rateCompany', { v }) : t('prv.rateOwn', { v });
}
diff --git a/apps/backoffice/src/pages/ServicePartners.tsx b/apps/backoffice/src/pages/ServicePartners.tsx
new file mode 100644
index 0000000..c7cda93
--- /dev/null
+++ b/apps/backoffice/src/pages/ServicePartners.tsx
@@ -0,0 +1,485 @@
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { formatDateTime, type Locale } from '@barev/i18n';
+import { navigate, useToast, useTRPC } from '@barev/web';
+import { useState } from 'react';
+import { errText, useT } from '../i18n.tsx';
+import { Avatar, Dialog, Field, I, Skeleton } from '../components/kit.tsx';
+import { CopyLink } from './Agencies.tsx';
+
+type Deal = 'PROFIT_SHARE' | 'COMMISSION';
+type Terms = { deal: Deal; commissionPct: number; profitSharePct: number; fotPct: number; taxPct: number };
+
+function useTermsText() {
+ const { t } = useT();
+ return (x: Terms) => (x.deal === 'COMMISSION' ? t('sp.terms.COMMISSION', { pct: x.commissionPct }) : t('sp.terms.PROFIT_SHARE', { pct: x.profitSharePct, fot: x.fotPct, tax: x.taxPct }));
+}
+
+/** Партнёры услуг: клининговые компании со своими сотрудниками и менеджером */
+export function ServicePartners() {
+ const { t, amd } = useT();
+ const trpc = useTRPC();
+ const terms = useTermsText();
+ const list = useQuery(trpc.bo.partners.servicePartners.queryOptions());
+ const [creating, setCreating] = useState(false);
+ return (
+ <>
+
+ {t('sp.title')}
+ setCreating(true)}>
+
+ {t('sp.add')}
+
+
+
+ {t('sp.lead')}
+
+ {!list.data ? (
+
+ ) : list.data.length === 0 ? (
+ {t('sp.empty')}
+ ) : (
+
+ )}
+ {creating && setCreating(false)} />}
+ >
+ );
+}
+
+export function ServicePartnerCard({ id }: { id: string }) {
+ const { t, amd, date, dateTime, locale, shared } = useT();
+ const trpc = useTRPC();
+ const qc = useQueryClient();
+ const toast = useToast();
+ const terms = useTermsText();
+ const c = useQuery(trpc.bo.partners.servicePartner.queryOptions({ id }));
+ const [dlg, setDlg] = useState<'edit' | 'payout' | null>(null);
+ const refresh = () => {
+ void qc.invalidateQueries({ queryKey: trpc.bo.partners.servicePartner.queryKey({ id }) });
+ void qc.invalidateQueries({ queryKey: trpc.bo.partners.servicePartners.queryKey() });
+ };
+ const reset = useMutation(trpc.bo.partners.resetManagerLink.mutationOptions({ onSuccess: () => (refresh(), toast(t('sp.linkReset'))), onError: (e) => toast(errText(t, e), 'error') }));
+ const removeManager = useMutation(trpc.bo.partners.removeManager.mutationOptions({ onSuccess: refresh, onError: (e) => toast(errText(t, e), 'error') }));
+ const back = (
+
+
+ {t('sp.back')}
+
+ );
+ if (!c.data)
+ return (
+ <>
+ {back}
+ {c.isError ? {errText(t, c.error)} : }
+ >
+ );
+ const d = c.data;
+ return (
+ <>
+ {back}
+
+
+
+
+
+
+ {t('sp.managerLink')}
+ confirm(t('sp.resetConfirm')) && reset.mutate({ id })}>
+ {t('sp.resetLink')}
+
+
+
+ {t('sp.managerLinkHint')}
+
+
+
+ {t('sp.managers')}
+
+ {d.managers.length === 0 ? (
+ {t('sp.noManagers')}
+ ) : (
+
+ {d.managers.map((m) => (
+ -
+
+ {m.name}
+
+ {t('sp.managerSince', { date: date(m.since) })}
+
+
+ confirm(t('sp.removeManagerConfirm', { name: m.name })) && removeManager.mutate({ id: m.id })}>
+ {t('sp.remove')}
+
+
+ ))}
+
+ )}
+
+
+
+
+ {t('sp.staff')}
+ {t('sp.staffHint')}
+
+ {d.staff.length === 0 ? (
+ {t('sp.noStaff')}
+ ) : (
+
+ )}
+
+
+
+
+ {t('sp.orders')}
+
+ {d.orders.length === 0 ? (
+ {t('sp.noOrders')}
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {t('sp.toPay')}
+
+
+ {amd(d.money.balance)}
+
+
+
+ {t('ag.accrued')} {amd(d.money.accrued)}
+
+
+ {t('prv.paidTotal')} {amd(d.money.paid)}
+
+
+ setDlg('payout')}>
+ {t('prv.payout')}
+
+ {d.money.months.length > 0 && (
+
+ {d.money.months.map((m) => (
+ -
+
+ {formatDateTime(locale as Locale, new Date(`${m.period}-15T12:00:00+04:00`), { month: 'long', year: 'numeric' })}
+
+
+ {t('ag.orders', { n: m.orders })} · {amd(m.revenue)}
+
+ {amd(m.amount)}
+
+ ))}
+
+ )}
+
+
+
+ {t('sp.byOrder')}
+
+ {d.money.recent.length === 0 ? (
+ {t('sp.noIncome')}
+ ) : (
+
+ )}
+
+ {d.note && (
+
+ )}
+
+
+ {dlg === 'edit' && setDlg(null)} onDone={refresh} />}
+ {dlg === 'payout' && setDlg(null)} onDone={refresh} />}
+ >
+ );
+}
+
+type PartnerRow = {
+ id: string;
+ name: string;
+ contactPhone: string | null;
+ note: string | null;
+ active: boolean;
+ deal: Deal;
+ commissionPct: number;
+ profitSharePct: number;
+ fotPct: number | null;
+ taxPct: number | null;
+ defaults: { fotPct: number; taxPct: number };
+};
+
+function PartnerDialog({ partner, onClose, onDone }: { partner?: PartnerRow; onClose: () => void; onDone?: () => void }) {
+ const { t, amd } = useT();
+ const trpc = useTRPC();
+ const qc = useQueryClient();
+ const toast = useToast();
+ const settings = useQuery({ ...trpc.bo.settings.get.queryOptions(), enabled: !partner });
+ const defaults = partner?.defaults ?? { fotPct: settings.data?.['partner.fotPct'] ?? 50, taxPct: settings.data?.['partner.taxPct'] ?? 10 };
+ const [f, setF] = useState({
+ name: partner?.name ?? '',
+ contactPhone: partner?.contactPhone ?? '',
+ note: partner?.note ?? '',
+ active: partner?.active ?? true,
+ deal: partner?.deal ?? ('COMMISSION' as Deal),
+ commissionPct: String(partner?.commissionPct ?? 30),
+ profitSharePct: String(partner?.profitSharePct ?? 50),
+ fotPct: partner?.fotPct == null ? '' : String(partner.fotPct),
+ taxPct: partner?.taxPct == null ? '' : String(partner.taxPct),
+ });
+ const num = (s: string) => Math.min(100, Number(s) || 0);
+ const opt = (s: string) => (s === '' ? null : num(s));
+ // пример на 20 000 ֏, чтобы было видно, как считается
+ const ex = 20_000;
+ const fot = opt(f.fotPct) ?? defaults.fotPct;
+ const tax = opt(f.taxPct) ?? defaults.taxPct;
+ const example =
+ f.deal === 'COMMISSION'
+ ? t('sp.exampleCOMMISSION', { sum: amd(ex), ours: amd(Math.floor((ex * num(f.commissionPct)) / 100)), partner: amd(ex - Math.floor((ex * num(f.commissionPct)) / 100)) })
+ : (() => {
+ const fotS = Math.floor((ex * fot) / 100);
+ const taxS = Math.floor((ex * tax) / 100);
+ const profit = Math.max(0, ex - fotS - taxS);
+ const p = Math.floor((profit * num(f.profitSharePct)) / 100);
+ return t('sp.examplePROFIT_SHARE', { sum: amd(ex), fot: amd(fotS), tax: amd(taxS), profit: amd(profit), partner: amd(p), ours: amd(profit - p) });
+ })();
+ const save = useMutation(
+ trpc.bo.partners.saveServicePartner.mutationOptions({
+ onSuccess: (r) => {
+ void qc.invalidateQueries({ queryKey: trpc.bo.partners.servicePartners.queryKey() });
+ onDone?.();
+ onClose();
+ if (!partner) navigate(`/service-partners/${r.id}`);
+ },
+ onError: (e) => toast(errText(t, e), 'error'),
+ }),
+ );
+ return (
+
+ );
+}
+
+function PartnerPayout({ id, balance, onClose, onDone }: { id: string; balance: number; onClose: () => void; onDone: () => void }) {
+ const { t, amd } = useT();
+ const trpc = useTRPC();
+ const toast = useToast();
+ const [amount, setAmount] = useState(String(balance));
+ const [note, setNote] = useState('');
+ const save = useMutation(
+ trpc.bo.partners.servicePartnerPayout.mutationOptions({
+ onSuccess: () => {
+ onDone();
+ toast(t('prv.payoutDone'));
+ onClose();
+ },
+ onError: (e) => toast(errText(t, e), 'error'),
+ }),
+ );
+ return (
+
+ );
+}
diff --git a/apps/bot-client/src/index.ts b/apps/bot-client/src/index.ts
index cae5b1d..5a1273d 100644
--- a/apps/bot-client/src/index.ts
+++ b/apps/bot-client/src/index.ts
@@ -14,6 +14,11 @@ import {
giveConsent,
rateOrder,
linkWebRequest,
+ clientPoints,
+ pointsHistory,
+ completeWebRequest,
+ webRequestSlots,
+ type LinkResult,
setClientChannel,
setLocale,
startClient,
@@ -41,6 +46,8 @@ const bot = new Bot(token || 'disabled:token');
/** Ожидаем ввод кода агентства от этих чатов */
const awaitingCode = new Set();
+/** Заявка с сайта без адреса: следующий текст — адрес (chatId → заявка) */
+const awaitingAddress = new Map();
/** Низкая оценка: следующий текст — комментарий к ней (chatId → заказ и оценка) */
const awaitingRatingComment = new Map();
@@ -75,9 +82,11 @@ async function askConsent(c: Context, locale: Locale) {
await c.reply(t('bot.client.consentText', { url: `${LANDING}/${locale}/privacy` }), { reply_markup: kb, parse_mode: 'HTML', link_preview_options: { is_disabled: true } });
}
-async function showMain(c: Context, locale: Locale, gift?: { endsAt: Date } | null) {
+const planName = (plan: string) => (plan === 'ELITE' ? 'Barev Elite' : 'Barev+');
+
+async function showMain(c: Context, locale: Locale, gift?: { endsAt: Date; plan: string } | null) {
const t = createT(locale);
- if (gift) await c.reply(t('bot.client.giftActivated', { date: formatDateTime(locale, gift.endsAt, { dateStyle: 'long' }) }));
+ if (gift) await c.reply(t('bot.client.giftActivated', { plan: planName(gift.plan), date: formatDateTime(locale, gift.endsAt, { dateStyle: 'long' }) }));
await c.reply(t('bot.client.welcome'), { reply_markup: mainKeyboard(locale) });
}
@@ -87,19 +96,107 @@ async function continueOnboarding(c: Context, locale: Locale) {
return showMain(c, locale);
}
+// ───── заявка с сайта: доспросить район, адрес и время ─────
+
+async function webRequestDone(c: Context, locale: Locale, link: LinkResult) {
+ const t = createT(locale);
+ if (link.kind === 'ordered') {
+ const date = formatDateTime(locale, link.scheduledAt, { weekday: 'long', day: 'numeric', month: 'long', hour: '2-digit', minute: '2-digit' });
+ await c.reply(t('bot.client.webRequestOrdered', { request: link.requestNumber, order: link.orderNumber, date }));
+ } else if (link.kind === 'linked' || link.kind === 'incomplete') {
+ await c.reply(t('bot.client.webRequestLinked', { request: link.requestNumber }));
+ }
+}
+
+/** Следующий вопрос по заявке: сначала район, потом адрес, потом день и время */
+async function webRequestStep(c: Context, locale: Locale, clientId: string, link: Extract, first = false) {
+ const t = createT(locale);
+ const chatId = c.chat!.id;
+ if (first) await c.reply(t('bot.client.wr.intro', { request: link.requestNumber }));
+ const next = link.missing[0];
+ if (next === 'district') {
+ const kb = new InlineKeyboard();
+ const districts = await db.district.findMany({ orderBy: { sortOrder: 'asc' } });
+ districts.forEach((d, i) => {
+ kb.text(t(`districts.${d.code}`), `wrd:${link.requestId}:${d.code}`);
+ if (i % 2 === 1) kb.row();
+ });
+ await c.reply(t('bot.client.wr.askDistrict'), { reply_markup: kb });
+ return;
+ }
+ if (next === 'address') {
+ awaitingAddress.set(chatId, link.requestId);
+ await c.reply(t('bot.client.wr.askAddress'));
+ return;
+ }
+ const days = await webRequestSlots(ctx, { requestId: link.requestId, clientId });
+ if (!days.length) {
+ await c.reply(t('bot.client.wr.noSlots'));
+ return showMain(c, locale);
+ }
+ const kb = new InlineKeyboard();
+ days.slice(0, 8).forEach((d, i) => {
+ kb.text(formatDateTime(locale, d.starts[0]!, { weekday: 'short', day: 'numeric', month: 'short' }), `wrday:${link.requestId}:${d.dateKey}`);
+ if (i % 2 === 1) kb.row();
+ });
+ await c.reply(t('bot.client.wr.askDay'), { reply_markup: kb });
+}
+
+async function webRequestAnswer(c: Context, input: { requestId: string; districtCode?: string; addressText?: string; preferredAt?: Date }) {
+ const client = await getClientByTelegramId(db, BigInt(c.from!.id));
+ if (!client) return;
+ const locale = client.user.locale as Locale;
+ try {
+ const res = await completeWebRequest(ctx, { ...input, clientId: client.id });
+ if (res.kind === 'incomplete') return webRequestStep(c, locale, client.id, res);
+ await webRequestDone(c, locale, res);
+ return showMain(c, locale);
+ } catch (e) {
+ if (e instanceof DomainError) return void (await c.reply(createT(locale)(`errors.${e.code}`)));
+ throw e;
+ }
+}
+
+bot.callbackQuery(/^wrd:(\w+):(\w+)$/, async (c) => {
+ await c.answerCallbackQuery();
+ await c.editMessageReplyMarkup().catch(() => undefined);
+ await webRequestAnswer(c, { requestId: c.match[1]!, districtCode: c.match[2]! });
+});
+
+bot.callbackQuery(/^wrday:(\w+):(\d{4}-\d{2}-\d{2})$/, async (c) => {
+ await c.answerCallbackQuery();
+ const client = await getClientByTelegramId(db, BigInt(c.from.id));
+ if (!client) return;
+ const locale = client.user.locale as Locale;
+ const t = createT(locale);
+ const [day] = await webRequestSlots(ctx, { requestId: c.match[1]!, clientId: client.id, dateKey: c.match[2]! }).catch(() => []);
+ if (!day) return void (await c.reply(t('bot.client.wr.dayFull')));
+ const kb = new InlineKeyboard();
+ day.starts.slice(0, 24).forEach((s, i) => {
+ kb.text(formatDateTime(locale, s, { hour: '2-digit', minute: '2-digit' }), `wrt:${c.match[1]}:${Math.round(s.getTime() / 60_000).toString(36)}`);
+ if (i % 4 === 3) kb.row();
+ });
+ await c.editMessageText(t('bot.client.wr.askTime', { day: formatDateTime(locale, day.starts[0]!, { weekday: 'long', day: 'numeric', month: 'long' }) }), { reply_markup: kb }).catch(() => c.reply(t('bot.client.wr.askTime'), { reply_markup: kb }));
+});
+
+bot.callbackQuery(/^wrt:(\w+):([0-9a-z]+)$/, async (c) => {
+ await c.answerCallbackQuery();
+ await c.editMessageReplyMarkup().catch(() => undefined);
+ await webRequestAnswer(c, { requestId: c.match[1]!, preferredAt: new Date(parseInt(c.match[2]!, 36) * 60_000) });
+});
+
bot.command('start', async (c) => {
const res = await startClient(ctx, c.from!, c.match || undefined);
// пришёл с сайта после заявки: язык и согласие уже есть — сразу говорим, что с заявкой
const token = decodeStartPayload(c.match).token;
const link = token ? await linkWebRequest(ctx, token, res.clientId) : null;
if (link && link.kind !== 'none') {
- const t = createT(res.locale);
- if (link.kind === 'ordered') {
- const date = formatDateTime(res.locale, link.scheduledAt, { weekday: 'long', day: 'numeric', month: 'long', hour: '2-digit', minute: '2-digit' });
- await c.reply(t('bot.client.webRequestOrdered', { request: link.requestNumber, order: link.orderNumber, date }));
- } else {
- await c.reply(t('bot.client.webRequestLinked', { request: link.requestNumber }));
+ if (link.kind === 'incomplete') {
+ const gift = link.gift ?? res.gift;
+ if (gift) await c.reply(createT(res.locale)('bot.client.giftActivated', { plan: planName(gift.plan), date: formatDateTime(res.locale, gift.endsAt, { dateStyle: 'long' }) }));
+ return webRequestStep(c, res.locale, res.clientId, link, true);
}
+ await webRequestDone(c, res.locale, link);
return showMain(c, res.locale, link.gift ?? res.gift);
}
if (res.needsLocale) {
@@ -158,6 +255,41 @@ bot.command('app', async (c) => {
bot.command('help', async (c) => c.reply(createT(await localeOf(c.from))('bot.client.help')));
+// ───── барики ─────
+
+const fmtPts = (locale: Locale, n: number) => new Intl.NumberFormat(locale === 'zh' ? 'zh-CN' : locale).format(n);
+const pointsKb = (locale: Locale) => (APP_URL.startsWith('https://') ? new InlineKeyboard().webApp(createT(locale)('bot.client.points.open'), `${APP_URL}?r=/points`) : undefined);
+
+bot.command('balance', async (c) => {
+ const client = await getClientByTelegramId(db, BigInt(c.from!.id));
+ const locale = await localeOf(c.from);
+ if (!client) return;
+ const t = createT(locale);
+ const p = await clientPoints(ctx, client.id);
+ const lines = [t('bot.client.points.balance', { balance: fmtPts(locale, p.balance) })];
+ if (p.pending) lines.push(t('bot.client.points.pending', { pending: fmtPts(locale, p.pending), date: p.pendingNextAt ? formatDateTime(locale, p.pendingNextAt, { day: 'numeric', month: 'long' }) : '—' }));
+ if (p.burnAt) lines.push(t('bot.client.points.burn', { date: formatDateTime(locale, p.burnAt, { day: 'numeric', month: 'long' }) }));
+ await c.reply(lines.join('\n'), { reply_markup: pointsKb(locale) });
+});
+
+bot.command('history', async (c) => {
+ const client = await getClientByTelegramId(db, BigInt(c.from!.id));
+ const locale = await localeOf(c.from);
+ if (!client) return;
+ const t = createT(locale);
+ const rows = await pointsHistory(db, client.id, { take: 10 });
+ if (!rows.length) return void (await c.reply(t('bot.client.points.empty')));
+ const name = (m: Record | null) => (m ? m[locale] || m.ru || '' : '');
+ const text = rows
+ .map((r) => {
+ const sign = r.amount > 0 ? '+' : '−';
+ const what = r.type === 'bonus' ? name(r.bonus) : r.type === 'accrual' ? name(r.category) : t(`bot.client.points.type.${r.type}`);
+ return `${formatDateTime(locale, r.at, { day: '2-digit', month: '2-digit' })} ${sign}${fmtPts(locale, Math.abs(r.amount))} · ${what}${r.orderRef ? ` ${r.orderRef}` : ''} · ${t(`bot.client.points.status.${r.status}`)}`;
+ })
+ .join('\n');
+ await c.reply(text, { reply_markup: pointsKb(locale) });
+});
+
/** Сообщение в чат команды: подписчик пишет консьержу, остальные — поддержке. Ответ придёт сюда же */
async function toTeam(c: Context, text: string, file?: ChatFile) {
const locale = await localeOf(c.from);
@@ -228,6 +360,12 @@ bot.on('message:text', async (c) => {
await rateOrder(ctx, { orderId: pending.orderId, clientId: client.id, score: pending.score, comment: c.message.text.slice(0, 1000) }).catch(() => undefined);
return toTeam(c, c.message.text);
}
+ // адрес для заявки с сайта
+ const requestId = awaitingAddress.get(c.chat.id);
+ if (requestId && client) {
+ awaitingAddress.delete(c.chat.id);
+ return webRequestAnswer(c, { requestId, addressText: c.message.text });
+ }
if (!awaitingCode.has(c.chat.id)) return toTeam(c, c.message.text);
if (!client) return;
try {
@@ -256,6 +394,8 @@ async function main() {
{ command: 'start', description: t('bot.client.cmdStart') },
{ command: 'app', description: t('bot.client.cmdApp') },
{ command: 'code', description: t('bot.client.cmdCode') },
+ { command: 'balance', description: t('bot.client.cmdBalance') },
+ { command: 'history', description: t('bot.client.cmdHistory') },
{ command: 'support', description: t('bot.client.cmdSupport') },
{ command: 'concierge', description: t('bot.client.cmdConcierge') },
{ command: 'language', description: t('bot.client.cmdLanguage') },
diff --git a/apps/bot-pro/src/index.ts b/apps/bot-pro/src/index.ts
index 1d07ce1..8057c21 100644
--- a/apps/bot-pro/src/index.ts
+++ b/apps/bot-pro/src/index.ts
@@ -9,6 +9,12 @@ import {
acceptPartnerInvite,
addProviderMessage,
checkCard,
+ accruePoints,
+ confirmRedemption,
+ getSettings,
+ previewAccrual,
+ rejectRedemption,
+ createProWebLogin,
DomainError,
linkByInvite,
peerName,
@@ -42,12 +48,25 @@ async function identity(c: Context) {
}
const localeOf = (id: Awaited>): Locale => (id?.user.locale as Locale) ?? 'ru';
-function cabinetKeyboard(locale: Locale) {
+function cabinetKeyboard(locale: Locale, manager = false) {
const kb = new InlineKeyboard();
- if (APP_URL.startsWith('https://')) kb.webApp(createT(locale)('bot.pro.openCabinet'), APP_URL);
+ if (APP_URL.startsWith('https://')) kb.webApp(createT(locale)('bot.pro.openCabinet'), APP_URL).row();
+ // менеджер партнёра может открыть кабинет и на компьютере
+ if (manager) kb.text(createT(locale)('bot.pro.openWeb'), 'web');
return kb;
}
+/** Одноразовая ссылка на кабинет в браузере (15 минут) */
+async function sendWebLink(c: Context) {
+ const id = await identity(c);
+ const t = createT(localeOf(id));
+ if (!id || id.companies.length === 0) return void (await c.reply(t('bot.pro.notLinked')));
+ const code = await createProWebLogin(ctx, id.user.id);
+ const url = `${APP_URL || 'http://localhost:5175'}/?login=${code}#/company`;
+ const kb = url.startsWith('https://') ? new InlineKeyboard().url(t('bot.pro.openWeb'), url) : undefined;
+ await c.reply(t('bot.pro.webLink', { url }), { reply_markup: kb, link_preview_options: { is_disabled: true } });
+}
+
async function greet(c: Context) {
const id = await identity(c);
const locale = localeOf(id);
@@ -61,7 +80,7 @@ async function greet(c: Context) {
...id.companies.map((co) => t('bot.pro.youAreDispatcher', { company: co.name })),
...id.partners.map((p) => t(p.role === 'OWNER' ? 'bot.partner.youAreOwner' : 'bot.partner.youAreStaff', { partner: p.name })),
].filter(Boolean);
- await c.reply(`${roles.join('\n')}\n\n${t('bot.pro.welcome')}`, { reply_markup: cabinetKeyboard(locale) });
+ await c.reply(`${roles.join('\n')}\n\n${t('bot.pro.welcome')}`, { reply_markup: cabinetKeyboard(locale, id.companies.length > 0) });
}
/** Оператор админки, привязавший этот Telegram */
@@ -173,6 +192,11 @@ bot.command('start', async (c) => {
});
bot.command('app', greet);
+bot.command('web', sendWebLink);
+bot.callbackQuery('web', async (c) => {
+ await c.answerCallbackQuery();
+ await sendWebLink(c);
+});
/** PRO-5: принять / отклонить из уведомления */
bot.callbackQuery(/^offer:(accept|decline):(\w+)$/, async (c) => {
@@ -214,6 +238,84 @@ bot.callbackQuery(/^rd:(\w+):(\w+)$/, async (c) => {
});
/** «Ответить» под уведомлением о сообщении */
+// ───── барики: быстрые действия команды ─────
+
+/** Кто может управлять бариками из бота: суперадмин или поддержка, если разрешено в настройках */
+async function pointsActor(c: Context) {
+ const admin = await adminOf(c);
+ if (!admin) return null;
+ const owner = admin.roles.includes('SUPERADMIN');
+ if (!owner && !(admin.roles.includes('SUPPORT') && (await getSettings(db))['points.supportCanManage'])) return null;
+ return { adminId: admin.id, owner };
+}
+const fmt = (n: number) => new Intl.NumberFormat('ru-RU').format(n);
+async function pointsError(c: Context, e: unknown) {
+ if (!(e instanceof DomainError)) throw e;
+ await c.reply(adminT(`errors.${e.code}`));
+}
+
+bot.callbackQuery(/^pr:(ok|no):(\w+)$/, async (c) => {
+ await c.answerCallbackQuery();
+ const actor = await pointsActor(c);
+ if (!actor) return void (await c.reply(adminT('bot.admin.notAdmin')));
+ const r = await db.pointsRedemption.findUnique({ where: { id: c.match[2]! }, include: { order: true } });
+ if (!r) return;
+ try {
+ if (c.match[1] === 'ok') {
+ if (!r.order) return;
+ const res = await confirmRedemption(ctx, { redemptionId: r.id, orderAmount: r.order.totalPrice }, actor);
+ await c.editMessageReplyMarkup().catch(() => undefined);
+ await c.reply(adminT('bot.admin.points.confirmed', { amount: fmt(res.amount) }));
+ } else {
+ await rejectRedemption(ctx, { redemptionId: r.id, reason: 'declined' }, actor);
+ await c.editMessageReplyMarkup().catch(() => undefined);
+ await c.reply(adminT('bot.admin.points.rejected'));
+ }
+ } catch (e) {
+ await pointsError(c, e);
+ }
+});
+
+/** /barik <телефон или @username> <сумма заказа> [категория] — подсказка и кнопка «Начислить» */
+bot.command('barik', async (c) => {
+ const actor = await pointsActor(c);
+ if (!actor) return void (await c.reply(adminT('bot.admin.notAdmin')));
+ const parts = (c.match ?? '').trim().split(/\s+/).filter(Boolean);
+ if (parts.length < 2) return void (await c.reply(adminT('bot.admin.points.help')));
+ const [who, sumRaw, catRaw] = parts;
+ const sum = Number(sumRaw!.replace(/[^\d]/g, ''));
+ const digits = who!.replace(/[^\d]/g, '');
+ const user = who!.startsWith('@')
+ ? await db.user.findFirst({ where: { username: { equals: who!.slice(1), mode: 'insensitive' } }, include: { client: true } })
+ : digits.length >= 8
+ ? await db.user.findFirst({ where: { phone: { endsWith: digits.slice(-8) } }, include: { client: true } })
+ : null;
+ if (!user?.client) return void (await c.reply(adminT('bot.admin.points.noClient')));
+ const cat = await db.pointsCategory.findUnique({ where: { code: (catRaw ?? 'cleaning').toLowerCase() } });
+ if (!cat || !sum) return void (await c.reply(adminT('bot.admin.points.help')));
+ const p = await previewAccrual(db, { clientId: user.client.id, categoryId: cat.id, orderAmount: sum, serviceDate: new Date() }, await getSettings(db), new Date());
+ const name = [user.firstName, user.lastName].filter(Boolean).join(' ') || `@${user.username}`;
+ const catName = (cat.name as Record).ru ?? cat.code;
+ const tier = p.tier === 'ELITE' ? 'Elite' : p.tier === 'BAREV_PLUS' ? 'Barev+' : 'Barev';
+ const kb = new InlineKeyboard().text(adminT('bot.admin.points.accrue'), `pa:${user.client.id}:${cat.code}:${sum}`);
+ await c.reply(adminT('bot.admin.points.preview', { amount: fmt(p.suggested), name, what: catName, sum: fmt(sum), tier, rate: p.ratePct, date: formatDateTime('ru', p.availableAt, { day: 'numeric', month: 'long' }) }), { reply_markup: kb });
+});
+
+bot.callbackQuery(/^pa:(\w+):([a-z_]+):(\d+)$/, async (c) => {
+ await c.answerCallbackQuery();
+ const actor = await pointsActor(c);
+ if (!actor) return;
+ const cat = await db.pointsCategory.findUnique({ where: { code: c.match[2]! } });
+ if (!cat) return;
+ try {
+ const r = await accruePoints(ctx, { clientId: c.match[1]!, kind: 'ORDER', categoryId: cat.id, orderAmount: Number(c.match[3]), serviceDate: new Date(), channel: 'BOT', idempotencyKey: `bot:${c.callbackQuery.message?.message_id}:${c.match[1]}` }, actor);
+ await c.editMessageReplyMarkup().catch(() => undefined);
+ await c.reply(r.status === 'created' ? adminT('bot.admin.points.done', { amount: fmt(r.amount) }) : r.status === 'needs_approval' ? adminT('bot.admin.points.needsApproval') : adminT('bot.admin.points.zero'));
+ } catch (e) {
+ await pointsError(c, e);
+ }
+});
+
bot.callbackQuery(/^ar:(c|p|t):(\w+)$/, async (c) => {
const admin = await adminOf(c);
if (!admin) {
diff --git a/apps/landing/app/[locale]/clean/page.tsx b/apps/landing/app/[locale]/clean/page.tsx
index 21c9ba7..574c2bc 100644
--- a/apps/landing/app/[locale]/clean/page.tsx
+++ b/apps/landing/app/[locale]/clean/page.tsx
@@ -5,6 +5,7 @@ import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { CleanForm } from '../../../components/clean';
import { FooterContacts, LegalLine } from '../../../components/seo';
+import { LegalLinks } from '../../../components/legal';
import { BotLink, BotLinkProvider, LangMenu, LangSwitch } from '../../../components/client';
import { getCleaning } from '../../../lib/data';
@@ -113,7 +114,7 @@ export default async function CleanPage({ params }: { params: Promise<{ locale:
diff --git a/apps/landing/app/[locale]/pricing/page.tsx b/apps/landing/app/[locale]/pricing/page.tsx
new file mode 100644
index 0000000..99b82bd
--- /dev/null
+++ b/apps/landing/app/[locale]/pricing/page.tsx
@@ -0,0 +1,117 @@
+import { createT, formatAmd, isLocale, LOCALES, type Locale } from '@barev/i18n';
+import { Icon } from '@barev/ui';
+import { notFound } from 'next/navigation';
+import { LegalShell, legalMetadata } from '../../../components/legal';
+import { getCatalog } from '../../../lib/data';
+
+export const revalidate = 300;
+export const dynamicParams = false;
+export function generateStaticParams() {
+ return LOCALES.map((locale) => ({ locale }));
+}
+export function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
+ return legalMetadata(params, 'pricing');
+}
+
+interface Row {
+ id: string;
+ price: string;
+ vars?: Record;
+ href?: string;
+}
+
+/**
+ * Цены: подписки клуба и услуги, которые сейчас продаются. Все суммы — из настроек админки
+ * (как на главной и страницах услуг), поэтому страница не расходится с ботом.
+ */
+export default async function Pricing({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale: raw } = await params;
+ if (!isLocale(raw)) notFound();
+ const locale: Locale = raw;
+ const t = createT(locale);
+ const amd = (n: number) => formatAmd(locale, n);
+ const { offer, barevPlus, categories } = await getCatalog();
+ const cleaning = categories.find((c) => c.code === 'HOME')?.services.find((s) => s.code === 'cleaning')?.fromPrice ?? 0;
+ const from = (n: number) => t('pricing.from', { price: amd(n) });
+
+ const plans = [
+ { id: 'free', name: 'Barev', price: t('landing.club.free'), pct: 0 },
+ { id: 'plus', name: 'Barev+', price: t('landing.club.perMonth', { price: amd(barevPlus.monthlyPrice) }), pct: offer.plusMaxPct },
+ { id: 'elite', name: 'Barev Elite', price: t('landing.club.perMonth', { price: amd(offer.elitePrice) }), pct: offer.eliteMaxPct },
+ ] as const;
+
+ const groups: { id: 'HOME' | 'DOCS'; rows: Row[] }[] = [
+ {
+ id: 'HOME',
+ rows: [
+ { id: 'cleaning', price: from(cleaning), href: '/clean' },
+ { id: 'transferStandard', price: amd(offer.transferStandard), href: '/airport' },
+ { id: 'transferPremium', price: amd(offer.transferPremium), href: '/airport' },
+ { id: 'hotel', price: t('pricing.perDay', { price: from(offer.hotelWithPlus) }), vars: { base: amd(offer.hotelBase) } },
+ ],
+ },
+ {
+ id: 'DOCS',
+ rows: [
+ { id: 'socialCard', price: amd(offer.socialCard), href: '/social-card' },
+ { id: 'consultation', price: amd(offer.consultation), href: '/residence-permit' },
+ { id: 'residence', price: from(offer.residenceEscortFrom), vars: { fee: amd(offer.residenceStateFee) }, href: '/residence-permit' },
+ ],
+ },
+ ];
+
+ return (
+
+
+ {t('pricing.plansTitle')}
+ {t('pricing.plansNote')}
+
+ {plans.map((p) => (
+
+ {p.name}
+ {p.price}
+
+ {[1, 2, 3].map((n) => (
+ -
+
+ {t(`landing.club.${p.id}F${n}`, { pct: p.pct })}
+
+ ))}
+
+ {t(`pricing.planNote.${p.id}`, { days: barevPlus.giftDays })}
+
+ ))}
+
+
+
+
+ {t('pricing.servicesTitle')}
+ {t('pricing.servicesNote')}
+ {groups.map((g) => (
+
+ {t(`categories.${g.id}.name`)}
+
+ {g.rows.map((r) => (
+
+ ))}
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/apps/landing/app/[locale]/privacy/page.tsx b/apps/landing/app/[locale]/privacy/page.tsx
index 6b35843..6e3d20c 100644
--- a/apps/landing/app/[locale]/privacy/page.tsx
+++ b/apps/landing/app/[locale]/privacy/page.tsx
@@ -1,80 +1,22 @@
-import { createT, isLocale, LOCALES, type Locale } from '@barev/i18n';
-import { Logo } from '@barev/ui';
-import type { Metadata } from 'next';
+import { isLocale, LOCALES } from '@barev/i18n';
import { notFound } from 'next/navigation';
-import { RichText } from '../../../components/rich-text';
-import { FooterContacts, LegalLine } from '../../../components/seo';
-import { CONTACTS, languageAlternates } from '../../../lib/seo';
+import { LegalDocument, legalMetadata } from '../../../components/legal';
export const dynamicParams = false;
export function generateStaticParams() {
return LOCALES.map((locale) => ({ locale }));
}
-/** Разделы политики по порядку; тексты — privacy..title / privacy..body */
+/** Разделы по порядку; тексты — privacy..title / privacy..body */
const SECTIONS = ['operator', 'data', 'purposes', 'basis', 'recipients', 'location', 'retention', 'security', 'rights', 'marketing', 'cookies', 'age', 'changes'] as const;
-export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise {
- const { locale } = await params;
- if (!isLocale(locale)) return {};
- const t = createT(locale);
- return {
- title: `${t('privacy.title')} — Barev Club`,
- description: t('privacy.intro'),
- alternates: { canonical: `/${locale}/privacy`, languages: languageAlternates('/privacy') },
- // своё превью ссылки, иначе подставляется старый слоган из общего layout
- openGraph: { title: `${t('privacy.title')} — Barev Club`, description: t('privacy.intro'), locale, type: 'article', siteName: 'Barev Club' },
- twitter: { card: 'summary_large_image', title: `${t('privacy.title')} — Barev Club`, description: t('privacy.intro') },
- };
+export function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
+ return legalMetadata(params, 'privacy');
}
-/** ONB-3: политика конфиденциальности. Оператор — ИП владельца; основной текст на русском, переводы needs_review */
-export default async function Privacy({ params }: { params: Promise<{ locale: string }> }) {
- const { locale: raw } = await params;
- if (!isLocale(raw)) notFound();
- const locale: Locale = raw;
- const t = createT(locale);
- const vars = { email: CONTACTS.email, phone: CONTACTS.phoneDisplay, tin: CONTACTS.tin };
- return (
-
-
-
- {t('privacy.title')}
-
- {t('privacy.updated')}
- {t('privacy.intro')}
-
- {SECTIONS.map((s) => (
- -
- {t(`privacy.${s}.title`)}
-
- ))}
-
- {SECTIONS.map((s, i) => (
-
-
- {i + 1}. {t(`privacy.${s}.title`)}
-
-
-
- ))}
-
-
- );
+/** ONB-3: политика конфиденциальности. Оператор — ИП владельца. Основной текст на русском, переводы needs_review */
+export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params;
+ if (!isLocale(locale)) notFound();
+ return ;
}
diff --git a/apps/landing/app/[locale]/refund/page.tsx b/apps/landing/app/[locale]/refund/page.tsx
new file mode 100644
index 0000000..f333783
--- /dev/null
+++ b/apps/landing/app/[locale]/refund/page.tsx
@@ -0,0 +1,22 @@
+import { isLocale, LOCALES } from '@barev/i18n';
+import { notFound } from 'next/navigation';
+import { LegalDocument, legalMetadata } from '../../../components/legal';
+
+export const dynamicParams = false;
+export function generateStaticParams() {
+ return LOCALES.map((locale) => ({ locale }));
+}
+
+/** Разделы по порядку; тексты — refund..title / refund..body */
+const SECTIONS = ['cancelClient', 'cancelUs', 'quality', 'subscription', 'nonRefundable', 'howTo', 'timing'] as const;
+
+export function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
+ return legalMetadata(params, 'refund');
+}
+
+/** Правила отмены и возврата денег. Основной текст на русском, переводы needs_review */
+export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params;
+ if (!isLocale(locale)) notFound();
+ return ;
+}
diff --git a/apps/landing/app/[locale]/terms/page.tsx b/apps/landing/app/[locale]/terms/page.tsx
new file mode 100644
index 0000000..91c28a7
--- /dev/null
+++ b/apps/landing/app/[locale]/terms/page.tsx
@@ -0,0 +1,22 @@
+import { isLocale, LOCALES } from '@barev/i18n';
+import { notFound } from 'next/navigation';
+import { LegalDocument, legalMetadata } from '../../../components/legal';
+
+export const dynamicParams = false;
+export function generateStaticParams() {
+ return LOCALES.map((locale) => ({ locale }));
+}
+
+/** Разделы по порядку; тексты — terms..title / terms..body */
+const SECTIONS = ['about', 'acceptance', 'orders', 'prices', 'payment', 'cancel', 'subscription', 'perks', 'docs', 'client', 'quality', 'liability', 'content', 'changes', 'law'] as const;
+
+export function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
+ return legalMetadata(params, 'terms');
+}
+
+/** Условия использования сервиса (публичная оферта). Основной текст на русском, переводы needs_review */
+export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params;
+ if (!isLocale(locale)) notFound();
+ return ;
+}
diff --git a/apps/landing/app/clean.css b/apps/landing/app/clean.css
index 4a66b00..d943551 100644
--- a/apps/landing/app/clean.css
+++ b/apps/landing/app/clean.css
@@ -455,6 +455,33 @@ button.cl-extra {
color: #e9c9d5;
}
+/* телефон сразу под комнатами и санузлами — единственное обязательное поле, кроме параметров */
+.cl-hero-phone {
+ max-width: 420px;
+ margin-top: 4px;
+}
+.cl-hero-phone .bc-input {
+ background: #fff;
+}
+.cl-hero-phone[data-error='true'] .bc-input {
+ border-color: var(--bc-danger);
+}
+/* согласие на обработку данных — нажатием кнопки */
+.cl-consent-note {
+ margin: 0;
+ font-size: 12px;
+ line-height: 1.45;
+ color: #e9c9d5;
+}
+.cl-consent-note a {
+ color: inherit;
+}
+.cl-consent-note--mobile {
+ display: none;
+ color: var(--bc-ink-2, #6b5d57);
+ padding: 0 4px;
+}
+
/* нижняя панель — только на телефоне */
.cl-bar {
display: none;
@@ -659,6 +686,12 @@ button.cl-extra {
.cl-receipt .cl-btn-pink {
display: none;
}
+ .cl-receipt .cl-consent-note {
+ display: none;
+ }
+ .cl-consent-note--mobile {
+ display: block;
+ }
.cl-bar {
position: fixed;
left: 12px;
diff --git a/apps/landing/app/landing.css b/apps/landing/app/landing.css
index e05da8f..2802d12 100644
--- a/apps/landing/app/landing.css
+++ b/apps/landing/app/landing.css
@@ -419,6 +419,129 @@ a:hover {
.policy__footer a {
color: inherit;
}
+.policy__legal {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px 20px;
+ flex-basis: 100%;
+}
+
+/* страница цен */
+.pr-plans {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 12px;
+ margin-top: 16px;
+}
+.pr-plan {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ padding: 18px;
+ border-radius: 20px;
+ background: #fff;
+ border: 1.5px solid rgba(74, 16, 40, 0.12);
+}
+.pr-plan[data-plan='plus'] {
+ background: var(--bc-pink);
+ border-color: var(--bc-pink);
+}
+.pr-plan[data-plan='elite'] {
+ background: var(--bc-perks);
+ border-color: var(--bc-perks);
+}
+.pr-plan h3 {
+ margin: 0;
+ font-family: var(--bc-font-head);
+ font-weight: 800;
+ font-style: italic;
+ font-size: 26px;
+ line-height: 1.1;
+ color: var(--bc-plum);
+}
+.pr-plan__price {
+ font-family: var(--bc-font-head);
+ font-weight: 600;
+ font-size: 18px;
+ color: var(--bc-plum);
+}
+.pr-plan ul {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ margin: 4px 0 0;
+ padding: 0;
+ list-style: none;
+ font-size: 15px;
+ line-height: 1.4;
+}
+.pr-plan li {
+ display: flex;
+ gap: 8px;
+ align-items: flex-start;
+}
+.pr-plan li svg {
+ flex: none;
+ margin-top: 2px;
+ color: var(--bc-plum);
+}
+.pr-plan small {
+ margin-top: auto;
+ padding-top: 8px;
+ font-size: 13px;
+ line-height: 1.4;
+ color: var(--bc-ink-2);
+}
+.pr-group h3 {
+ margin: 24px 0 4px;
+ font-family: var(--bc-font-head);
+ font-size: 18px;
+ color: var(--bc-plum);
+}
+.pr-list {
+ margin: 0;
+ border-radius: 20px;
+ background: #fff;
+ padding: 4px 18px;
+}
+.pr-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 16px;
+ padding: 12px 0;
+}
+.pr-row + .pr-row {
+ border-top: 1px solid rgba(74, 16, 40, 0.1);
+}
+.pr-row dt {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ font-weight: 600;
+}
+.pr-row dt a {
+ color: inherit;
+}
+.pr-row dt small {
+ font-weight: 400;
+ font-size: 13px;
+ line-height: 1.4;
+ color: var(--bc-ink-2);
+}
+.pr-row dd {
+ margin: 0;
+ flex: none;
+ font-family: var(--bc-font-head);
+ font-weight: 600;
+ white-space: nowrap;
+ color: var(--bc-plum);
+}
+@media (max-width: 720px) {
+ .pr-plans {
+ grid-template-columns: minmax(0, 1fr);
+ }
+}
@media (max-width: 720px) {
.wrap {
padding: 12px 16px 24px;
diff --git a/apps/landing/components/clean.tsx b/apps/landing/components/clean.tsx
index 1cb7e14..55ea752 100644
--- a/apps/landing/components/clean.tsx
+++ b/apps/landing/components/clean.tsx
@@ -19,10 +19,11 @@ const API = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000';
const AGENCY_KEY = 'barev.agency';
const TYPES = ['regular', 'general', 'renovation'] as const;
-type Errors = Partial>;
+type Errors = Partial>;
/**
- * Страница /clean (модель qlean.ru): параметры → доп. услуги → время → адрес → контакты.
+ * Страница /clean (модель qlean.ru): параметры и телефон → доп. услуги → время → адрес → имя.
+ * Обязательны только тип уборки, комнаты, санузлы и телефон; время и адрес бот доспросит, а оператор уточнит.
* Цена считается в браузере той же функцией quote, что и на сервере. Заявка сразу видна в админке,
* а человек уходит в бота по ссылке, которая привязывает заявку к его Telegram.
*/
@@ -81,7 +82,6 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
const [note, setNote] = useState('');
const [phone, setPhone] = useState('');
const [name, setName] = useState('');
- const [consent, setConsent] = useState(false);
const [errors, setErrors] = useState({});
const [sending, setSending] = useState(false);
const [done, setDone] = useState<{ number: number; url: string } | null>(null);
@@ -96,11 +96,7 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
function validate(): Errors {
const e: Errors = {};
- if (!time) e.time = t('landing.clean.err.time');
- if (!district) e.district = t('landing.clean.err.district');
- if (street.trim().length < 3) e.street = t('landing.clean.err.street');
if (!/^\+?\d{8,15}$/.test(phone.replace(/[\s()\-.]/g, ''))) e.phone = t('landing.clean.err.phone');
- if (!consent) e.consent = t('landing.clean.err.consent');
return e;
}
@@ -127,9 +123,10 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
body: JSON.stringify({
json: {
params,
- preferredAt: time!.toISOString(),
- districtCode: district,
- addressText: street.trim(),
+ preferredAt: time?.toISOString(),
+ districtCode: district || undefined,
+ // короткий адрес не отправляем — бот спросит его заново
+ addressText: street.trim().length >= 3 ? street.trim() : undefined,
note: note.trim() || undefined,
phone,
name: name.trim() || undefined,
@@ -211,6 +208,30 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
+
@@ -254,7 +275,7 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
)}
-
+
{days.map((d) => (
-
+
)}
{t('landing.clean.after')}
+
@@ -403,6 +397,18 @@ export function CleanForm({ locale, config, messages }: { locale: Locale; config
);
}
+/** Согласие на обработку данных — нажатием кнопки, без отдельной галочки */
+function ConsentNote({ locale, t, className = 'cl-consent-note' }: { locale: Locale; t: (k: string) => string; className?: string }) {
+ return (
+
+ {t('landing.clean.consentByClick')}{' '}
+
+ {t('landing.clean.privacy')}
+
+
+ );
+}
+
function Block({ title, hint, error, children }: { title: string; hint?: string; error?: string; children: ReactNode }) {
return (
diff --git a/apps/landing/components/home.tsx b/apps/landing/components/home.tsx
index bb3bbb2..30e58ed 100644
--- a/apps/landing/components/home.tsx
+++ b/apps/landing/components/home.tsx
@@ -4,6 +4,7 @@ import type { Metadata } from 'next';
import { getCatalog, type LandingOffer } from '../lib/data';
import { BotLink } from './client';
import { SERVICE_PAGES } from '../lib/services';
+import { LegalLinks } from './legal';
import { FooterContacts, LegalLine } from './seo';
/** Главная (/) и «Уже живу» (/live): индексируются, у каждой свой canonical и hreflang */
@@ -102,7 +103,7 @@ export function HomeFooter({ locale }: { locale: Locale }) {
{t('landing.footer.partner')}
- {t('landing.footer.privacy')}
+
);
diff --git a/apps/landing/components/legal.tsx b/apps/landing/components/legal.tsx
new file mode 100644
index 0000000..45b998e
--- /dev/null
+++ b/apps/landing/components/legal.tsx
@@ -0,0 +1,107 @@
+import { createT, isLocale, LOCALES, type Locale } from '@barev/i18n';
+import { Logo } from '@barev/ui';
+import type { Metadata } from 'next';
+import type { ReactNode } from 'react';
+import { CONTACTS, languageAlternates } from '../lib/seo';
+import { RichText } from './rich-text';
+import { FooterContacts, LegalLine } from './seo';
+
+/** Страницы с ценами и правилами: их требуют платёжные провайдеры при проверке сайта */
+export const LEGAL_PAGES = ['pricing', 'terms', 'refund', 'privacy'] as const;
+export type LegalPageId = (typeof LEGAL_PAGES)[number];
+
+/** Ссылки на цены и правила — в подвал любой страницы */
+export function LegalLinks({ locale }: { locale: Locale }) {
+ const t = createT(locale);
+ return (
+ <>
+ {LEGAL_PAGES.map((p) => (
+
+ {t(`landing.footer.${p}`)}
+
+ ))}
+ >
+ );
+}
+
+/** Мета страницы: заголовок и описание из .title / .intro */
+export async function legalMetadata(params: Promise<{ locale: string }>, ns: LegalPageId): Promise {
+ const { locale } = await params;
+ if (!isLocale(locale)) return {};
+ const t = createT(locale);
+ const title = `${t(`${ns}.title`)} — Barev Club`;
+ const description = t(`${ns}.intro`);
+ return {
+ title,
+ description,
+ alternates: { canonical: `/${locale}/${ns}`, languages: languageAlternates(`/${ns}`) },
+ // своё превью ссылки, иначе подставляется слоган из общего layout
+ openGraph: { title, description, locale, type: 'article', siteName: 'Barev Club' },
+ twitter: { card: 'summary_large_image', title, description },
+ };
+}
+
+/** Каркас: логотип, языки, заголовок, подвал с реквизитами и ссылками на остальные правила */
+export function LegalShell({ locale, page, children }: { locale: Locale; page: LegalPageId; children: ReactNode }) {
+ const t = createT(locale);
+ return (
+
+
+
+ {t(`${page}.title`)}
+
+ {t(`${page}.updated`)}
+ {t(`${page}.intro`)}
+ {children}
+
+
+ );
+}
+
+/** Текст правил: оглавление и нумерованные разделы ..title / ..body */
+export function LegalDocument({ locale, ns, sections }: { locale: Locale; ns: Exclude; sections: readonly string[] }) {
+ const t = createT(locale);
+ const vars = { email: CONTACTS.email, phone: CONTACTS.phoneDisplay, tin: CONTACTS.tin };
+ return (
+
+
+ {sections.map((s) => (
+ -
+ {t(`${ns}.${s}.title`)}
+
+ ))}
+
+ {sections.map((s, i) => (
+
+
+ {i + 1}. {t(`${ns}.${s}.title`)}
+
+
+
+ ))}
+
+ );
+}
diff --git a/apps/landing/lib/seo.ts b/apps/landing/lib/seo.ts
index e04a3a3..dfaa298 100644
--- a/apps/landing/lib/seo.ts
+++ b/apps/landing/lib/seo.ts
@@ -3,7 +3,7 @@ import { LOCALES } from '@barev/i18n';
export const SITE = (process.env.LANDING_URL ?? 'http://localhost:3000').replace(/\/$/, '');
/** Страницы, которые должны быть в поиске; экспериментальные /landN закрыты noindex и сюда не входят */
-export const INDEXED_PATHS = ['', '/live', '/clean', '/social-card', '/residence-permit', '/airport', '/privacy'] as const;
+export const INDEXED_PATHS = ['', '/live', '/clean', '/social-card', '/residence-permit', '/airport', '/pricing', '/terms', '/refund', '/privacy'] as const;
/** hreflang для пути: все языки + x-default на русскую версию (абсолютные адреса для sitemap) */
export function languageAlternates(path: string, absolute = false): Record {
diff --git a/apps/landing/next-env.d.ts b/apps/landing/next-env.d.ts
index ce4e94a..a419cbe 100644
--- a/apps/landing/next-env.d.ts
+++ b/apps/landing/next-env.d.ts
@@ -1,7 +1,7 @@
///
///
-import "./.next/types/routes.d.ts";
-import "./.next/types/root-params.d.ts";
+import "./.next/dev/types/routes.d.ts";
+import "./.next/dev/types/root-params.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/apps/landing/tsconfig.tsbuildinfo b/apps/landing/tsconfig.tsbuildinfo
new file mode 100644
index 0000000..b5b4cca
--- /dev/null
+++ b/apps/landing/tsconfig.tsbuildinfo
@@ -0,0 +1 @@
+{"fileNames":["../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.esnext.float16.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/global.d.ts","../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/styled-jsx/types/css.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/styled-jsx/types/macro.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/styled-jsx/types/style.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/styled-jsx/types/global.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/styled-jsx/types/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/get-page-files.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/globals.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/crypto.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/events.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/utility.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/header.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/readable.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/fetch.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/formdata.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/connector.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/client-stats.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/client.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/errors.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/dispatcher.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/global-origin.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/pool-stats.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/pool.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/handlers.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/balanced-pool.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/round-robin-pool.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/h2c-client.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-call-history.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-client.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-pool.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/snapshot-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/mock-errors.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/proxy-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/socks5-proxy-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/retry-handler.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/retry-agent.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/api.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cache-interceptor.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/interceptors.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/util.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cookies.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/patch.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/websocket.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/eventsource.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/content-type.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/cache.d.ts","../../node_modules/.pnpm/undici-types@7.24.6/node_modules/undici-types/index.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/navigator.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/storage.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/web-globals/streams.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/assert.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/assert/strict.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/async_hooks.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/buffer.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/child_process.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/cluster.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/console.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/constants.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/crypto.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/dgram.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/dns.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/dns/promises.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/domain.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/events.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/fs.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/fs/promises.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/http.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/http2.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/https.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/inspector.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/inspector.generated.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/module.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/net.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/os.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/path.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/perf_hooks.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/process.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/punycode.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/querystring.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/readline.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/readline/promises.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/repl.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/sea.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/sqlite.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/stream.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/stream/promises.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/stream/consumers.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/stream/web.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/string_decoder.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/test.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/timers.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/timers/promises.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/tls.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/trace_events.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/tty.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/url.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/util.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/v8.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/vm.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/wasi.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/worker_threads.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/zlib.d.ts","../../node_modules/.pnpm/@types+node@24.19.2/node_modules/@types/node/index.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/canary.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/experimental.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/index.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/client.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/canary.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/experimental.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/fallback.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/search-params.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/segment-cache/vary-params-decoding.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/vary-params.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/params.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-kind.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/cache-control.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/webpack/webpack.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/entry-constants.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/constants.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/bundler.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/load-custom-routes.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/image-config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/body-streams.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-matches/route-match.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/app-router-headers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/setup-exception-listeners.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/worker.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/constants.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/api-utils/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/page-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/analysis/get-page-static-info.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/require-hook.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-polyfill-crypto.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-baseline.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/random.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/date.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/node-environment.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/page-extensions-type.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/rsc-transport.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/app-router-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/static-paths/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/get-supported-browsers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/rendering-mode.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/cpu-profile.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/adapter/setup-node-env.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/instrumentation/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/coalesced-function.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-utils/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/trace/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/trace/trace.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/trace/shared.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/trace/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/load-jsconfig.d.ts","../../node_modules/.pnpm/@next+env@16.4.2/node_modules/@next/env/dist/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/telemetry/storage.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/build-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/bloom-filter.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack-config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/swc/generated-native.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/swc/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/parse-version-info.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/shared/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/parse-stack.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/server/shared.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/request-insights.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/shared/request-insights.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/static.d.ts","../../node_modules/.pnpm/@types+react-dom@19.3.0_@types+react@19.3.0/node_modules/@types/react-dom/server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/app-render-prerender-utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/stream-ops.web.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/stream-ops.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/debug-channel.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/hot-reloader-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/i18n-provider.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/next-url.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/cookies.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/request.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/after/builtin-request-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/response.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/deep-readonly.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/render.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/mitt.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/with-router.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/router.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/route-loader.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/page-loader.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/router.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/readonly-url-search-params.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/vary-path.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/cache-map.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/navigation-testing-lock.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/scheduler.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/optimistic-routes.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/cache.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/segment-cache/decode-server-response.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/render-tree.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/templates/pages.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/pages/module.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/load-default-error-components.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/base-http/node.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/normalizer.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/request/suffix.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/request/rsc.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/request/next-data.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/incremental-cache/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/base-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/async-callback-set.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","../../node_modules/.pnpm/@img+colour@1.1.0/node_modules/@img/colour/index.d.ts","../../node_modules/.pnpm/sharp@0.35.5_@types+node@24.19.2/node_modules/sharp/dist/index.d.mts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/image-optimizer/transform.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/image-optimizer/image-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/image-optimizer.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/next-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/lru-cache.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/dev-bundler-service.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/static-paths-worker.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dev/next-dev-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/next.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/render-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/route-module.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/load-components.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/adapter.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/response-cache/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/cache-handlers/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/use-cache/use-cache-wrapper.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/turborepo-access-trace/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/turborepo-access-trace/result.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/turborepo-access-trace/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/export/routes/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/export/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/export/worker.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/worker.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/route-cache-key.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/response-cache/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/fallback-params.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/image-response.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/url-pattern.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/after/after.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/after/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/connection.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/exports/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request-meta.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/cli/next-test.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/use-cache/cache-life-profile.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/use-cache/cache-life.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/size-limit.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/config-shared.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/base-http/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/client-component-renderer-logger.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/render-result.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/app-dir-module.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/cache-signal.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/instant-validation/boundary-tracking.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/instant-validation/instant-validation-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/instant-validation/instant-samples.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/lazy-result.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/lib/implicit-tags.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/staged-rendering.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/dynamic-rendering-utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/segment-config/ensure-static.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/after/after-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/create-error-handler.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/debug-channel-server.web.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/debug-channel-server.node.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/debug-channel-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/instant-validation/instant-validation.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/typescript-utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/dev-validation-worker-globals.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/create-transport-tree-from-loader-tree.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/parse-request-headers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/app-render.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/error-boundary.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/layout-router.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/render-from-template-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/client-page.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/client-segment.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/hooks-server-context.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/extra-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/resolvers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/types/icons.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/metadata-resolution-primitives.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/metadata.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/metadata/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/lib/framework/boundary-components.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/rsc/preloads.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/postponed-state.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/rsc/taint.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/collect-segment-data.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/entry-base.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/templates/app-page.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/helpers/prerender-manifest-matcher.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/jsx-dev-runtime.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/jsx-runtime.d.ts","../../node_modules/.pnpm/@types+react@19.3.0/node_modules/@types/react/compiler-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/module.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/async-storage/work-store.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/http.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/redirect-status-code.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/redirect-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/templates/app-route.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-route/module.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/segment-config/app/app-segments.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/build/adapter/build-complete.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/router-transition-types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/utils.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/pages/_app.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/app.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/io.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/use-cache/cache-tag.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/cache-stages.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/cache.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/pages/_document.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/document.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/dynamic.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dynamic.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/pages/_error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/catch-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/api/error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/head.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/head.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/cookies.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/headers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/request/draft-mode.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/headers.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/get-img-props.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/image-external-get-image-props.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/api/image.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/image-component.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/shared/lib/image-external.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/image.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/link.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/link.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/unrecognized-action-error.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/redirect.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/not-found.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/forbidden.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/unauthorized.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/unstable-rethrow.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/navigation.react-server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/components/navigation.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/navigation.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/router.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/client/script.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/script.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@vercel/og/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/server.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/types/global.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/types/compiled.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/image-types/global.d.ts","./.next/dev/types/routes.d.ts","./.next/dev/types/root-params.d.ts","./next-env.d.ts","./next.config.ts","../../packages/i18n/locales/ru.json","../../packages/i18n/locales/en.json","../../packages/i18n/locales/zh.json","../../packages/i18n/locales/hy.json","../../packages/i18n/locales/es.json","../../packages/i18n/src/index.ts","./lib/seo.ts","./app/robots.ts","./app/sitemap.ts","./lib/flats.ts","./app/api/flats/photo/[id]/[index]/route.ts","./app/api/flats/request/route.ts","../../packages/core/src/types.ts","../../packages/core/src/flows/types.ts","../../packages/core/src/flows/definitions.ts","../../packages/core/src/flows/machine.ts","../../packages/core/src/flows/index.ts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/json-schema.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/standard-schema.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/registries.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/to-json-schema.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/versions.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/schemas.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/checks.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/errors.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/core.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/parse.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/memoizer.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/regexes.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ar.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/az.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/be.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/bg.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/bn.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ca.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ckb.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/cs.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/da.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/de.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/el.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/en.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/eo.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/es.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/fa.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/fi.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/fr.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/fr-ca.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/gu.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/he.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/hi.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/hr.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/hu.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/hy.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/id.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/is.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/it.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ja.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ka.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/kh.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/km.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/kn.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ko.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/lt.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/mk.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ms.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ne.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/nl.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/nn.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/no.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ota.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ps.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/pl.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/pt.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/pt-br.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ro.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ru.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/sk.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/sl.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/sv.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ta.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/tg.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/th.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/tk.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/tr.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ua.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/uk.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/ur.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/uz.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/vi.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/zh-cn.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/zh-tw.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/yo.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/index.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/doc.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/compile.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/api.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/json-schema-processors.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/json-schema-generator.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/index.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/errors.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/parse.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/schemas.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/checks.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/compat.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/from-json-schema.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/deep-partial.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/in-out.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/iso.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/coerce.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/external.d.cts","../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/index.d.cts","../../packages/core/src/params.ts","../../packages/core/src/pricing.ts","../../packages/core/src/time.ts","../../packages/core/src/slots.ts","../../packages/core/src/assignment.ts","../../packages/core/src/cancellation.ts","../../packages/core/src/deeplink.ts","../../packages/core/src/membership.ts","../../packages/core/src/promo.ts","../../packages/core/src/settings.ts","../../packages/core/src/payments.ts","../../packages/core/src/catalog.ts","../../packages/core/src/payout.ts","../../packages/core/src/partners.ts","../../packages/core/src/points.ts","../../packages/core/src/index.ts","./lib/data.ts","./lib/redirect.ts","./lib/services.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@vercel/og/index.node.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/server/og/image-response.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/og.d.ts","./app/apple-icon.tsx","./app/(redirect)/layout.tsx","./app/(redirect)/page.tsx","./app/(redirect)/apartments/page.tsx","./app/(redirect)/clean/page.tsx","./app/(redirect)/flower/page.tsx","./app/(redirect)/land1/page.tsx","./app/(redirect)/land2/page.tsx","./app/(redirect)/land3/page.tsx","./app/(redirect)/land4/page.tsx","./app/(redirect)/land5/page.tsx","./app/(redirect)/land6/page.tsx","./app/(redirect)/live/page.tsx","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@next/font/dist/types.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","../../node_modules/.pnpm/next@16.4.2_@opentelemetry+api@1.9.1_@types+node@24.19.2_react-dom@19.3.1_react@19.3.1__react@19.3.1/node_modules/next/font/google/index.d.ts","./app/[locale]/layout.tsx","./lib/og.tsx","./app/[locale]/opengraph-image.tsx","./components/client.tsx","../../packages/ui/src/index.tsx","./components/rich-text.tsx","./components/seo.tsx","./components/legal.tsx","./components/home.tsx","./components/quiz.tsx","./components/variant.tsx","./app/[locale]/page.tsx","./app/[locale]/airport/opengraph-image.tsx","./components/service-page.tsx","./app/[locale]/airport/page.tsx","./components/flats.tsx","./app/[locale]/apartments/page.tsx","./app/[locale]/clean/opengraph-image.tsx","./components/clean.tsx","./app/[locale]/clean/page.tsx","./components/flowers.tsx","./app/[locale]/flower/page.tsx","./app/[locale]/land0/page.tsx","./app/[locale]/land1/page.tsx","./app/[locale]/land2/page.tsx","./components/gift-code.tsx","./app/[locale]/land3/page.tsx","./app/[locale]/land4/page.tsx","./components/savings.tsx","./app/[locale]/land5/page.tsx","./app/[locale]/land6/page.tsx","./app/[locale]/live/opengraph-image.tsx","./app/[locale]/live/page.tsx","./app/[locale]/pricing/page.tsx","./app/[locale]/privacy/page.tsx","./app/[locale]/refund/page.tsx","./app/[locale]/residence-permit/opengraph-image.tsx","./app/[locale]/residence-permit/page.tsx","./app/[locale]/social-card/opengraph-image.tsx","./app/[locale]/social-card/page.tsx","./app/[locale]/terms/page.tsx"],"fileIdsList":[[77,133,150,151],[77,133,150,151,531],[77,133,150,151,677],[68,77,133,150,151],[77,133,150,151,553,699],[77,133,150,151,531,539,542,553,711],[77,133,150,151,531,539,542,557,676,706,708,713],[77,133,150,151,531,539,542,553,676,701,702,704,705,716],[77,133,150,151,531,539,542,676,701,702,706,708,718],[77,133,150,151,531,553,676,701,702],[77,133,150,151,531,539,553,675,676,701,702,708],[77,133,150,151,531,553],[77,133,150,151,531,539,553,676,701,702,708,723],[77,133,150,151,531,539,553,676,701,708],[77,133,150,151,531,539,553,676,701,708,726],[77,133,150,151,531,539,553,675,676,701,708],[68,77,133,150,151,531,539,542,553,697],[77,133,150,151,531,539,542,553,676,701,704,706,708],[77,133,150,151,531,539,542,553,676,701,704,706,707,708],[77,133,150,151,531,553,676,702,705],[77,133,150,151,531,553,705],[77,133,150,151,557],[77,133,150,151,681],[77,133,150,151,542,554],[77,133,150,151,542,553,554],[68,77,133,150,151,553,675,676,702],[68,77,133,150,151,553,675],[68,77,133,150,151,557],[68,77,133,150,151,543,701,702],[77,133,150,151,701],[77,133,150,151,542,553,676,678,701,702,704,705],[68,77,133,150,151,542,553,554,702,703,704],[68,77,133,150,151,553,675,701,702],[77,133,150,151,553,554,676],[77,133,150,151,542,553,554,676,678,701,703,706,708],[77,133,150,151,542,553,701,702],[77,133,150,151,675],[77,133,146,150,151,155,681],[77,133,150,151,514,531,553],[77,133,150,151,553],[77,133,150,151,553,676],[77,133,150,151,542,543,544,545],[77,133,150,151,155,542],[77,130,131,133,150,151],[77,132,133,150,151],[133,150,151],[77,133,138,150,151,168],[77,133,134,139,144,150,151,153,165,176],[77,133,134,135,144,150,151,153],[77,133,136,150,151,177],[77,133,137,138,145,150,151,154],[77,133,138,150,151,165,173],[77,133,139,141,144,150,151,153],[77,132,133,140,150,151],[77,133,141,142,150,151],[77,133,143,144,150,151],[77,132,133,144,150,151],[77,133,144,145,146,150,151,165,176],[77,133,144,145,146,150,151,160,168],[77,125,133,141,144,147,150,151,153,165,176],[77,133,144,145,147,148,150,151,153,165,173,176],[77,133,147,149,150,151,165,173,176],[75,76,77,78,79,80,81,82,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182],[77,133,144,150,151],[77,133,150,151,152,176],[77,133,141,144,150,151,153,165],[77,133,150,151,154],[77,133,150,151,155],[77,132,133,150,151,156],[77,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182],[77,133,150,151,158],[77,133,150,151,159],[77,133,144,150,151,160,161],[77,133,150,151,160,162,177,179],[77,133,145,150,151],[77,133,144,150,151,165,166,168],[77,133,150,151,167,168],[77,133,150,151,165,166],[77,133,150,151,168],[77,133,150,151,169],[77,130,133,150,151,165,170,176],[77,133,144,150,151,171,172],[77,133,150,151,171,172],[77,133,138,150,151,153,165,173],[77,133,150,151,174],[77,133,150,151,153,175],[77,133,147,150,151,159,176],[77,133,138,150,151,177],[77,133,150,151,165,178],[77,133,150,151,152,179],[77,133,150,151,180],[77,133,138,150,151],[77,125,133,150,151],[77,133,150,151,181],[77,125,133,144,146,150,151,156,165,168,176,178,179,181],[77,133,150,151,165,182],[68,77,133,150,151,186,187,189],[68,72,77,133,150,151,184,185,186,187,188,489,537],[68,72,77,133,150,151,184,185,189,489,537],[68,77,133,150,151,187,189,276],[68,77,133,150,151,187,189],[68,72,77,133,150,151,185,186,189,489,537],[68,72,77,133,150,151,184,186,189,489,537],[66,67,77,133,150,151],[77,133,150,151,492],[77,133,150,151,372,494,495,496,497,498,499],[77,133,150,151,439,505,506],[77,133,150,151,516,518,519],[77,133,150,151,198,202,203,205,214,220,241,385,401],[77,133,150,151,205,215,216,217,219,401],[77,133,150,151,205,214,253,255,257,258,261,401],[77,133,150,151,198,203,205,210,212,213,214,238,240,241,242,384,401],[77,133,150,151,401],[77,133,150,151,194,216,237,474,485],[77,133,150,151,205],[77,133,150,151,190,194,237,486],[77,133,150,151,263],[77,133,150,151,262,401],[77,133,147,150,151,396,465,473],[77,133,147,150,151,396,423,428,444,485],[77,133,147,150,151,330,396],[77,133,150,151,378],[77,133,150,151,377,378,379],[77,133,150,151,377],[74,77,133,147,150,151,190,198,205,213,216,220,221,234,235,238,239,385,401,486,489],[77,133,150,151,202,205,218,253,254,259,260,401,540],[77,133,150,151,218,540],[77,133,150,151,202,235,401,405,540],[77,133,150,151,540],[77,133,150,151,205,218,219,540],[77,133,150,151,256,540],[77,133,150,151,221,240,243,383],[68,77,133,150,151,439],[68,77,133,150,151,159,194],[68,77,133,150,151,194],[68,77,133,150,151,327],[68,77,133,150,151,237,439],[77,133,150,151,194,312,327,328,523,529],[77,133,150,151,311,524,525,526,527,528],[77,133,150,151,479],[77,133,150,151,479,480],[77,133,150,151,237,319,323],[77,133,150,151,210,236,237,314],[77,133,150,151,237,315,323,324,325],[77,133,150,151,318],[68,77,133,150,151,192,237,314,315,316,317,318,319,321,322],[77,133,150,151,192,236,237,314,317,318,323],[77,133,150,151,237,316,319,323],[77,133,150,151,237,314,323],[77,133,150,151,237,314,316,317,319,320,323],[77,133,150,151,192,314,316,317,319,323],[68,77,133,150,151,206,515,517],[68,77,133,150,151,176],[68,77,133,150,151,218,304],[68,77,133,150,151,218,385],[77,133,150,151,302,306],[68,77,133,150,151,303,491],[77,133,150,151,695],[68,77,133,147,150,151,165,536,537],[68,72,77,133,147,150,151,184,185,186,189,489,536],[77,133,147,150,151,198,237,386],[77,133,147,150,151,198,203,300,346,369,375,376,380,381,385,401,402],[77,133,150,151,234,382],[77,133,150,151,489],[77,133,150,151,204],[77,133,150,151,457],[77,133,150,151,191,194,373,406,448,452,453,454,539],[68,77,133,150,151,191,194,407,453,456],[77,133,150,151,159,194,407,452,453,455,539],[77,133,150,151,446,447,448,449,450,451],[77,133,150,151,448],[77,133,150,151,452],[68,77,133,150,151,270,271,275,282],[68,77,133,150,151,237,264,265,266,267,272,274,282],[77,133,150,151,270,272],[77,133,150,151,268],[77,133,150,151,273],[77,133,150,151,269],[68,77,133,150,151,490,491],[68,77,133,150,151,491],[77,133,150,151,346,392,423],[77,133,150,151,392],[77,133,147,150,151,491],[77,133,150,151,483],[77,132,133,150,151,482],[77,133,150,151,165],[77,133,150,151,194,237,280,376,388,396,402,404,407,414,419,420,423,428,432,433,434,435,436,473],[77,133,150,151,233],[77,133,150,151,237,244,317],[77,133,150,151,236,237,407,437],[77,133,150,151,429,430],[77,133,150,151,165,429],[77,133,150,151,278],[77,133,150,151,194,376,388,396,401,420,432,433,437],[77,133,150,151,412,415,423,428],[68,77,133,150,151,165,191,194,263,432,440,441,442,443,444,445,458,459,460,461,462,463,464,540],[77,133,150,151,191,194,216,408,409,410,413,414,428],[77,133,150,151,165,216,237,280,407,412,420,431,437],[77,133,150,151,276,375,388],[77,133,150,151,216,407],[77,133,150,151,276,279],[77,133,150,151,276,277,278,540],[77,133,147,150,151,159,206,214,237,246,267,280,297,298,345,346,369,370,375,401,402,473,489,540],[77,133,150,151,191,192,194],[77,133,150,151,428],[77,132,133,150,151,216,298,345,373,401,402,403,418,424,425,426,427],[77,133,150,151,423],[77,132,133,150,151,193,194,286,375,387,388,408,409,410,411,412,415,416,417,419,420,421,422,428],[77,133,147,150,151,214,286,408],[77,133,150,151,216,345,346,376,401,402,428],[77,133,147,150,151,214,401],[77,133,147,150,151,165,214,396,402],[77,133,147,150,151,159,194,198,209,214,218,238,244,246,248,283,288,293,297,298,300,334,337,339,342,343,344,345,369,376,385,387,396,401,402,404,473],[77,133,147,150,151,165],[77,133,150,151,473],[77,133,150,151,205,206,207,263,396,397,399,400,489,491,540],[77,133,150,151,202,203,401],[77,133,150,151,280,282],[77,133,147,150,151,165,176,196,261,263,264,265,266,267,274,275,280,281,540],[77,133,150,151,159,176,194,196,253,292,293,294,334,335,345,346,355,358,359,369,376,387,396,401],[77,133,150,151,221,234,238,345,401],[77,133,150,151,420,423],[77,133,141,147,150,151,153,198,206,345,352,353,387,396,401],[77,133,150,151,351,401],[77,133,150,151,406],[77,133,147,150,151,282,356,357,366],[77,133,150,151,396,401],[77,133,150,151,388,418],[77,133,150,151,198,214,298,385,387,491],[77,133,147,150,151,159,204,249,253,335,355,358,361,396],[77,133,150,151,195,196,385],[77,133,147,150,151,221,234,253,362],[77,133,150,151,194,196,205,214,248,364,385,401],[77,133,147,150,151,176,267,280,401],[77,133,147,150,151,218,247,248,249,258,282,363,365,385,401],[74,77,133,147,150,151,244,298,368,489,491],[77,133,150,151,333,369],[77,133,147,150,151,159,194,198,209,220,221,234,237,246,288,292,293,294,297,298,334,335,337,345,346,347,349,354,369,376,385,387,396,404,473,491],[77,133,147,150,151,165,221,355,360,366,396],[77,133,150,151,224,225,226,227,228,229,230,231,232,233],[77,133,150,151,283,338],[77,133,150,151,340],[77,133,150,151,338],[77,133,150,151,340,341],[77,133,150,151,679],[77,133,147,150,151,165,198,210,213,237,375,402,403],[77,133,147,150,151,159,204,206,214,244,297,298,299,332,369,396,404,489,491],[77,133,147,150,151,159,176,208,209,210,299,345,367,387,388,395,402],[77,133,150,151,408],[77,133,150,151,409],[77,133,150,151,238,473],[77,133,150,151,410],[77,133,150,151,193],[77,133,150,151,195,371,386,404],[77,133,147,150,151,195,198,386,404],[77,133,150,151,371,373],[77,133,150,151,374],[77,133,150,151,195,196],[77,133,150,151,195,295],[77,133,150,151,195],[77,133,150,151,209,336],[77,133,150,151,194,196],[77,133,150,151,298,385],[77,133,147,150,151,176,197,298,368,376,385,387,388,396,402,404,407,434,436,437,438,466,467,471,472],[77,133,147,150,151,237],[77,133,150,151,307,310,312,313,327,328],[68,77,133,150,151,186,189,468,469,470],[68,77,133,150,151,186,189,277,468,469,470],[77,133,150,151,484],[77,133,150,151,214,216,287,298,368,401,423,428,444,475,476,477,478,480,481,483,486],[77,133,150,151,327],[77,133,147,150,151,332,396],[77,133,150,151,332],[77,133,147,150,151,296,300,329,331,368,396,404,489,491],[77,133,150,151,307,308,309,310,312,313,327,328,490],[74,77,133,147,150,151,159,176,195,196,214,246,297,298,345,366,367,369,385,386,387,396,401,402,489],[77,133,150,151,398],[77,133,150,151,191,194,372,374],[77,133,150,151,287,289,292,345],[77,133,150,151,287,290,389,390,391,393,394],[77,133,147,150,151,283,401],[77,133,147,150,151],[77,133,150,151,286,423],[77,133,150,151,285],[77,133,150,151,287,288],[77,133,150,151,284,286,401],[77,133,147,150,151,208,287,289,290,291,396,401,402],[68,77,133,150,151,194,237,323,326],[68,77,133,150,151,192,236],[77,133,150,151,200,201],[68,77,133,150,151,206],[68,77,133,150,151,194,311],[68,74,77,133,150,151,297,298,489,491],[77,133,150,151,515],[77,133,150,151,206,515,516,518],[68,77,133,150,151,306],[68,77,133,150,151,159,176,204,260,301,303,305,491],[77,133,150,151,194,218,402],[77,133,150,151,194,348],[68,77,133,150,151,192,237],[77,133,150,151,237],[68,77,133,145,147,150,151,159,202,204,255,306,489,490],[68,77,133,150,151,184,185,186,189,489,537],[68,69,70,71,72,77,133,150,151],[77,133,150,151,250,251,252],[77,133,150,151,250],[68,72,77,133,147,149,150,151,159,183,184,185,186,189,190,204,214,216,246,361,452,486,487,488,491,537],[77,133,150,151,501],[77,133,150,151,503],[77,133,150,151,507],[77,133,150,151,696],[77,133,150,151,509],[77,133,150,151,511,512,513],[77,133,150,151,519],[73,77,133,150,151,493,500,502,504,508,510,514,520,522,531,532,534,538,539,540,541],[77,133,150,151,521],[77,133,150,151,530],[77,133,150,151,680],[77,133,150,151,303],[77,133,150,151,533],[77,132,133,150,151,287,289,290,292,389,390,393,394,535,537],[77,133,150,151,183],[77,133,150,151,165,183,350],[77,89,92,95,96,133,150,151,176],[77,92,133,150,151,165,176],[77,92,96,133,150,151,176],[77,86,133,150,151],[77,90,133,150,151],[77,88,89,92,133,150,151,176],[77,133,150,151,153,173],[77,86,133,150,151,183],[77,88,92,133,150,151,153,176],[77,83,84,85,87,91,133,144,150,151,165,176],[77,92,101,109,133,150,151],[77,84,90,133,150,151],[77,92,119,120,133,150,151],[77,84,87,92,133,150,151,168,176,183],[77,92,133,150,151],[77,88,92,133,150,151,176],[77,83,133,150,151],[77,86,87,88,90,91,92,93,94,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,123,124,133,150,151],[77,92,112,115,133,141,150,151],[77,92,101,102,103,133,150,151],[77,90,92,102,104,133,150,151],[77,91,133,150,151],[77,84,86,92,133,150,151],[77,92,96,102,104,133,150,151],[77,96,133,150,151],[77,90,92,95,133,150,151,176],[77,84,88,92,101,133,150,151],[77,92,112,133,150,151],[77,104,133,150,151],[77,84,88,92,96,133,150,151],[77,86,92,119,133,150,151,168,181,183],[77,133,150,151,658],[77,133,150,151,647],[77,133,150,151,647,650],[77,133,150,151,569,641,645,647,648,649,650,651,652,653,654,655,656,657],[77,133,150,151,565,567,650],[77,133,150,151,647,648],[77,133,150,151,566,572,647,649],[77,133,150,151,567,569,571,572,573,574],[77,133,150,151,569,571,573,574],[77,133,150,151,571,574],[77,133,150,151,569,571,573],[77,133,150,151,566,569,571,572,574],[77,133,150,151,565,567,568,569,570,571,572,573,574,575,576,577,641,642,643,644,645,646],[77,133,150,151,565,567,568,571],[77,133,150,151,567,568,571],[77,133,150,151,571],[77,133,150,151,565,566,568,569,570,572,573,574],[77,133,150,151,565,566,567,571,647],[77,133,150,151,571,572,573,574],[77,133,150,151,573],[77,133,150,151,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640],[77,133,150,151,560],[77,133,150,151,662],[77,133,150,151,560,660,661,663],[77,133,150,151,560,561],[77,133,150,151,561,562,563],[77,133,150,151,560,561,562],[77,133,150,151,560,564,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674],[77,133,150,151,659],[77,133,150,151,659,661],[77,133,150,151,659,660],[77,133,150,151,659,662],[77,133,150,151,548,549,550,551,552]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"045c1b395851aa71ef76393398466330fe1eeebc113c8085eefc6d84abea3a88","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"68d7453aee169c6f39bf6a87d2a07e21209dfe085ce8469b7331bc7f8f0545eb","impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"378281aa35786c27d5811af7e6bcaa492eebd0c7013d48137c35bbc69a2b9751","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb9de9c4763c447e2fda608854ad494c4a99e10dff9862e2ac437edbd477acab","affectsGlobalScope":true,"impliedFormat":1},{"version":"1b2dd1cbeb0cc6ae20795958ba5950395ebb2849b7c8326853dd15530c77ab0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"387a023d363f755eb63450a66c28b14cdd7bc30a104565e2dbf0a8988bb4a56c","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"14e9acf826baba0ef4b5665704084896e7bcc06f65a9ab13af7e93d27d6b7069","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"21adf13435b9b748529c8cedf80f884e5130b9684188120a686cd2b26a2059c7","impliedFormat":1},{"version":"eec76bf6b9346f3f95fa402621b889489e96930e72295b0369022f332e9b4a6a","impliedFormat":1},{"version":"0ecd58f413f9bc3b7d4383eae31b0c8fc576985cd7404d6f99f8c643543ade74","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"d33ce35e3f9cfcc1d94eca415bdd3bde94d5b153ffdd33e6c4455c029986c630","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"4dc59f6e1dbf3d5f66660fceabe6c174d3261b37b696ae1854f0dbaf255fc753","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"436d7b4543b340b0f3eef4310d524242e41369b9652aa9c70428767c4dcac455","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"114f493b30f364255290472111b5a4791d5902c308645670cd0401429cbc6930","impliedFormat":1},{"version":"f724236417941ea77ec8d38c6b7021f5fb7f8521c7f8c1538e87661f2c6a0774","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d97fb21da858fb18b8ae72c314e9743fd52f73ebe2764e12af1db32fc03f853f","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ea15fd99b2e34cb25fe8346c955000bb70c8b423ae4377a972ef46bfb37f595","impliedFormat":1},{"version":"7cf69dd5502c41644c9e5106210b5da7144800670cbe861f66726fa209e231c4","impliedFormat":1},{"version":"31a2721bfdb4eaf3af1168396bdc307d14892074aa64801ac975aa9809a1727f","impliedFormat":1},{"version":"01b30c21189d840c5133bd8d250d70c9e8f389884b00e66b093579b49a7cfd4c","affectsGlobalScope":true,"impliedFormat":1},{"version":"45660ca397a0254c7ed61255fe8174ac0951452e4565207d41313b6fbf5b8431","impliedFormat":1},{"version":"51aecd2df90a3cffea1eb4696b33b2d78594ea2aa2138e6b9471ec4841c6c2ee","impliedFormat":1},{"version":"9d8f9e63e29a3396285620908e7f14d874d066caea747dc4b2c378f0599166b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"3b909f9fa68b102e393d86d11f605ea14fe736d69374bd88a1c1e6fb6898f5d6","impliedFormat":1},{"version":"53880a6a8e7ca1536d25eed26f1a74bb893711d7395db74d5a329f8e074a576f","impliedFormat":1},{"version":"9f39e70a354d0fba29ac3cdf6eca00b7f9e96f64b2b2780c432e8ea27f133743","impliedFormat":1},{"version":"cb7ac5f8e38b425e4cc4619bdb9895ceb94b364be8b462f8cf220c2e0963bd75","impliedFormat":1},{"version":"b5cc0993d6853c829184f119e49176bb43061cd0dbcb2192d296f7221b4d7b11","impliedFormat":1},{"version":"1cbdcdef62bf42688e5d825898c3a59458466c48ad8a4ef3f88d8a1cd04310d6","impliedFormat":1},{"version":"1049c567c0a6244b69738cdd83edce170b8d5ca941817cf185f7f55c28b3feb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"e6a2a1eecdb48e9a9eb36d115e212664f20710530e5ec32bbea84bf36979d2c7","impliedFormat":1},{"version":"1e7e5eaeb0526d12e8bc859e537c65779e673d4beb94615da7f062a8bce2fd96","impliedFormat":1},{"version":"06c12e208576282dfd4aa04cc47ae3447008fdf79a360a9b0f3a6fb940960cd1","impliedFormat":1},{"version":"f952e6977043709c36ea7d9f626219f7bcb066b0da6277257eea0d2ec76123ce","impliedFormat":1},{"version":"0c50296ee73dae94efc3f0da4936b1146ca6ce2217acfabb44c19c9a33fa30e5","impliedFormat":1},{"version":"6a4b62da0425ae60eefe00841578be0244a8888a62593a843369c9c311f15eee","impliedFormat":1},{"version":"4dbd12e59b970f64303e68820f395a169e512e48eecd360305591be83592b80d","impliedFormat":1},{"version":"2d25328278ab945e6ad1e73d831a9e79ba274cb994ebc0470f29c08d2550bcd2","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd541a9b163154df9713f5669c157e330f6957f44915a097c4d99e9f4df616dd","impliedFormat":1},{"version":"3e294a1b71ea288a0796d374118150455e8019dbffcf8b4124faaf9721d29a8c","impliedFormat":1},{"version":"04bf1aa481d1adfb16d93d76e44ce71c51c8ef68039d849926551199489637f6","impliedFormat":1},{"version":"0343687443e7684643e8349cb178f2f9bbdeed2ab53445b0f2870ccda91d274d","affectsGlobalScope":true,"impliedFormat":1},{"version":"614d31f77751e038f30e01641443df8591e12b337c675a44f70675fd5dbf5ae9","affectsGlobalScope":true,"impliedFormat":1},{"version":"a58a15da4c5ba3df60c910a043281256fa52d36a0fcdef9b9100c646282e88dd","impliedFormat":1},{"version":"b36beffbf8acdc3ebc58c8bb4b75574b31a2169869c70fc03f82895b93950a12","impliedFormat":1},{"version":"42a350ce4f6f291198dc89833afcc4fd078248b4e1fdc9d05c846c66a670f710","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"8c81fd4a110490c43d7c578e8c6f69b3af01717189196899a6a44f93daa57a3a","impliedFormat":1},{"version":"5fb39858b2459864b139950a09adae4f38dad87c25bf572ce414f10e4bd7baab","impliedFormat":1},{"version":"9ba17a5bdbeb17c5584000b1ae4b3552116f2151f6c04830c070ef36bf4cecec","impliedFormat":1},{"version":"d30fbda663d9683468f519de4062e4a59a1a318b8b1c9e5a8e30073d6bff4b1d","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"3f87014045740d3df7752b1dd6a6d8c245fb646104471dda177e7ce41b6cb296","impliedFormat":1},{"version":"6e11fd90418aae21a4b5f9f8fb79b7d920143486b2a5911c9eed377ab71fe5c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"c119835edf36415081dfd9ed15fc0cd37aaa28d232be029ad073f15f3d88c323","impliedFormat":1},{"version":"f75d37a23477e13019deb34401bac250666de0bca64de6b41698d90bfb3b3db0","impliedFormat":1},{"version":"9705cd157ffbb91c5cab48bdd2de5a437a372e63f870f8a8472e72ff634d47c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ae86f30d5d10e4f75ce8dcb6e1bd3a12ecec3d071a21e8f462c5c85c678efb41","impliedFormat":1},{"version":"10eb385d3120c6c5981249af7ec214a6756b0f40e8bb3d184be3d0457b67b2d9","impliedFormat":1},{"version":"e03460fe72b259f6d25ad029f085e4bedc3f90477da4401d8fbc1efa9793230e","impliedFormat":1},{"version":"3c59c992b671e83a35dec52e894b5bfcf2dcb0104e24b3082b8c793ec3997532","impliedFormat":1},{"version":"85fb581c048b948a48842e6584d61512939566e0c7a4d6439f54902ce6c79bee","affectsGlobalScope":true,"impliedFormat":1},{"version":"673176c21f8a68d5d4e930208c6de7f49857043cc9b9c45909b30244981936b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"09c273ba5bda2a12318fbfc37433a3f45b6137a65dea55e009d1c3f7608b9965","impliedFormat":1},{"version":"bcaf6a7cda69d3744d039c864a8fa59502514a9f8d2d2b8d0107001ceb9b406f","impliedFormat":1},{"version":"0d5b085f36e6dc55bc6332ecb9c733be3a534958c238fb8d8d18d4a2b6f2a15a","impliedFormat":1},{"version":"0b0dfb2d3e8420ead06f6a11acfb02ddcec42257e6ce391993e895ba0af86de4","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3b927f3f6054ebee0c7497a72c574081d21cca71d29d7996ca9aecf9f6ad80d","impliedFormat":1},{"version":"d7e9ab1b0996639047c61c1e62f85c620e4382206b3abb430d9a21fb7bc23c77","impliedFormat":1},{"version":"865a2612f5ec073dd48d454307ccabb04c48f8b96fda9940c5ebfe6b4b451f51","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"dfb24c6874a941ebd8947c97efb27c6b40f4a48218ce7433d1d088d1245b6d58","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"ed91c87062f8720dfb894f41e364d0c189eb3fa40501f93cf36691e06f5d3261","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"6820bbf8a6224854ee584c7524679a3fbd37aff253910b3eb589293f8d1dcd71","impliedFormat":1},{"version":"8c21af163ff099d909d34ee3b2e0e5bb14987e148205b02c7abb670f6d613f80","impliedFormat":1},{"version":"d6ae84a58cd76d1f44ce54a3dbf0fe745407da6c8a8ebca9ab9f6797f24d2d6e","impliedFormat":1},{"version":"ab2acae979239e320dce1c8288d717113dd3155a4a5639c07082b4aa9adb7ca7","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"772293119492ba49cef5cda206d98d3044db718a758a0bdf7cf8e851b0e1ed39","impliedFormat":1},{"version":"260e85ffab04d2d16cbaf3899fcb0cfdfa696cb99948d7b703fb28af9ff383fb","impliedFormat":1},{"version":"fbf9959ac279b397cdcd47b6155c32ace1e33ea148c6c1b87815225cb919685f","impliedFormat":1},{"version":"fd4e24ccff3966390600d7f5d6aa1fed5a512e92ada735ea5fbc933d313ad3d3","impliedFormat":1},{"version":"0672de9c653eb04fd7535b21926bcdb94ffb2d8158d632660b346d38c403064f","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"8353adc36468bb55b52ac03d199285bd57fe5cc6530a0ab3ec0156f6459a2e9e","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"f6e0694f98a39a8fcc85e98c3f9ecea676cd784b96bfecbf9be7670df6df7775","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"e4cbf2f1e89ecccaddd2c045e600ae41b732295953fb06247c7dcbc2d281ed30","impliedFormat":1},{"version":"9222cd69f4ea6f0aadc222f649b08830757a081a0f170bf3e392fafb90ce6888","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"ebf0d070d95e81f32d04bf219e8b953cbe67f2ff3b59dee24dd8cb9dfe28ad88","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"2c74ea743d3643ce807f881c791f45aaf336f8c7270ac8276921c8941b453f38","impliedFormat":1},{"version":"612d9da66bb046a9c1e2e8d026245ded881fc4b9f98cbfae714415d57ee0ae0b","impliedFormat":1},{"version":"32c2ad9494dad5d11b0564a619fee18f388db6c1e9e2cd3c360b3122549691eb","impliedFormat":1},{"version":"6c301d40aec56a74ec7bd7324e31a728dadf9bfba3e96def02938d3d973534ec","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"97ef9e5ee435bc55a6bf9d89099c122e994c14a5a8e5d2c94196397ca78bf067","impliedFormat":1},{"version":"8d207e1f9d2c30d6f77dfa693f3827c3fbf0d89240297e10bdfe1041d433df68","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"5ff14774ab0cfd57d74a785e8962d16787237fe3951422d6b57d51724bb623e4","impliedFormat":1},{"version":"f17ab725503b22a8f5e7cbb8c8e772a4b877fc10f52387a11c5111bc4c49febd","impliedFormat":1},{"version":"c64a1373fc1c4401ea846231b69f06fcd8861b261a608a391256ffa4e9169f78","impliedFormat":1},{"version":"cd8ce8d68567f62dd580b3c3c37777ac3f5b81944c7417f5ea83030eab533385","impliedFormat":1},{"version":"17e34edaaf998ae68ce6860f30a1e68fa56e28ba59e17c14071608ea7555ce1f","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49af4b52f0d4d2304c5f2c6fe5fab3e153e0acc38830d0202821b877c097dd02","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"a0977af38b8e0b4ef1440ec107284076057b208539a254976bd48df2dfd74d43","impliedFormat":1},{"version":"f89488602bec98a142072fae7ea5ba99431a569ff580c64b7be39896474799d8","impliedFormat":1},{"version":"4ef09f003d5552d0984240eb133e4fcff774ac79c04e89093ed34082e78b18ca","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"2ffb043dc5163458e473b7010859f86e01dc4edffcae0a93d885d028b426a546","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8065914a3b9cbc1ab55a05556d62120e893ed6c0373ae603af7b32143744fea7","impliedFormat":1},{"version":"b607ce5e29f1ab4fc0791175a0db840a78f5a9a0347f6c7a6aca8d65f1c8eb7a","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"42d12b8f6c704d5fcb1ef0def685db4137c46b286bd42063bdc1f0483f5ec612","impliedFormat":1},{"version":"b7a19436dee81dec5ef66720df5dce89cc4e6d767984475e209654dac5ae1357","impliedFormat":1},{"version":"3750bda25d87cef827c2c970a8dc0cc1a2fcc01f96834cf2e0f4bc5e037edc09","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"9917f2694799516bf571e62e4b76cfcb22df50a74335302223e10e839c01c60c","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"5d5179db368664843aca3825b6e7ffa69f47cbe3f138b543fb20dba48dbab4d8","impliedFormat":1},{"version":"7303b45138d2511035056a5901a1490ebdcbf055cbb1276f8629c5121cbe733e","impliedFormat":1},{"version":"47bf8f46d61fa63278a5d10630f6bd7063394bb69284e484c61b352ebe0d8e6e","impliedFormat":1},{"version":"84d7827cbe98ae5ebb56b7571e594a8132245ea05bc60bb232d019f51b52880f","impliedFormat":1},{"version":"46e48e65148cc2afd03fad660f54cb5705ace4c45e80aace208ed7833a96f404","impliedFormat":1},{"version":"b0fb2e6b4a7b366ae1a7a441ef27586e5a8f480b48583b644c2e16fa3537ac5d","impliedFormat":1},{"version":"5f3bafd9fe0a6c1e07cf0036d92ff04f0eec503660781823256817f00bcb1fdb","impliedFormat":1},{"version":"efcce61e435bbf26e26a95115cf1313a0d236937b8be3854d7975fa9b75b12e3","affectsGlobalScope":true,"impliedFormat":1},{"version":"72b0ced59987170ebaa22b5fe0fa205437809b94c6d6e9e1ffd94ca5bb9c62b2","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab7dfff19354646b5dd29676783546c81498f8289f679650f9e612f49f8481f0","impliedFormat":1},{"version":"168aef326b885de740f50def048399ec5b6d1338bbc19e14c942414dbae287f1","impliedFormat":1},{"version":"74eca395ab8ca0411b94a9fb37afb288436a8117965aa7b48ba07fcd024087f8","impliedFormat":1},{"version":"4f58011d28e315f844e72bc05c1a35416a467f09ac8fb49d5ed90114569bc283","impliedFormat":1},{"version":"ddffca9d6b1024d95a4a49b002bb7d5b96752545ddc1063d31dfe84c5f270637","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"87cc05fe13108f02e12da7e3efd8e360fef78d96a0c9e11408ea1b1b9fb3e03d","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"1abbf67c218d23c2ce76887caac2df6c7dab3d97ba2b65348432b876f510002a","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"a49e1f0fe346d8302d5f0a7c13f70badb03afca56b6f44b4ad7fdfd89364a9dd","impliedFormat":1},{"version":"bcb41487305a09e06d427b7ead5a1233df21d8b44cd87b92b4182d1c228294e7","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"2352f74bc51c0e2c36f3fe406986dd4d0b1385faae349507403517d75bc2be8f","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"67c2f945a841d2d15e96ee2b24841c38c7699d71bd33d6ae4bbe6eb0f3017dce","impliedFormat":1},{"version":"e0e36f9bbd630799a0ebf0642c1c99bc5efd38235973f205973af72f536b80d8","impliedFormat":1},{"version":"036c8aa095343338b51d319022cdcbe38f0af122623f78aad845237036c4bae8","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"5b03473fa053c05307ac9a9944f4c015d03dd5f130842b9732e95c643d01c765","impliedFormat":1},{"version":"3628501086ba84cc656d1f955c4f053e3e0f4345abe579cba134af7725f38547","impliedFormat":1},{"version":"7b61910227f1ff9162526c136a3e83b866023fafffb85852220312dddfaacadd","impliedFormat":1},{"version":"a6dd0d4b58792273ba5ccc3acbdb9d27aade6873068336879065fdaab0f4fca8","impliedFormat":1},{"version":"c0766276c806282cd3f5d836477b196616ba7e1581900be2a369bb39f9de6f4f","impliedFormat":1},{"version":"6cd1cbd1f0b1e34114f67dc737b1ab06cedb0e0aed12d959d1074e41f6f85f09","impliedFormat":1},{"version":"62d28d7019e637d92c82a7fa0bf3169453fa7c9992ed92cf0501b7b18192a162","impliedFormat":1},{"version":"f36095381ed736f850234ab9f79368ec49189d0132e1a0f4a5f0d96180eb78ca","impliedFormat":1},{"version":"8737644a365c3cb0ef0ca096b2a7a0cbdf8bd82d93b0709b7583b4f390797558","impliedFormat":1},{"version":"8eb5507553e27e1437d6daa43ee8d46ffe9b6d60d1a71b388fd5ec26533e5cf9","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"b499af2054a037a162b3b72cd886f48bbf32a3502c865c6e29fac7d2ab3ce0b5","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"4cceef18d7f088e797a463e90b7a9dad10c6bc667724b7686e3e740ae00122be","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"5bb9e88d20bdc94bf2cd2ff3618c9d53e7ee8f497c0cbaecc79cef8e943409b2","impliedFormat":1},{"version":"3905e3debdb0fba461fc9c0376d88989c5407d10b11aa4acd9d7a22c45b20484","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"2467b00d963828f540f4acd7910f4c04cfe4b489550e6bb682212f65583bca5b","impliedFormat":1},{"version":"b837d41bb8d39398690458f45cc445160dad36ec0db5ba0463d114e560d49d85","impliedFormat":99},{"version":"ae37b7e1e01a7acee14354d827feaacb2433fdb2ee18f0aa2ac60a5aa58196ef","impliedFormat":1},{"version":"76b99cc799570def931268a227616448e82d3f6facabc0f1a0f102ee65643e95","impliedFormat":1},{"version":"bfb96afc9bace6f71f3f132483ca0754b70b6f25230fd159ea99155690b48d7f","impliedFormat":1},{"version":"ae6b0da095dc51ff6bb1c9b458fd1ee581a67b3e93743dce5754a5b83e963800","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"103c58438e43570fb39bc14944f6773b836526043f519414f8e6570427e663be","impliedFormat":1},{"version":"da1bc1be19354bc4712aa812f103975b40c663ba99fc58d4f17491714d594e0d","impliedFormat":1},{"version":"58f5ce9d6441bfeff2b5a5c3f8c47374a2858cbd79957f6df838c17c08b35e1d","impliedFormat":1},{"version":"211963a34067f0334557633ef63c8f081ffec6cdc501224441f0b1098bf304f3","impliedFormat":1},{"version":"2a00d48eee5e75003a93aebc363d63153166bf413eb71d719d08e9d2746c3949","impliedFormat":1},{"version":"a3dde9ce0124a50289ff943d376ffc0bc4b1c795c7a179e2514543cc1526631c","impliedFormat":1},{"version":"e0cee12109e0a10a4c3d6769fcc7644b7c1ea7f52365bea51728f5af29f8a137","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"1aa1e206e09cf48e9a0dd6b4f37628e50131294217b5292cfc53a4bd44128adc","impliedFormat":1},{"version":"c22c47cceda0d08fc90443b8dac8065e971fb80acb2b6ef4bddceba19161a398","impliedFormat":1},{"version":"5ccc24867ba467754aeaff9a8036ec9f6fa6c6ec802b6bedc000b08cfa19313f","impliedFormat":1},{"version":"09295612cbae4ce578aa88465b6d7a2ed52e3d2145f3dc45f66ce1d2ecd825e4","impliedFormat":1},{"version":"c9df081660108cfec15ea7c7467e180a7993cc26966373e1da5986151fae9292","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"7d03e550f45bf597173831cb4e1f7b052ec9abc5633fa40d64b9417de4f9198c","impliedFormat":1},{"version":"97ddb5af2e6bc8731f334a8e9fe8dd35d707f22c63be18c638844f3e49fcb1c6","impliedFormat":1},{"version":"3e24b87ddbd3645c523360b586e14c7c6ff0b804ef43e749fa8c560f4bce4631","impliedFormat":1},{"version":"46e1e1b9469e08cbcc89902587d06f88852ca86dff2b038e6d6ade4a85d0f3b1","impliedFormat":1},{"version":"c853c553edd8ac067fccd83636f6eb8631a81f687b4a6043e80283d8f4bdfb1e","impliedFormat":1},{"version":"0436bf5feec3381a5737834f6c99db6061505ab1be668baaab9fada2c70172b4","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"77e99ae2244f97b15fe0af565cd4ccf6a5a3298fb61bbc55af32007eec39f78b","impliedFormat":1},{"version":"636e7a3de47dacec888d05adf330c5988db766f31f37ee03810489baee81d76d","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6db920eb76bc2f044dd32b36288a99298d60ab9747af38a3750ef27a319ed45b","impliedFormat":1},{"version":"fcd9a6c4136876805dda3b1e3e35e98ba72dd648853608fee7965d857507b502","impliedFormat":1},{"version":"8c848e5d0edf1dacc0ce45dcf6a17eebca9375233cd6ae954705cb4f59f8c9ef","impliedFormat":1},{"version":"a24f74e3142d3372bac0e6306917b61f59d39fc9b0e9aacee59af225b749f0e0","impliedFormat":1},{"version":"74ab02daed557f783d9779a9ce470ab276cf187c033df390da9c5c621f79f9b3","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"5bd12e52bdd0135ed15e1584e0e4206591ddea86a92b0c76d7851a0b09462f8e","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"0b77b819b5417775fccb20c678293cf614c054a5b1a65421a5b933a9124ba998","impliedFormat":1},{"version":"71188d4edc2606f825a0f81a440ec3b4dbde942de24d86e6c329af291863dc38","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"ef8b9028d751f291df91ebb3e5b1a6607fa99dcfe64563b7e85a9b22034b60fa","impliedFormat":1},{"version":"ce11568d7135fbe99854aa6088b327f9e4c234707c94c4e91e1a52919a881bcf","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"ac9d4e0559bac6980fca9a27377286b6ebee551ae85e8c34d16b41ad3fb668af","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"03a25a013a533ce17cd79374f6af19b63e0a5c0d363f07df371ca23cf27a740d","impliedFormat":1},{"version":"1227fe54ceddfff14f1143a88f3b1890b749b0d3d242d107b234cc6673392a99","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"da2e8764665bb85ae184a4c3738869b462d1781263d012dcab0b292533aaba98","impliedFormat":1},{"version":"5e17c6748e336bdf5a83eef55499c4a09ac20ef7e8ac533411dd0e97d23d3ccf","impliedFormat":1},{"version":"6bbf33947658770121ce0afa44828e1ea9294b1e6c4c7984c0f6da7cc5c53216","impliedFormat":1},{"version":"ebb8af215c7d449add233d33aae1ae80eadf70d3b1e333c55ee09e6dd9181781","impliedFormat":1},{"version":"1bab48faa2e3426331252b77c63f5118307586eeeffc8608274848c10ddda25a","impliedFormat":1},{"version":"7275cd36c1fa132f3b91339fb9226c6d9187c85d49b5c2ab73f4f7241403ee54","impliedFormat":1},{"version":"c3ec4f81043ca175e7d8c466102606a8b5757391c22682b2746312a09d538b1a","impliedFormat":1},{"version":"0b603555f1881f87256ffd6344d3e3ed6d466c2e701eabf381f28be8c2125892","impliedFormat":1},{"version":"897e4f7662488e3ecc79e743bdd3b78f13bdb69a97851afa5b440c4211e32ea9","impliedFormat":1},{"version":"e2e1c6d3b2d93add5200bd7bc1a8cccb4e446836b2111ece45db8683a2c765de","impliedFormat":1},{"version":"f44202f1916ae603a700af976229a10bf92c5ec614c5369b67697bbadd7cd9ef","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"2c4de79f406d137390608e8c0a44fba2ff8e00bacfcae7c9d1781fef10e9440d","impliedFormat":1},{"version":"6903a057a7382ca0ba867e2cce8b0015e5f6a0bd9b44f86981983303f09391c1","impliedFormat":1},{"version":"8fcadaa47d7587984a0d59b22f52569848854b104001e64d764375d7c7339635","impliedFormat":1},{"version":"48d3f630ea5febd05dcb9a30b4a070dfefe42ead9c7117113e05ba9a43b70ff7","impliedFormat":1},{"version":"51a00ba6e353d9c5ab691f5e783d681c9b5ca7e38f78aedebde04f773f204002","impliedFormat":1},{"version":"15d87d8f5dae7e0ba772297a455b264d4b657653b0a50bdacd383469b759da02","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"f8cd8619b40c909f8e0363be869c6c91e95a2cf6648d1b771365eb45a11a47ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"3ac03a99e8b3afbe3a39011db96dec2ba3777020b71f3e9617caa1610fbe6ea0","impliedFormat":1},{"version":"5f3820872e54f04cc7d1ed5833aa91c5d45f72d6c82787d03590388063641887","impliedFormat":1},{"version":"5541971ac5ca5a07fbf99b18d072960d29c06558c143e26fa3fd34eda1cd2604","impliedFormat":1},{"version":"bf6e368c991c772a8cfd766b1e5ca38313a98591d56b7467cc9942923b7ca375","impliedFormat":1},{"version":"ef38d10c4a62b93bff2b78e8f164c3912972953dddd05678b6648701121eeabe","impliedFormat":1},{"version":"0df1599ff2c071019f5b34feeb897a667e289694de0e74282ef27e045c7db31b","impliedFormat":1},{"version":"89a3b46d657bfcfb6a58735c11de210c0a238d509752f0048ef5daf462d91e96","impliedFormat":1},{"version":"e2ea36cd1c578a8079f9657514fd85d6c86e9df40e82d2c17b6fae2284cbea3d","impliedFormat":1},{"version":"39fa99a361d1afd2b4affe49ff10d20760423079038fa40a8ae3aebbfe46673f","impliedFormat":1},{"version":"69f4476827a996362a5d1881080a576a7437c5efcbd94809b36621cbd57c36c1","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"bfd922cd6c7e5404cb2beb99ab0be844b0440dc8ad220894ad32efb85db97bcd","impliedFormat":1},{"version":"a52429ff820c9878482940e2b7752e5b004e0f16635c0cefa2a8da473556201f","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"649588d1787139707a4ee0ea5a7ac8a54d94c6d9823b15bbb28f18b79392e295","impliedFormat":1},{"version":"ff64fa5b9727f769066ac59eb42bdfe0931dbb61c9f42aecb3e0f412d0186f88","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"00e981b1c8e1499dfeb6003893f56c4b40dc386826dcc0227c9eb9425a7a3c7f","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"456006a6975b26c0a1785feddae165f6d307e2d601ffde27e21fc4a790e448a4","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"1fe0d18b111e1145a7e7601855bccd4ca20f24e3b9a5aba6bb1fa9d1a7059170","impliedFormat":1},{"version":"5632c3c26d420c063eebe64c45b1248b9492a67bf44f1d0c57e9dc8f6cf449bb","impliedFormat":1},{"version":"4c536efd581b2109005df14e670ffbf799dea8731b33db3fd2c3ab655b4eafc6","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"209acaaec93dabfd798afedf614bb31107cdb10ee9a2b488eb9c8ffdc39bd9f8","impliedFormat":1},{"version":"139353683aae58322057c7e4c138b1df68a0904b5abff6c76aa125b089f2fc32","impliedFormat":1},{"version":"8efbf3aadf0e8e7e8b57ada8a18f251eeb975f1d7e040467e91b25b2f226b5b7","impliedFormat":1},{"version":"3557bf9a27126e46b6203359286b70133cec354cff2744d1dfc40993718bf618","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"650459c223407fb9149486446241a10fb327b96a127f4ece6d6fe9cefa34e28f","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"4366274f3c6df057c80bad865b35938314f4a429e47f9aa610a4a310e0d843f7","impliedFormat":1},{"version":"10b2c5fc764c6dc12b9e022b178b4ff41a08733074b376611578e34a8f79a2e8","impliedFormat":1},{"version":"4d67410db8f887d5f2140f17aa2d426553a60279f2ece7d33bbb939922766fac","affectsGlobalScope":true,"impliedFormat":1},{"version":"c6e51008cf8190894ff2fc8e672273bf950d246084a03bfb7c3a274fa810c2d9","impliedFormat":1},{"version":"b213dad76ca37fd552274c9499056e1c0d9c1bd38a55bb7f68b22ba6b84c3ad7","impliedFormat":1},{"version":"c30436b130b6218b7714314dc41d3f459590db4bdf099eecd51cb1bda32109a8","impliedFormat":1},{"version":"b838d4c72740eb0afd284bf7575b74c624b105eff2e8c7b4aeead57e7ac320ff","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"9186d55827b220396267ea19d6cd3d86d672275868579723899d8af83683f3f5","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"975e8b26961e55ff04d0aaeab53cab3c474c6e61e3fc310e6cef688ac13bf091","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"a6805fcafed712aea7759f8bc731014f9d22738c1d6ef9d43b8091d1d48346d5","impliedFormat":1},{"version":"775f181bd4a533d6f8b5e55ec1d9f1624559720ae8a70e9432258da26b38d27c","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"ea4394f420147f1ae87dd54b84769725db30efed35f9016dcf48b9bea03a20e8","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"b4d41ad260db258f37a5e9b5004d87b79c2e3b8f2a8597c9ae8d1735e3a0ffbd","impliedFormat":1},{"version":"2c56dc2dc1369d89a4d09bccec5da44fd1c1799aa333ca683adf392d63884010","impliedFormat":1},{"version":"360fe40be059e5206b565f91e130ac2768169b06ecd714f982b0ef4c602e96cd","impliedFormat":1},{"version":"0e7c1ade102180b6f90570ce942ee6036019f6f9ff9f98bde33bbd3cf60a6553","affectsGlobalScope":true,"impliedFormat":1},{"version":"e8daa443eaf9a27fd382cc1f8ebe30330c0f4d89511cfb469166874806751d35","impliedFormat":1},{"version":"e723bc0b289a8ed8a753453e7ed79876bb032470e7f2da39c02bc9ba70847738","impliedFormat":1},{"version":"1640728521f6ab040fc4a85edd2557193839d0cd0e41c02004fc8d415363d4e2","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"d748648024504c3ddb46411e310b4c69050b8a695e0e1982683bf5594d5a2d8b","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"043b4931cc88f57ad36d9cb9d11ff7f688ceded5ea90bfef50f812fdd625e449","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"3af9eef9d87d6800c89af627157b73c95f726bffb758f8a67eaa66aa74655ddd","impliedFormat":1},{"version":"fd6d0bd82f88f407489ca7714e272b0703d8ed000ceeb1c281c576cb5f49b2af","impliedFormat":1},{"version":"26f8627d501decb20e9494ee1d9a7eb27c21e9b50df506aae1fe1ad3f9b11aa0","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"ec2804a1343f9af99b504838771f77a92cc756ee564c4df3df67cee0ebccc292","impliedFormat":1},{"version":"07a86ec5e70855b9fb5ed27f6a7a84d3ba3f63ba521c9e3cf2ea53ad8484a46a","impliedFormat":1},{"version":"d7bcbc84a8a0137869fbb37985d21d0fbf1d9903e1afbe692577302d865fba60","impliedFormat":1},{"version":"1b16beb8414a7abf9e9d82c0df4d5f2ec6c17fac3fb7d6185004ae506d034651","impliedFormat":1},{"version":"153a111b813b430aaa37a352abc884f0434665c9a6b6b3a4deb1ecaf3a74e17a","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"3204da0763290f87d42da49b260e8e3627b2c9a31861314c61715c29180c44ec","impliedFormat":1},{"version":"ad77d716cbfc3f97be873c1129229a4e8bf83c12ada344862eeab5a590614a9d","impliedFormat":1},{"version":"5d9359c0f7a12246cd39b564ba601c7baa0eb1f9a10c47ce207804dab89356a0","impliedFormat":1},{"version":"fc85587d32e46b46e698053316f16472d7e2e78bf45d177b47dae651f3891aaa","impliedFormat":1},{"version":"27796b11ec9f91d57f251cc5d3f317bbb7ad618484d140d8b0bd81e4064a9016","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"e297c0a524edee7677939122f90027bfbe5f2698939d9a85728e5044b39c7124","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"cdcb96ffdab6204c3ded7f53ff8a3e730c3689eb83f8b2eb065287bfa8e7b1f0","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"09d8a449a9f38eefc0383f6e08c52cefe471943d99cc3c2242a21c02235b6dcd","impliedFormat":1},{"version":"41eb514d9ce0a6e87957f08a4b7af70d93f87637f37dee706e2d92a6601c25a9","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"7bd01f0f28cd3aeb2046274d85208e245965f6f2948edf4f7b2057bcf9f22ccc","impliedFormat":99},{"version":"d2f2cf2b8cc92bea913cda4a076e0f790b23a21e84f989d12f0116a7fe3906e0","impliedFormat":99},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e10ae5cb4548fe3ee1d33b0b0a215de662f4ea8e0e267f7aa22fa7637394286","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"86024b0dad34d63d0e571024627dbc6162116753810d9e7c2ba917f8be78c8da","affectsGlobalScope":true},"f3387dd7800eec3c34273f7a8efad13e864598c7e8f788d321e407390989bb59","0f70629890b72a0a82e91972cc032c04b658b26c265373cb711cf576bfbf8fcc",{"version":"74d1b1b417a7579b43719ec41853a8a4eb7ee84b8e648194a803397572cd7c34","signature":"2c380b13a2ae4cc3b82ce36c611bb90b04a892bcb9182ec6ce515acbd7e099aa"},"efbb306c00a88cc4679f92dc3e0c2e0e1f9276ebb7573838e73c6d44b9bbd247","abaed96b55dcc8370b343d1ef327efdd97c4b83a444c7bf5f0f624a4197d5e52","ac32d6368c9dce8cfcb97e6240c257e97edc74060c05f29bf46b86a4fc1f1211","f2b51d22527454ee78fe2b25026b31fbd325dd51a142628f4f4c2b11a07bc00c","1e2d030877f71470eb954cdd026d14d8a0143596dd092cc8d4c5760fd2fe1d18","88863d5da7236775b5027e4ce8355575c1afbe7e91477064441c8343af17cc35","9a209de729313822323d1552fd368f86397bafabb986582deb12e859e4fe1e97","c8fc2b7c8c6c76fe2cbb25c341f9b8443836a2dbf900b5c89cb3888487d829c5","bdd275968a84a306403364149556a79cd90096a4ff448b2d13f77f389acb7fd3",{"version":"5e01f7874fe97713d543b7dbb598ff8ea4f01ab5b10af712fea80b61a36b1e9b","signature":"4b8dc9a8f881f7f0abaf065135dd0ea99048b02838126ff6b4395e7072ad9568"},{"version":"b3d8903764c03c56c5d163039aff5c443f8c291e1e1618b9e42e26b6c65aa159","signature":"c3faf2c588035c3bd5f088e771758f8ef3ade18ee1ce91a92ae493a9ba45557b"},{"version":"c6d566b4f23df9fc956b01a122187b3868a6fca95c392548e5e42ac7057ccf0d","signature":"9cf016e7b4e40f4e230e9d60fe2989c04e885ca1ccb4896e0edc7742fadf618f"},"d69571340044a73bb4ac9ac098834cda390d25fdef5d708c8f913cfac034a5f2","2e5e3be55d2d145fc5b684de5f779b5496f7a9546d21e61a2913f769a7e219c6","29051935e3257b8e3e4a73d201c0bd40de1f4aae47d2bd0f810300b9dba4b5ff","c20a37bc34c4c9104fe79e223a22742add3f8ad602ad4662f3f53e6b2d16735c","361865b03dcb98d2a95fd93b3ab43d1471c73d743dce9dc389e1374dd0ccbd3a",{"version":"d1fc2d317157b161af800631bb01668bf08307bf2a0ff053f743aeca3a368465","impliedFormat":1},{"version":"835fb2909ce458740fb4a49fc61709896c6864f5ce3db7f0a88f06c720d74d02","impliedFormat":1},{"version":"6e5857f38aa297a859cab4ec891408659218a5a2610cd317b6dcbef9979459cc","impliedFormat":1},{"version":"2ef8ffe86811721c62038c3de3c2cb27e5555f252b9c71ae1a877f1335485aea","impliedFormat":1},{"version":"404660f2aeed19fc2af51f287dad86556beeeff2075768b01832092de4397c38","impliedFormat":1},{"version":"204b47598070c8d2b26921cdd7cb5b55804bd73ad1a60428750ef95b35c97ec4","impliedFormat":1},{"version":"85605c7095abac45fb2be5b15d1a0a806586113321eb923c28ad7fd0764ed7db","impliedFormat":1},{"version":"c7d7e274be439bd604580d994bdfb305221e471e061d3178f430c09d417f9536","impliedFormat":1},{"version":"c140211fba71b3a847b15da4a70776ed904198e7e4dc8c32df22742235072c4c","impliedFormat":1},{"version":"ce51a3572f75b0f8fc07a11828876ac28cf606a780a2d4c6b3bbcee79e48a90b","impliedFormat":1},{"version":"a8fed1298e1a1aeb2b689c56fe4200c6bf48491cabe47f54a1caa22fa9ebcc6e","impliedFormat":1},{"version":"c7d1e897d7751e2f2f7e41ee6db87a567418a0e9d307c580029e8565a76cb1f8","impliedFormat":1},{"version":"bae85faf965874160673777542d5def87f22c71125d3b71267b1384b0532a4c4","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"e0bfe601a9fdf6defe94ed62dc60ac71597566001a1f86e705c95e431a9c816d","impliedFormat":1},{"version":"8fdac54b93a59a6627b74c680e2df92f8f66b0b7d2699c9dd2a10484066a1c22","impliedFormat":1},{"version":"55fadfc733db7198f557af11bf55ae955db6257e17262351a9cdb8a98af4a9f9","impliedFormat":1},{"version":"ff49687860a57d46828bccbedd739e192ead2421a59bb04024529e8e80c6264e","impliedFormat":1},{"version":"d5063dd2ce061414ebb1ec3608295d6681d3153a427b715bd515813c621b3cf1","impliedFormat":1},{"version":"b147d5d4e973ea9725631a6bd49d3dffd0c28c521b20b7bf44456daa86723395","impliedFormat":1},{"version":"14e1da8984e72f3837de4aec8bc6d29e9ecce4dc260ac6ef4ca4e5e4f93add01","impliedFormat":1},{"version":"99003dbd8309d6cfda98e4bacb264ad40bfc197ede6af95370b0f3177076eb6a","impliedFormat":1},{"version":"be7e9393805753e479746c81dcfe4287063d83ffa30e0284f7a016775af2c1d2","impliedFormat":1},{"version":"f49bf9fcde399132c5760eefb0714cee3f8e96cd30fcec8c535e2cee57870d63","impliedFormat":1},{"version":"9943ae429279a7a4bab6bacc828f9416ee0eed92a370d4c22d5b4235b0c9bd66","impliedFormat":1},{"version":"5490cbcd192227f9a1f61bdf7000da8b47635fc0cdec9e1879b932586b6d2e8e","impliedFormat":1},{"version":"487178767be2789fa2f765d0e77fc5abad8212f7d5dfbe255011dd8e8bb5306c","impliedFormat":1},{"version":"2316301dd223d31962d917999acf8e543e0119c5d24ec984c9f22cb23247160c","impliedFormat":1},{"version":"a3eb5de45edf334745bb6347979b6f9eb44bab235910afb551d44eb05a84a233","impliedFormat":1},{"version":"bfa8e3563e561377191b49bcfb4cea149286a2b843058c1236dce8c3b541564d","impliedFormat":1},{"version":"b8495ee8dbff077d31e9365c73f170709106d7bc6e17a163c7568bb485c8368c","impliedFormat":1},{"version":"e818471014c77c103330aee11f00a7a00b37b35500b53ea6f337aefacd6174c9","impliedFormat":1},{"version":"88c4f1da1a1a6f8ca005fa1a4241897da754b7120fdb731b51a4434232bbcb42","impliedFormat":1},{"version":"31506fd6e72c0d09e082b2f0b3741e6bbe90670361c9560ef998bdb1e56edc3e","impliedFormat":1},"41140b3d97d5fc3e97768ed2c89c551681520a31b9795629d34674cf9bdf7102","4354ec0c8d17aaa038161143334560dd672b0de0749e139c25814dc75b3febdc","25e2370aacd534850e7f8d181b50b7e4711de17fad5774b9608b6f6c55dad90d","988c0a7414c51774953098902384826c3e0970233869efbfacaee42411e720fc","99e549996a10725d615b0e33621ec10d3f2c543d288faf22a5ebe4cdf8d4e24c","3f3d1753981fdc51db4bf97e9e74a9507af8de1eff47834d8ddd344d010f3bf9","dd6f52deae02047a9fdc6b1282d01a14918f637d052119a90435e71185103474","e3c7380125078fb61cc0f7dc4025ded0e300b791b29f57f84eb617c8c6073a13","577cff7163208ae5153ada8072380903c04cc7753cf616943931956c7a4b12d5","18e56f0fbe0651ae3ccb993175a10f55c224ffb22f387858673c5c52a18136de","2e2c235590914cf71058379ab8940aab31c12262b1c27c80d380e287ec64f8f9","26949c70d274e6e8856c8354f030c00d0f83d2c787e1e68f30d1e30dea9bb61a","c67976ba54d4f09f0e13f19e49ada4085de5df23baa9f563df080f12ba82af50","d0cb16f4086e4ee3c9854ac4da49431a1173c9fcf000fd929481f77d6ce74288","5c46931154d1353896f17b968c169a7e2e08c89c1937ef4d4545e7d8d3341088","eb9e7e0d5ef2240075126074be369f5afd25220d0a6aa125dbfb3fabc2ab59f0","e845935ccbcf623fa3b56f316b26ad76bc729f05cca4d2342e7ef10cab39f37a","513235c081b3b587848fb84c1edd2d917f36dc58344ddbbf179f1fbe8777347e","38d864764cad17125127f94e55591b039eeff3a9dd1639c9c8342ccc572982d0",{"version":"1d5f3f3a6b781909db1f435b239f36f013b555e88cc63a534b7ed7a179410ae8","impliedFormat":99},{"version":"7348c35ce10f8323a515ea6a6c237c0dc7c3fd5e491c4dacec2a7b93f0dfcd26","impliedFormat":1},{"version":"258e67b2638408b67fbf5fe6c953b8f2dd2a69f9171d31c9a976cd2329716e4c","impliedFormat":1},{"version":"b5495bcdc47b3890dbacf440b7a2dd7b5fdf1cad2b7fda211928d8ae930931b3","signature":"8f7f62f40d8447dc6bb1871350f1faf6b8111a8eba1f898c1d7dbaa6967d80c9"},{"version":"0e84fa13e597066b5f8bd7e9340b79f2faebb83278ee68044c737a258d70baf5","signature":"0f537ffed3090c15311197bc8c975849e1fb425a89ccb02d8e5367a8f37b1913"},"4aaaabb272f0647bbe61dd2a5744d045654bc707af2339c5632b28be5abcc08a",{"version":"1602a998bf79e0db1c34b28d1c857ee2db0b0407dadd55f2b74aecc148bde192","signature":"e85554208324358b653dc14bfa973a3911e7a811309132d524b0222362cf4842"},"f935ff1874d966d443db2aeb663eb84ddff040fdd21b66177f27807656820ff3",{"version":"de8352bc70008e927c5e26438972ada26b6ea449b8081b5e8a63d475b59dd276","signature":"cfb8e2fe289360e093792cbe0f6ac803ac39b005b7708b812509a2bac700566f"},"149d3ddb9bcaed44c8ca4e7b1771e0b5de8c10f7d59419a27857de7cfc42e4a5","d474730b002d9a48a702bb03c641d8468b993f4394a17e7acbb9e29c5687af98","0f77a49c172d34ddbe18a6e8137c027081bb84f8a01a3075da3a0e29033f98eb","79bd6640b0bcf9842b387479dff22f2b64e132b4f913202244ced6444e7cdde8","dc7a174d3c5716066adb18717e06f10c26db9ca10200ad819460fd132abf5f8c","6deb3ba04df8c0cce11a39fbe3a22c10831a285aee844c27879ee92b8ccc683b","0d9958101decfe610955e3820eb2fdeacee0a5c55ce1333a8b9eb59a37194cea",{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"54a99ba46c134a0f697cf3539249cb97efb159ae7d0b4b2881208a6563bafbc0","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},"88099a984010d6ea67a599aa2523286dbf1138466a24b1538b55d73bb5f9c048",{"version":"b940e698c83d12a887d0c759c19f2d3379040084c2223a6ce66e3c14df7e5b16","signature":"fbd03632acc9017d591fb0ec95b5acac82f3ef9c5de6d69b08e85f34720f528f"},"5ac61e0ed4f3d38cf20c8cf80e0292b6c03634917175a69c00a6d807cf563501","40e8386b2bd641491e0d1d9d5cd7518e041eee73f0a320fd99f7770981425a09","57ddd6f03de0064af9bc820db6b4d2f8e93ce2f8a2b92142ef7fd64c2f8a788e",{"version":"4378a371b86ea8bf3cb7353d1dd4677b085a31dad9fbd50babba2cdd7714dac6","signature":"97e90cff06c1ba24714499dc18e95bde285d2d52199f3816468185aef3e02dfc"},"e2c23db28bcbbe42e51845f62a9fc1b0652a9701ee8fbf3283c56775657f03da","87ae365a7684f34dda647ec7c5070c89a26af2c8a8d462ea1767d5f4c98e24b9","078bb4e7b5158a85073e7d5320af3ea37f20555e948e03d4d457543c1b83a51c","91d75abd9c6f1423c79056bb49aa634e19b93a24c68e73b67e94b408b6dda0a1","725da6635fbc94f2f32c8e455fb8555dce32eb50ab3d48eb99ccd423c50de03d","75ed20a17804e37055222e3629cc8d746636a2eabc2413be78d7890abeed5f0f","f4e310972e7c2b72bc98cce31f7c2ae1556e5b365da6ba90db9f502886433aac","e5f088449e3f5fba279f3b9b6bcc6c7014dd408b51b0de56b6e0ed51404af6d2","2d2f0b8d7c3d3e6043ed7e70df2209de040cc069459dad0955b38acb550cff2a",{"version":"72189afb4340e6659fab627973dd49aae7908f0312e7aea3d5ba4137c7e49459","signature":"a97b24d588d8d2ae40ab5edba31ec199f05c8722eb88bc64e06694ec9562ff76"},"452721c6552c9b219e07e4eb139a24fdc38b2c6d2d981d55a1872ecddf3ea5db","f67dd41482f7affe4f42561bd4bef25e5cdb410f56bd91dc171adedc9662deeb","689e7fbb5bf4d4ad3676d7bfb0a768bb28337a2443550384833927d26bbe607f","6fcd60690c6af81d0ab4b6bff64c50c7ec620f8ad14dded6cfc8cdf547257db4","adc4eca6e90579519b4765610765a1d48a764d0d0ca48ca4645f2046d6fa275f","022ef0efaac3c611f9066cc7bc80084660512f69ac115460ca92865c517388fb","9c128b6476630357076a2915336b67b5168a624fda07a17742eece776aac7d69","7b9f04b527a334bfc1bb8353ddec6b77a14767e5401fcd09db05a2c6bdbf5aea","7d2c507ce3185802f5874016b5ea63289b69c1fee84b68e34c8dd1d4285b4bf0","010fc987bad9915006e40d1b9e866b670b36f618181b220da9c5221c06af1ebe","6d6c78807f79f6529372cec42788db010a53a23737bbc0393a228fd3cdce9f45","86e88d56a772d05ebc2b788f736d55ce385cbd2061c79dfd956db563fdab74c1","57fb28667928bcd901f723f20a981e5c5ac3ac9713707150937b66581df18eef","ea6dd0345f148e9b84d735534b7e0544f3f4214a211766aa9674fcdaec657d6c","41685eeb900284c36abf5c74520d00009b137886b9bb51fedd3cbfe7194a233a","ea0da3d0167608aa472118d656be4478678d5bb2ffc882bf96382fa3020b706f","b17666fb8902e34400e3a2ffbdac6cd1355f8ecc906687eed283baeacee2ed17","1fbe1614d7d6026aae35cd2bd0b5d9742339149daf1032006b2aea724354c74b","e57cb9f09aef4cb649695ac671787fea85d3a5ada735981d3b54a4660120a4d6","607a648edf06bb4f2974ed071bd51e9d6d51662f3e0d727aa0e0c848181f112c","36a40f4e28768776501ab6780fb95ae8abaf3d75fbf85913b0ac39429ea158d0","1e04399e1c266d3ebcdaf244ae53ec529a4e11cdbf87dd4826d3a975d6bc91df","09c2663a39316253d26ea01dfcbd4fa8686f3c63d72e72493cc43ea9b3f57315","703adcfd2979fb0030b15852ac0143582c57d2d12083a4cbe7ad84f64be673af","300e6693e57e22ca8de9ccd0923dd3f551d05ba96ef39a577bdf09077605ae33"],"root":[546,547,[554,559],[676,678],[682,694],[698,701],[703,738]],"options":{"allowImportingTsExtensions":true,"allowJs":false,"esModuleInterop":true,"jsx":1,"module":99,"noUncheckedIndexedAccess":true,"skipLibCheck":true,"strict":true,"target":9,"verbatimModuleSyntax":true},"referencedMap":[[545,1],[544,1],[685,2],[686,3],[687,2],[688,3],[689,3],[690,3],[691,3],[692,3],[693,3],[683,4],[694,3],[684,3],[710,5],[712,6],[714,7],[715,5],[717,8],[719,9],[720,10],[721,11],[722,12],[724,13],[725,14],[727,15],[728,16],[698,17],[729,5],[730,18],[700,5],[709,19],[731,20],[732,21],[733,21],[734,5],[735,6],[736,5],[737,6],[738,21],[558,22],[559,22],[682,23],[555,24],[556,25],[716,26],[701,27],[713,28],[718,29],[723,30],[706,31],[705,32],[707,33],[703,1],[726,26],[704,34],[711,35],[708,36],[676,37],[557,1],[699,38],[677,39],[554,40],[678,41],[546,42],[547,43],[350,1],[255,1],[130,44],[131,44],[132,45],[77,46],[133,47],[134,48],[135,49],[75,1],[136,50],[137,51],[138,52],[139,53],[140,54],[141,55],[142,55],[143,56],[144,57],[145,58],[146,59],[78,1],[76,1],[147,60],[148,61],[149,62],[183,63],[150,64],[151,1],[152,65],[153,66],[154,67],[155,68],[156,69],[157,70],[158,71],[159,72],[160,73],[161,73],[162,74],[163,1],[164,75],[165,76],[167,77],[166,78],[168,79],[169,80],[170,81],[171,82],[172,83],[173,84],[174,85],[175,86],[176,87],[177,88],[178,89],[179,90],[180,91],[79,1],[80,92],[81,1],[82,1],[126,93],[127,94],[128,1],[129,79],[181,95],[182,96],[188,97],[187,4],[189,98],[186,99],[277,100],[276,101],[184,102],[470,1],[185,103],[66,1],[68,104],[468,4],[469,4],[67,1],[493,105],[500,106],[507,107],[517,108],[487,109],[245,1],[218,110],[259,111],[239,1],[385,112],[254,113],[235,1],[241,1],[216,1],[486,114],[291,115],[217,1],[238,116],[262,117],[263,118],[466,119],[481,120],[331,121],[379,122],[380,123],[378,124],[377,1],[240,125],[261,126],[219,127],[405,1],[406,128],[244,129],[220,130],[297,129],[293,129],[207,129],[257,131],[256,1],[384,132],[397,1],[210,1],[506,133],[442,134],[443,135],[439,136],[526,1],[444,1],[445,4],[440,137],[530,138],[529,139],[525,1],[311,1],[480,140],[479,1],[524,141],[441,4],[325,142],[315,143],[326,144],[314,1],[319,145],[323,146],[324,147],[320,148],[322,149],[321,150],[316,1],[318,151],[527,1],[523,1],[528,1],[518,152],[521,153],[305,154],[304,155],[488,1],[303,156],[533,4],[302,157],[285,1],[535,1],[696,158],[695,1],[679,159],[536,4],[537,160],[199,1],[381,161],[382,162],[383,163],[203,1],[247,1],[213,164],[190,1],[459,4],[205,165],[458,166],[455,167],[457,168],[456,169],[446,1],[447,1],[454,1],[449,1],[452,170],[448,1],[450,171],[453,172],[451,171],[215,1],[211,1],[212,129],[267,1],[272,173],[275,174],[271,175],[269,176],[274,177],[270,178],[265,1],[464,4],[299,4],[492,157],[501,179],[505,180],[424,181],[392,1],[288,1],[393,182],[214,183],[482,184],[483,185],[278,186],[437,187],[411,188],[463,189],[426,4],[435,190],[431,191],[430,192],[429,193],[434,194],[416,195],[465,196],[412,1],[415,197],[413,1],[432,198],[461,199],[460,1],[462,1],[422,200],[420,1],[280,201],[279,202],[376,203],[193,204],[425,205],[428,206],[417,207],[423,208],[409,209],[476,210],[402,211],[335,212],[346,213],[208,214],[403,215],[401,216],[204,217],[281,218],[266,1],[282,219],[360,220],[264,1],[359,221],[421,222],[74,1],[354,223],[353,1],[352,224],[246,1],[407,225],[347,1],[198,1],[372,1],[243,1],[358,226],[283,227],[419,228],[345,229],[418,1],[357,1],[268,1],[362,230],[386,231],[363,232],[242,1],[365,233],[367,234],[366,235],[249,1],[356,214],[369,236],[334,237],[355,238],[361,239],[223,1],[227,1],[226,1],[225,1],[230,1],[224,1],[233,1],[232,1],[229,1],[228,1],[231,1],[234,240],[222,1],[339,241],[338,1],[343,242],[340,243],[342,244],[344,242],[341,243],[680,245],[404,246],[300,247],[396,248],[499,1],[394,1],[511,249],[513,250],[388,251],[512,252],[497,1],[194,253],[191,253],[221,1],[387,254],[371,255],[374,256],[375,257],[197,258],[475,258],[295,258],[336,259],[296,259],[196,260],[195,1],[337,261],[209,262],[467,263],[474,215],[473,264],[436,265],[438,266],[471,267],[472,268],[485,269],[484,270],[478,271],[333,272],[330,273],[332,274],[329,275],[368,276],[398,1],[399,277],[498,1],[373,278],[370,279],[395,280],[477,1],[284,281],[410,282],[408,283],[286,284],[289,285],[389,1],[287,286],[290,286],[495,1],[494,1],[496,1],[391,1],[390,1],[292,287],[427,1],[327,288],[237,289],[260,1],[202,290],[298,1],[503,4],[201,1],[515,291],[313,4],[509,4],[312,292],[490,293],[310,291],[206,1],[516,294],[519,295],[308,4],[309,4],[301,1],[200,1],[273,1],[307,296],[306,297],[248,298],[414,72],[294,72],[364,1],[349,299],[348,1],[236,300],[317,301],[192,1],[328,4],[400,164],[433,1],[491,302],[69,4],[72,303],[73,304],[70,4],[71,1],[258,92],[253,305],[252,1],[251,306],[250,1],[489,307],[502,308],[504,309],[508,310],[697,311],[510,312],[514,313],[543,314],[520,314],[542,315],[522,316],[531,317],[681,318],[532,319],[534,320],[538,321],[541,164],[540,1],[539,322],[351,323],[64,1],[65,1],[11,1],[12,1],[14,1],[13,1],[2,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[3,1],[23,1],[24,1],[4,1],[25,1],[29,1],[26,1],[27,1],[28,1],[30,1],[31,1],[32,1],[5,1],[33,1],[34,1],[35,1],[36,1],[6,1],[40,1],[37,1],[38,1],[39,1],[41,1],[7,1],[42,1],[47,1],[48,1],[43,1],[44,1],[45,1],[46,1],[8,1],[52,1],[49,1],[50,1],[51,1],[53,1],[9,1],[54,1],[55,1],[56,1],[58,1],[57,1],[59,1],[60,1],[10,1],[61,1],[1,1],[62,1],[63,1],[101,324],[114,325],[98,326],[115,186],[124,327],[89,328],[90,329],[88,330],[123,322],[118,331],[122,332],[92,333],[111,334],[91,335],[121,336],[86,337],[87,331],[93,338],[94,1],[100,339],[97,338],[84,340],[125,341],[116,342],[104,343],[103,338],[105,344],[108,345],[102,346],[106,347],[119,322],[95,348],[96,349],[109,350],[85,186],[113,351],[112,338],[99,349],[107,352],[110,353],[117,1],[83,1],[120,354],[659,355],[651,356],[657,357],[652,357],[654,357],[648,356],[658,358],[653,359],[655,357],[656,357],[649,360],[650,361],[644,362],[572,363],[643,364],[574,365],[642,1],[573,366],[647,367],[646,368],[645,369],[565,1],[576,370],[575,363],[577,1],[567,364],[571,371],[566,1],[568,372],[569,373],[570,1],[578,374],[579,374],[580,374],[581,374],[582,374],[583,374],[584,374],[585,374],[586,374],[587,374],[588,374],[589,374],[590,374],[591,374],[592,374],[593,374],[595,374],[594,374],[596,374],[597,374],[598,374],[599,374],[600,374],[601,374],[602,374],[641,375],[603,374],[604,374],[605,374],[606,374],[607,374],[608,374],[609,374],[610,374],[611,374],[612,374],[613,374],[614,374],[615,374],[616,374],[617,374],[618,374],[620,374],[619,374],[622,374],[621,374],[623,374],[624,374],[625,374],[626,374],[627,374],[628,374],[629,374],[630,374],[631,374],[632,374],[633,374],[634,374],[635,374],[636,374],[637,374],[640,374],[638,374],[639,374],[664,376],[665,377],[671,378],[666,376],[562,379],[564,380],[563,381],[561,376],[675,382],[667,377],[660,383],[673,1],[670,1],[672,384],[674,1],[661,385],[668,1],[669,383],[663,386],[662,1],[560,1],[549,1],[552,1],[551,1],[548,1],[550,1],[553,387],[702,4]],"affectedFilesPendingEmit":[685,686,687,688,689,690,691,692,693,683,694,684,710,712,714,715,717,719,720,721,722,724,725,727,728,698,729,730,700,709,731,732,733,734,735,736,737,738,558,559,682,555,556,716,701,713,718,723,706,705,707,703,726,704,711,708,676,557,699,677,554,678,547],"version":"5.9.3"}
\ No newline at end of file
diff --git a/apps/miniapp-client/src/App.tsx b/apps/miniapp-client/src/App.tsx
index eff48a0..cf5b5e1 100644
--- a/apps/miniapp-client/src/App.tsx
+++ b/apps/miniapp-client/src/App.tsx
@@ -16,6 +16,7 @@ import { Perks } from './screens/Perks.tsx';
import { Profile } from './screens/Profile.tsx';
import { Services } from './screens/Services.tsx';
import { Chat } from './screens/Chat.tsx';
+import { Points } from './screens/Points.tsx';
const ROOTS = ['/', '/orders', '/services', '/perks', '/profile', '/docs'];
@@ -65,6 +66,7 @@ function Routes({ segment }: { segment: 'MOVING' | 'LIVING' }) {
else if (path === '/profile') screen = ;
else if (path === '/membership') screen = ;
else if (path === '/chat') screen = ;
+ else if (path === '/points') screen = ;
else screen = segment === 'MOVING' ? : ;
const withNav = ROOTS.includes(path);
return (
diff --git a/apps/miniapp-client/src/app.css b/apps/miniapp-client/src/app.css
index 38c4452..28bf529 100644
--- a/apps/miniapp-client/src/app.css
+++ b/apps/miniapp-client/src/app.css
@@ -933,3 +933,105 @@
.chat-compose__send:disabled {
opacity: 0.4;
}
+
+/* барики в форме заказа */
+.points-toggle {
+ display: flex;
+ gap: 12px;
+ align-items: flex-start;
+ padding: 12px 14px;
+ border-radius: 18px;
+ background: var(--bc-perks, #f6e3b4);
+ cursor: pointer;
+}
+.points-toggle[data-off] {
+ opacity: 0.6;
+ cursor: default;
+}
+.points-toggle input {
+ width: 22px;
+ height: 22px;
+ margin-top: 1px;
+ accent-color: var(--bc-plum);
+ flex: none;
+}
+.points-toggle small {
+ display: block;
+ font-size: 13px;
+ opacity: 0.8;
+ margin-top: 2px;
+}
+
+/* ───── барики ───── */
+.points-hero {
+ gap: 6px;
+}
+.points-hero__num {
+ font-family: var(--bc-font-head);
+ font-weight: 800;
+ font-size: 46px;
+ line-height: 1;
+ letter-spacing: -0.03em;
+}
+.points-hero__ghost {
+ color: #fff;
+ border-color: rgba(255, 255, 255, 0.5);
+}
+.points-rates {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 14px;
+}
+.points-rates th,
+.points-rates td {
+ padding: 6px 4px;
+ text-align: right;
+}
+.points-rates th:first-child,
+.points-rates td:first-child {
+ text-align: left;
+}
+.points-rates th {
+ font-weight: 600;
+ opacity: 0.6;
+}
+.points-rates [data-on] {
+ font-weight: 800;
+ opacity: 1;
+ color: var(--bc-plum);
+}
+.points-dots {
+ display: flex;
+ gap: 8px;
+}
+.points-dots span {
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background: var(--bc-bg);
+ border: 2px solid rgba(74, 16, 40, 0.15);
+}
+.points-dots span[data-mark] {
+ border-color: var(--bc-plum);
+}
+.points-dots span[data-on] {
+ background: var(--bc-plum);
+ border-color: var(--bc-plum);
+}
+.points-row {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ padding: 10px 4px;
+ border-bottom: 1px solid rgba(74, 16, 40, 0.08);
+}
+.points-row:last-child {
+ border-bottom: 0;
+}
+.points-plus {
+ color: var(--bc-home-ink, #2f5b1f);
+ white-space: nowrap;
+}
+.points-minus {
+ white-space: nowrap;
+}
diff --git a/apps/miniapp-client/src/screens/OrderDetail.tsx b/apps/miniapp-client/src/screens/OrderDetail.tsx
index d296af2..61a15b4 100644
--- a/apps/miniapp-client/src/screens/OrderDetail.tsx
+++ b/apps/miniapp-client/src/screens/OrderDetail.tsx
@@ -112,9 +112,15 @@ export function OrderDetail({ id }: { id: string }) {
−{amd(o.discountAmount)}
)}
+ {o.pointsUsed > 0 && (
+
+ {t('client.points.paidLine')}
+ −{amd(o.pointsUsed)}
+
+ )}
{t('client.order.total')}
- {amd(o.totalPrice)}
+ {amd(o.totalPrice - o.pointsUsed)}
{o.cancelFee > 0 && (
diff --git a/apps/miniapp-client/src/screens/OrderForm.tsx b/apps/miniapp-client/src/screens/OrderForm.tsx
index 071a278..58f3fdd 100644
--- a/apps/miniapp-client/src/screens/OrderForm.tsx
+++ b/apps/miniapp-client/src/screens/OrderForm.tsx
@@ -31,6 +31,8 @@ export function OrderForm({ code }: { code: string }) {
const [promoInput, setPromoInput] = useState('');
const [promo, setPromo] = useState('');
const [promoError, setPromoError] = useState (null);
+ // барики: списать в этом заказе (с промокодом нельзя)
+ const [usePts, setUsePts] = useState(false);
const [touched, setTouched] = useState(false);
// дефолты услуги, затем — параметры повторяемого заказа (ORD-7)
@@ -132,10 +134,13 @@ export function OrderForm({ code }: { code: string }) {
paymentMethodId: methodId || undefined,
repeatOfId: repeatId ?? undefined,
promoCode: q?.promo ? promo : undefined,
+ usePoints: ptsUsed || undefined,
});
}
const q = quote.data;
+ const ptsAvailable = !!q?.points.allowed && !q.promo;
+ const ptsUsed = usePts && ptsAvailable ? q!.points.max : 0;
return (
@@ -294,6 +299,27 @@ export function OrderForm({ code }: { code: string }) {
) : (
)}
+ {q && q.points.balance > 0 && (
+
+ )}
+ {ptsUsed > 0 && (
+
+ {t('client.points.paidLine')}
+ −{amd(ptsUsed)}
+
+ )}
{
@@ -325,7 +351,7 @@ export function OrderForm({ code }: { code: string }) {
{t('client.order.total')}
- {q ? amd(q.totalPrice) : '…'}
+ {q ? amd(q.totalPrice - ptsUsed) : '…'}
{slot && (
diff --git a/apps/miniapp-client/src/screens/Points.tsx b/apps/miniapp-client/src/screens/Points.tsx
new file mode 100644
index 0000000..4729ec4
--- /dev/null
+++ b/apps/miniapp-client/src/screens/Points.tsx
@@ -0,0 +1,213 @@
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { Badge, Button, Card, Center, Field, Icon, Sheet, Spinner } from '@barev/ui';
+import { errorText, haptic, useI18n, useToast, useTRPC } from '@barev/web';
+import { useState } from 'react';
+import { LEVEL_NAME, PageHead, type Level } from '../lib.tsx';
+
+/** Экран «Барики»: баланс, ожидание, сгорание, ставки по уровню, серия уборок, маршрут, история */
+export function Points() {
+ const { t, dt, locale } = useI18n();
+ const trpc = useTRPC();
+ const p = useQuery(trpc.client.points.summary.queryOptions());
+ const history = useQuery(trpc.client.points.history.queryOptions());
+ const [pay, setPay] = useState(false);
+ const n = (v: number) => new Intl.NumberFormat(locale === 'zh' ? 'zh-CN' : locale).format(v);
+ const date = (d: Date) => dt(d, { day: 'numeric', month: 'long' });
+ const name = (m: Record | null | undefined) => (m ? m[locale] || m.ru || m.en || '' : '');
+
+ if (!p.data)
+ return (
+
+
+
+ );
+ const d = p.data;
+ const tier = d.tier as Level;
+ return (
+
+
+
+
+
+ {t('client.points.balance')}
+
+ {n(d.balance)}
+
+ {t('client.points.equals', { amount: n(Math.max(0, d.balance)) })}
+
+ {d.pending > 0 && ⏳ {t('client.points.pending', { amount: n(d.pending), date: d.pendingNextAt ? date(d.pendingNextAt) : '—' })}}
+ {d.burnAt && 🔥 {t('client.points.burn', { amount: n(d.burnAmount), date: date(d.burnAt) })}}
+
+ {d.openRequests > 0 && {t('client.points.requestPending')}}
+
+
+
+
+ {t('client.points.rates')}
+ {LEVEL_NAME[tier]}
+
+
+
+
+ |
+ Barev |
+ Barev+ |
+ Elite |
+
+
+
+ {d.rates.map((r) => (
+
+ | {name(r.name)} |
+ {r.barev}% |
+ {r.plus}% |
+ {r.elite}% |
+
+ ))}
+
+
+ {tier === 'BAREV' && d.plusWouldGet > 0 && (
+
+ {t('client.points.plusWouldGet', { amount: n(d.plusWouldGet) })}
+
+ )}
+
+
+
+ {t('client.points.streak')}
+
+ {[1, 2, 3, 4, 5, 6].map((i) => (
+ = i || undefined} data-mark={i === 3 || i === 6 || undefined} />
+ ))}
+
+
+ {d.streak.next
+ ? t('client.points.streakLeft', { left: d.streak.next - d.streak.count, bonus: d.streak.next === 3 ? 2 : 3, days: d.streak.gapDays })
+ : t('client.points.streakMax', { bonus: d.streak.bonusPct })}
+
+
+
+ {d.route && (
+
+ {t('client.points.route')}
+
+ {[1, 2, 3].map((i) => (
+ = i || undefined} />
+ ))}
+
+
+ {t('client.points.routeText', { done: d.route.done, amount: n(d.route.amount), date: date(d.route.until) })}
+
+
+ )}
+
+
+ {t('client.points.history')}
+ {!history.data ? (
+
+ ) : history.data.length === 0 ? (
+
+ {t('client.points.empty')}
+
+ ) : (
+
+ {history.data.map((r) => (
+
+
+
+ {r.type === 'bonus' ? name(r.bonus) : r.type === 'accrual' ? name(r.category) : t(`client.points.type.${r.type}`)}
+ {r.orderRef ? {r.orderRef} : null}
+
+
+ {dt(r.at, { day: 'numeric', month: 'short' })} · {t(`client.points.status.${r.status}`)}
+ {r.status === 'PENDING' && r.availableAt ? ` · ${t('client.points.availableFrom', { date: date(r.availableAt) })}` : ''}
+ {r.expiresAt && r.status === 'ACTIVE' ? ` · ${t('client.points.until', { date: date(r.expiresAt) })}` : ''}
+
+ {r.comment && 💬 {r.comment} }
+
+ 0 ? 'points-plus' : 'points-minus'}>
+ {r.amount > 0 ? '+' : '−'}
+ {n(Math.abs(r.amount))}
+
+
+ ))}
+
+ )}
+
+ {pay && setPay(false)} />}
+
+ );
+}
+
+/** Оплатить бариками: выбрать заказ или ввести сумму — запрос уходит команде */
+function PaySheet({ balance, sharePct, min, onClose }: { balance: number; sharePct: number; min: number; onClose: () => void }) {
+ const { t, amd, dt } = useI18n();
+ const trpc = useTRPC();
+ const qc = useQueryClient();
+ const toast = useToast();
+ const orders = useQuery(trpc.client.orders.list.queryOptions());
+ const [orderId, setOrderId] = useState('');
+ const [amount, setAmount] = useState('');
+ const [note, setNote] = useState('');
+ const order = orders.data?.active.find((o) => o.id === orderId);
+ const max = order ? Math.min(balance, Math.floor(((order.totalPrice - order.pointsUsed) * sharePct) / 100)) : balance;
+ const value = Number(amount) || 0;
+ const send = useMutation(
+ trpc.client.points.request.mutationOptions({
+ onSuccess: () => {
+ haptic.ok();
+ toast(t('client.points.requested'));
+ void qc.invalidateQueries();
+ onClose();
+ },
+ onError: (e) => toast(errorText(t, e), 'error'),
+ }),
+ );
+ const payable = orders.data?.active.filter((o) => o.paymentStatus === 'UNPAID') ?? [];
+ return (
+
+
+
+ {t('client.points.pay')}
+
+
+
+
+
+ {t('client.points.payHint', { pct: sharePct, min: amd(min).replace(/\s?֏$/, '') })}
+
+
+
+
+
+ setAmount(e.target.value.replace(/\D/g, '').slice(0, 7))} />
+
+
+ {t('client.points.max', { max: amd(max).replace(/\s?֏$/, '') })}
+
+ {!order && (
+
+ setNote(e.target.value)} />
+
+ )}
+ max} onClick={() => send.mutate({ amount: value, orderId: orderId || undefined, note: note.trim() || undefined })}>
+ {t('client.points.send')}
+
+
+
+ );
+}
diff --git a/apps/miniapp-client/src/screens/Profile.tsx b/apps/miniapp-client/src/screens/Profile.tsx
index f304d91..07d572d 100644
--- a/apps/miniapp-client/src/screens/Profile.tsx
+++ b/apps/miniapp-client/src/screens/Profile.tsx
@@ -42,6 +42,14 @@ export function Profile() {
|