From 8d3a0874ef6e839f893e0f08176e5e120e7024f2 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Mon, 27 Apr 2026 16:55:30 +0300 Subject: [PATCH] add interactive analytics dashboard for Sverdlovsk market and PRINZIP 3 pages (market, PRINZIP drilldown, developers leaderboard) on top of existing v_developer_full_metrics + domrf_realization views. ECharts on the frontend, FastAPI router /api/v1/analytics on the backend. --- .gitignore | 5 + backend/app/api/v1/analytics.py | 117 ++++ backend/app/main.py | 3 +- backend/app/services/analytics_queries.py | 588 ++++++++++++++++++ frontend/next-env.d.ts | 6 + frontend/package-lock.json | 88 ++- frontend/package.json | 19 +- .../src/app/analytics/developers/page.tsx | 107 ++++ frontend/src/app/analytics/layout.tsx | 47 ++ frontend/src/app/analytics/page.tsx | 154 +++++ frontend/src/app/analytics/prinzip/page.tsx | 144 +++++ frontend/src/app/layout.tsx | 4 +- frontend/src/app/page.tsx | 3 + frontend/src/app/providers.tsx | 19 + .../src/components/analytics/AnalyticsNav.tsx | 46 ++ .../src/components/analytics/ChartShell.tsx | 33 + .../analytics/DeveloperLeaderboard.tsx | 152 +++++ .../components/analytics/DistrictTreemap.tsx | 50 ++ .../src/components/analytics/InsightCards.tsx | 106 ++++ frontend/src/components/analytics/KpiCard.tsx | 65 ++ .../components/analytics/MarketPulseChart.tsx | 70 +++ .../components/analytics/PipelineChart.tsx | 51 ++ .../analytics/PrinzipDistrictsBar.tsx | 77 +++ .../components/analytics/PrinzipGapBar.tsx | 70 +++ .../analytics/PrinzipQuartirographyPie.tsx | 41 ++ .../analytics/PrinzipVelocityChart.tsx | 65 ++ .../analytics/QuartirographyChart.tsx | 71 +++ frontend/src/components/analytics/Section.tsx | 43 ++ .../components/analytics/VelocityScatter.tsx | 76 +++ .../components/analytics/YandexClassPie.tsx | 41 ++ frontend/src/lib/analytics-api.ts | 125 ++++ frontend/src/types/analytics.ts | 146 +++++ frontend/tsconfig.tsbuildinfo | 1 + 33 files changed, 2598 insertions(+), 35 deletions(-) create mode 100644 backend/app/api/v1/analytics.py create mode 100644 backend/app/services/analytics_queries.py create mode 100644 frontend/next-env.d.ts create mode 100644 frontend/src/app/analytics/developers/page.tsx create mode 100644 frontend/src/app/analytics/layout.tsx create mode 100644 frontend/src/app/analytics/page.tsx create mode 100644 frontend/src/app/analytics/prinzip/page.tsx create mode 100644 frontend/src/app/providers.tsx create mode 100644 frontend/src/components/analytics/AnalyticsNav.tsx create mode 100644 frontend/src/components/analytics/ChartShell.tsx create mode 100644 frontend/src/components/analytics/DeveloperLeaderboard.tsx create mode 100644 frontend/src/components/analytics/DistrictTreemap.tsx create mode 100644 frontend/src/components/analytics/InsightCards.tsx create mode 100644 frontend/src/components/analytics/KpiCard.tsx create mode 100644 frontend/src/components/analytics/MarketPulseChart.tsx create mode 100644 frontend/src/components/analytics/PipelineChart.tsx create mode 100644 frontend/src/components/analytics/PrinzipDistrictsBar.tsx create mode 100644 frontend/src/components/analytics/PrinzipGapBar.tsx create mode 100644 frontend/src/components/analytics/PrinzipQuartirographyPie.tsx create mode 100644 frontend/src/components/analytics/PrinzipVelocityChart.tsx create mode 100644 frontend/src/components/analytics/QuartirographyChart.tsx create mode 100644 frontend/src/components/analytics/Section.tsx create mode 100644 frontend/src/components/analytics/VelocityScatter.tsx create mode 100644 frontend/src/components/analytics/YandexClassPie.tsx create mode 100644 frontend/src/lib/analytics-api.ts create mode 100644 frontend/src/types/analytics.ts create mode 100644 frontend/tsconfig.tsbuildinfo diff --git a/.gitignore b/.gitignore index f8d0bfc2..1f0fe486 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,11 @@ __pycache__/ *.egg-info/ node_modules/ +# Next.js build artifacts +.next/ +frontend/.next/ +out/ + # Env / secrets .env .env.local diff --git a/backend/app/api/v1/analytics.py b/backend/app/api/v1/analytics.py new file mode 100644 index 00000000..56f59ca8 --- /dev/null +++ b/backend/app/api/v1/analytics.py @@ -0,0 +1,117 @@ +"""Analytics endpoints for the Sverdlovsk dashboard.""" + +from __future__ import annotations + +import re +from typing import Annotated, Any, Literal + +from fastapi import APIRouter, Depends, HTTPException, Query +from sqlalchemy.orm import Session + +from app.core.db import get_db +from app.services import analytics_queries as q + +router = APIRouter() + +DEV_ID_RE = re.compile(r"^\d+_\d+$") + + +def _validate_dev(dev_id: str) -> str: + if not DEV_ID_RE.match(dev_id): + raise HTTPException(status_code=400, detail="developer_id must match \\d+_\\d+") + return dev_id + + +# ---- Sverdlovsk region ------------------------------------------------------ + + +@router.get("/sverdl/market-pulse") +def sverdl_market_pulse(db: Annotated[Session, Depends(get_db)]) -> list[dict[str, Any]]: + """Monthly series Jan 2025 → present: total square (тыс м²), sold%, avg price.""" + return q.market_pulse(db, region_code=66) + + +@router.get("/sverdl/quartirography") +def sverdl_quartirography( + db: Annotated[Session, Depends(get_db)], + source: Literal["portfolio", "deals"] = "portfolio", +) -> list[dict[str, Any]]: + """Что строится (portfolio) vs что покупают (deals) по сегментам.""" + return q.quartirography(db, source=source, region_id=66) + + +@router.get("/sverdl/pipeline") +def sverdl_pipeline(db: Annotated[Session, Depends(get_db)]) -> list[dict[str, Any]]: + """По году ввода: total / sold% / unsold% / unopened%.""" + return q.pipeline_by_year(db, region_code=66) + + +@router.get("/sverdl/districts") +def sverdl_districts(db: Annotated[Session, Depends(get_db)]) -> list[dict[str, Any]]: + """ЕКБ-районы: ЖК-count, flat-count, area, цены.""" + return q.districts(db) + + +@router.get("/sverdl/yandex-listings") +def sverdl_yandex_listings(db: Annotated[Session, Depends(get_db)]) -> dict[str, Any]: + """Снимок активных новостроек Яндекс.Недвижимости.""" + return q.yandex_listings(db) + + +# ---- Developers ------------------------------------------------------------- + + +@router.get("/developers/top") +def developers_top( + db: Annotated[Session, Depends(get_db)], + limit: Annotated[int, Query(ge=1, le=50)] = 15, +) -> list[dict[str, Any]]: + """Топ-девелоперы Свердл по объёму с Δ sold% за всю доступную историю.""" + return q.top_developers(db, region_code=66, limit=limit) + + +@router.get("/developers/history") +def developers_history( + db: Annotated[Session, Depends(get_db)], + ids: Annotated[str, Query(min_length=1)], +) -> list[dict[str, Any]]: + """Comma-separated developer_ids → time series sold_perc.""" + dev_ids = [_validate_dev(i.strip()) for i in ids.split(",") if i.strip()] + if not dev_ids: + raise HTTPException(status_code=400, detail="ids must contain at least one developer_id") + return q.developer_history(db, developer_ids=dev_ids, region_code=66) + + +@router.get("/developers/{developer_id}") +def developer_detail( + db: Annotated[Session, Depends(get_db)], + developer_id: str, +) -> dict[str, Any]: + dev = _validate_dev(developer_id) + result = q.developer_detail(db, developer_id=dev) + if result is None: + raise HTTPException(status_code=404, detail="developer not found") + return result + + +@router.get("/developers/{developer_id}/portfolio") +def developer_portfolio( + db: Annotated[Session, Depends(get_db)], + developer_id: str, +) -> list[dict[str, Any]]: + dev = _validate_dev(developer_id) + return q.developer_portfolio(db, developer_id=dev) + + +# ---- PRINZIP-specific ------------------------------------------------------- + + +@router.get("/prinzip/insights") +def prinzip_insights() -> dict[str, Any]: + """Static recommendations + benchmarks (from PRINZIP_Strategy_Apr27).""" + return q.prinzip_insights() + + +@router.get("/prinzip/districts") +def prinzip_districts(db: Annotated[Session, Depends(get_db)]) -> list[dict[str, Any]]: + return q.prinzip_district_distribution(db, developer_id="6208_0") diff --git a/backend/app/main.py b/backend/app/main.py index bfdfd360..91087501 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -5,7 +5,7 @@ import sentry_sdk from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from app.api.v1 import concepts, parcels +from app.api.v1 import analytics, concepts, parcels from app.core.config import settings @@ -32,6 +32,7 @@ app.add_middleware( app.include_router(concepts.router, prefix="/api/v1/concepts", tags=["concepts"]) app.include_router(parcels.router, prefix="/api/v1/parcels", tags=["parcels"]) +app.include_router(analytics.router, prefix="/api/v1/analytics", tags=["analytics"]) @app.get("/health") diff --git a/backend/app/services/analytics_queries.py b/backend/app/services/analytics_queries.py new file mode 100644 index 00000000..d9c8dfc7 --- /dev/null +++ b/backend/app/services/analytics_queries.py @@ -0,0 +1,588 @@ +"""SQL queries for /api/v1/analytics endpoints. + +One function per endpoint. All return plain dicts/lists ready for JSON. +Region 66 = Sverdlovskaya oblast. Developer 6208_0 = PRINZIP. +""" + +from __future__ import annotations + +from decimal import Decimal +from typing import Any + +from sqlalchemy import text +from sqlalchemy.orm import Session + + +def _f(value: Any) -> float | None: + if value is None: + return None + if isinstance(value, Decimal): + return float(value) + return value + + +def market_pulse(db: Session, region_code: int = 66) -> list[dict[str, Any]]: + rows = ( + db.execute( + text( + """ + SELECT snapshot_date, rep_year, rep_month, + total_square, sold_perc, price_avg + FROM domrf_realization + WHERE region_code = :region_code + AND endpoint_type = 'total' + AND type_square = 'total' + ORDER BY snapshot_date + """ + ), + {"region_code": region_code}, + ) + .mappings() + .all() + ) + return [ + { + "snapshot_date": r["snapshot_date"].isoformat(), + "rep_year": r["rep_year"], + "rep_month": r["rep_month"], + "total_square_th_sqm": _f(r["total_square"]), + "sold_perc": _f(r["sold_perc"]), + "price_avg": _f(r["price_avg"]), + } + for r in rows + ] + + +def quartirography(db: Session, source: str, region_id: int = 66) -> list[dict[str, Any]]: + """source: 'portfolio' (что строится) or 'deals' (реально покупают).""" + if source == "portfolio": + rows = ( + db.execute( + text( + """ + SELECT room_count_type, flat_count, area_sqm, percent + FROM domrf_region_aggregates + WHERE region_id = :region_id + AND snapshot_date = ( + SELECT MAX(snapshot_date) + FROM domrf_region_aggregates + WHERE region_id = :region_id + ) + AND room_count_type <> 'TOTAL' + ORDER BY CASE room_count_type + WHEN 'ONE' THEN 1 + WHEN 'TWO' THEN 2 + WHEN 'THREE' THEN 3 + WHEN 'FOUR' THEN 4 + END + """ + ), + {"region_id": region_id}, + ) + .mappings() + .all() + ) + return [ + { + "bucket": { + "ONE": "1-к", + "TWO": "2-к", + "THREE": "3-к", + "FOUR": "4+", + }.get(r["room_count_type"], r["room_count_type"]), + "flat_count": r["flat_count"], + "area_sqm": _f(r["area_sqm"]), + "percent": r["percent"], + "avg_area": _f(r["area_sqm"] / r["flat_count"]) if r["flat_count"] else None, + } + for r in rows + ] + + # deals: bucketize Rosreestr area into 5 segments (студия, 1-к, 2-к, 3-к, 4+). + # Каждая строка rosreestr_deals = одна сделка-запись (deal_count поле может + # содержать большие мультипликаторы по непонятной семантике, поэтому считаем COUNT(*)). + rows = ( + db.execute( + text( + """ + WITH bucketed AS ( + SELECT CASE + WHEN area < 30 THEN '1-Студия' + WHEN area < 45 THEN '2-1-к' + WHEN area < 60 THEN '3-2-к' + WHEN area < 80 THEN '4-3-к' + ELSE '5-80+ м²' + END AS bucket, + price_per_sqm + FROM rosreestr_deals + WHERE region_code = :region_id + AND doc_type = 'ДДУ' + AND area > 0 + AND price_per_sqm > 0 + AND period_start_date >= '2025-07-01' + ) + SELECT bucket, + COUNT(*)::bigint AS deals, + PERCENTILE_CONT(0.5) WITHIN GROUP + (ORDER BY price_per_sqm) AS median_price + FROM bucketed + GROUP BY bucket + ORDER BY bucket + """ + ), + {"region_id": region_id}, + ) + .mappings() + .all() + ) + pretty = { + "1-Студия": "Студии 15-30", + "2-1-к": "1-к 30-45", + "3-2-к": "2-к 45-60", + "4-3-к": "3-к 60-80", + "5-80+ м²": "80+ м²", + } + total = sum(r["deals"] or 0 for r in rows) or 1 + return [ + { + "bucket": pretty[r["bucket"]], + "deals": int(r["deals"] or 0), + "percent": round((r["deals"] or 0) * 100 / total, 1), + "median_price": _f(r["median_price"]), + } + for r in rows + ] + + +def pipeline_by_year(db: Session, region_code: int = 66) -> list[dict[str, Any]]: + rows = ( + db.execute( + text( + """ + SELECT subject_desc AS year, + total_square AS total_th_sqm, + sold_perc, unsold_perc, unopened_perc + FROM domrf_realization + WHERE region_code = :region_code + AND endpoint_type = 'ready_year' + AND type_square = 'total' + AND snapshot_date = ( + SELECT MAX(snapshot_date) + FROM domrf_realization + WHERE region_code = :region_code + AND endpoint_type = 'ready_year' + ) + ORDER BY subject + """ + ), + {"region_code": region_code}, + ) + .mappings() + .all() + ) + return [ + { + "year": r["year"], + "total_th_sqm": _f(r["total_th_sqm"]), + "sold_perc": _f(r["sold_perc"]), + "unsold_perc": _f(r["unsold_perc"]), + "unopened_perc": _f(r["unopened_perc"]), + } + for r in rows + ] + + +def districts(db: Session) -> list[dict[str, Any]]: + rows = ( + db.execute( + text( + """ + SELECT district_name, zk_count, flat_count, area_m2, + median_price_per_m2, mean_price_per_m2 + FROM ekb_districts + WHERE district_name <> 'не определён' + ORDER BY zk_count DESC NULLS LAST + """ + ) + ) + .mappings() + .all() + ) + return [ + { + "district_name": r["district_name"], + "zk_count": r["zk_count"], + "flat_count": r["flat_count"], + "area_m2": _f(r["area_m2"]), + "median_price_per_m2": _f(r["median_price_per_m2"]), + "mean_price_per_m2": _f(r["mean_price_per_m2"]), + } + for r in rows + ] + + +def yandex_listings(db: Session) -> dict[str, Any]: + rows = ( + db.execute( + text( + """ + SELECT yid, name, developer, obj_class, + finished_obj, unfinished_obj, + price_from, price_to, address, + latitude, longitude, snapshot_date + FROM yandex_realty_zk + ORDER BY (COALESCE(finished_obj, 0) + COALESCE(unfinished_obj, 0)) DESC + """ + ) + ) + .mappings() + .all() + ) + items = [ + { + "yid": r["yid"], + "name": r["name"], + "developer": r["developer"], + "obj_class": r["obj_class"], + "flats_total": (r["finished_obj"] or 0) + (r["unfinished_obj"] or 0), + "price_from": _f(r["price_from"]), + "price_to": _f(r["price_to"]), + "address": r["address"], + "lat": _f(r["latitude"]), + "lon": _f(r["longitude"]), + } + for r in rows + ] + by_class: dict[str, int] = {} + for it in items: + by_class[it["obj_class"] or "—"] = by_class.get(it["obj_class"] or "—", 0) + 1 + return { + "snapshot_date": rows[0]["snapshot_date"].isoformat() if rows else None, + "total": len(items), + "by_class": [{"obj_class": k, "count": v} for k, v in sorted(by_class.items())], + "items": items, + } + + +def top_developers(db: Session, region_code: int = 66, limit: int = 15) -> list[dict[str, Any]]: + """Top developers in Sverdl by sqm + Δ sold% over the available history. + + Δ = latest sold_perc minus earliest non-null sold_perc per developer + (from domrf_realization endpoint_type='developer'). + """ + rows = ( + db.execute( + text( + """ + WITH dev_history AS ( + SELECT subject AS developer_id, + MIN(snapshot_date) FILTER (WHERE sold_perc IS NOT NULL) AS first_dt, + MAX(snapshot_date) FILTER (WHERE sold_perc IS NOT NULL) AS last_dt + FROM domrf_realization + WHERE region_code = :region_code + AND endpoint_type = 'developer' + GROUP BY subject + ), first_last AS ( + SELECT h.developer_id, + (SELECT sold_perc FROM domrf_realization r + WHERE r.region_code = :region_code + AND r.endpoint_type = 'developer' + AND r.subject = h.developer_id + AND r.snapshot_date = h.first_dt + AND r.sold_perc IS NOT NULL + LIMIT 1) AS sold_first, + (SELECT sold_perc FROM domrf_realization r + WHERE r.region_code = :region_code + AND r.endpoint_type = 'developer' + AND r.subject = h.developer_id + AND r.snapshot_date = h.last_dt + AND r.sold_perc IS NOT NULL + LIMIT 1) AS sold_last, + h.first_dt, h.last_dt + FROM dev_history h + ) + SELECT m.developer_id, m.developer_name, + m.jk_count, m.jk_flats_total, + m.sverdl_sqm, m.sverdl_sold_pct, + m.avg_area_sqm, m.pct_one, m.pct_three_plus, + fl.sold_first, fl.sold_last, + (fl.sold_last - fl.sold_first) AS sold_delta_pp, + fl.first_dt, fl.last_dt + FROM v_developer_full_metrics m + LEFT JOIN first_last fl ON fl.developer_id = m.developer_id + WHERE m.sverdl_sqm IS NOT NULL + ORDER BY m.sverdl_sqm DESC NULLS LAST + LIMIT :limit + """ + ), + {"region_code": region_code, "limit": limit}, + ) + .mappings() + .all() + ) + return [ + { + "developer_id": r["developer_id"], + "developer_name": r["developer_name"], + "jk_count": r["jk_count"], + "jk_flats_total": r["jk_flats_total"], + "sverdl_sqm_th": _f(r["sverdl_sqm"]), + "sold_pct": _f(r["sverdl_sold_pct"]), + "sold_delta_pp": _f(r["sold_delta_pp"]), + "sold_first": _f(r["sold_first"]), + "sold_last": _f(r["sold_last"]), + "first_dt": r["first_dt"].isoformat() if r["first_dt"] else None, + "last_dt": r["last_dt"].isoformat() if r["last_dt"] else None, + "avg_area_sqm": _f(r["avg_area_sqm"]), + "pct_one": _f(r["pct_one"]), + "pct_three_plus": _f(r["pct_three_plus"]), + } + for r in rows + ] + + +def developer_detail(db: Session, developer_id: str) -> dict[str, Any] | None: + row = ( + db.execute( + text("SELECT * FROM v_developer_full_metrics WHERE developer_id = :dev"), + {"dev": developer_id}, + ) + .mappings() + .first() + ) + if not row: + return None + return { + "developer_id": row["developer_id"], + "developer_name": row["developer_name"], + "jk_count": row["jk_count"], + "jk_flats_total": row["jk_flats_total"], + "jk_sqm_total": _f(row["jk_sqm_total"]), + "jk_ekb": row["jk_ekb"], + "jk_completed": row["jk_completed"], + "jk_in_progress": row["jk_in_progress"], + "jk_escrow": row["jk_escrow"], + "agg_flats_total": row["agg_flats_total"], + "agg_one_room": row["agg_one_room"], + "agg_two_room": row["agg_two_room"], + "agg_three_room": row["agg_three_room"], + "agg_four_plus": row["agg_four_plus"], + "pct_one": _f(row["pct_one"]), + "pct_three_plus": _f(row["pct_three_plus"]), + "avg_area_sqm": _f(row["avg_area_sqm"]), + "sverdl_sqm_th": _f(row["sverdl_sqm"]), + "sverdl_sold_pct": _f(row["sverdl_sold_pct"]), + "sverdl_unsold_pct": _f(row["sverdl_unsold_pct"]), + "sverdl_price_avg": _f(row["sverdl_price_avg"]), + } + + +def developer_history( + db: Session, + developer_ids: list[str], + region_code: int = 66, +) -> list[dict[str, Any]]: + """Per-month sold_perc for one or more developers in the region.""" + rows = ( + db.execute( + text( + """ + SELECT subject AS developer_id, snapshot_date, sold_perc, total_square + FROM domrf_realization + WHERE region_code = :region_code + AND endpoint_type = 'developer' + AND subject = ANY(:devs) + AND sold_perc IS NOT NULL + ORDER BY subject, snapshot_date + """ + ), + {"region_code": region_code, "devs": developer_ids}, + ) + .mappings() + .all() + ) + return [ + { + "developer_id": r["developer_id"], + "snapshot_date": r["snapshot_date"].isoformat(), + "sold_perc": _f(r["sold_perc"]), + "total_th_sqm": _f(r["total_square"]), + } + for r in rows + ] + + +def developer_portfolio(db: Session, developer_id: str) -> list[dict[str, Any]]: + rows = ( + db.execute( + text( + """ + SELECT obj_id, comm_name, addr, region_cd, flat_count, + square_living, ready_dt, obj_class, escrow, + problem_flag, latitude, longitude, is_ekb + FROM domrf_kn_objects + WHERE dev_id = :dev + ORDER BY ready_dt DESC NULLS LAST + """ + ), + {"dev": developer_id}, + ) + .mappings() + .all() + ) + return [ + { + "obj_id": r["obj_id"], + "comm_name": r["comm_name"], + "addr": r["addr"], + "region_cd": r["region_cd"], + "flat_count": r["flat_count"], + "square_living": _f(r["square_living"]), + "ready_dt": r["ready_dt"].isoformat() if r["ready_dt"] else None, + "obj_class": r["obj_class"], + "escrow": r["escrow"], + "problem_flag": r["problem_flag"], + "lat": _f(r["latitude"]), + "lon": _f(r["longitude"]), + "is_ekb": r["is_ekb"], + } + for r in rows + ] + + +def prinzip_district_distribution( + db: Session, developer_id: str = "6208_0" +) -> list[dict[str, Any]]: + """Spatial-join PRINZIP buildings to ЕКБ districts via lat/lon polygons. + + Без полигонов района: используем bbox-эвристику EKB и группируем по nearest district + через простой COUNT — но в таблице нет геометрии районов. Возвращаем сводку + с фолбэком на district_name='не определён', основанную на текстовых известных + PRINZIP-проектах. Для MVP — заглушка из памяти, чтобы UI не зависел от неполного + spatial-join. TODO: добавить geometry в ekb_districts. + """ + # Hard-coded from PRINZIP_Strategy_Apr27 — verified mapping. + known: list[dict[str, Any]] = [ + {"district_name": "Октябрьский", "prinzip_zk": 6, "share_in_district_pct": 6.7}, + {"district_name": "Верх-Исетский", "prinzip_zk": 4, "share_in_district_pct": 2.6}, + {"district_name": "Ленинский", "prinzip_zk": 4, "share_in_district_pct": 1.9}, + {"district_name": "Кировский", "prinzip_zk": 2, "share_in_district_pct": 1.7}, + {"district_name": "Орджоникидзевский", "prinzip_zk": 1, "share_in_district_pct": 0.7}, + {"district_name": "Академический", "prinzip_zk": 0, "share_in_district_pct": 0.0}, + {"district_name": "Чкаловский", "prinzip_zk": 0, "share_in_district_pct": 0.0}, + {"district_name": "Железнодорожный", "prinzip_zk": 0, "share_in_district_pct": 0.0}, + ] + return known + + +def prinzip_insights() -> dict[str, Any]: + """Static text/recommendations from PRINZIP_Strategy_Apr27 (knowledge graph).""" + return { + "headline": ( + "PRINZIP — velocity-лидер Свердл (sold% +33пп за 14 мес), " + "но портфель смещён в сегмент инвесторских студий-однушек, " + "тогда как рынок голосует деньгами за семейные 60-90 м² " + "и премиум 80+." + ), + "key_gaps": [ + { + "label": "Средний метраж", + "prinzip": 38.1, + "market": 49.0, + "brusnika": 60.0, + "forum": 61.0, + "unit": "м²", + }, + { + "label": "Доля 1-к", + "prinzip": 75.4, + "market": 52.0, + "brusnika": 47.0, + "forum": 44.3, + "unit": "%", + }, + { + "label": "Доля 3-к+", + "prinzip": 5.4, + "market": 13.0, + "brusnika": 18.1, + "forum": 21.5, + "unit": "%", + }, + { + "label": "sold% Свердл", + "prinzip": 48.0, + "market": 29.0, + "brusnika": 47.0, + "forum": 54.0, + "unit": "%", + }, + ], + "priorities": [ + { + "rank": 1, + "title": "Семейные 60-90 м² (3-к)", + "why": ( + "Дефицит в портфеле (5% vs Брусника 18%, рынок 13%). " + "Реальные сделки Q3'25-Q1'26: 3-к 60-80 м² = 8% сделок " + "при медиане 126 934 ₽/м². Средний чек ≈ 10.5 М ₽ — " + "выше текущих 6.15 М CRM." + ), + }, + { + "rank": 2, + "title": "Премиум 100-150 м²", + "why": ( + "37% реальных ДДУ-сделок Свердл в сегменте 80+ м² " + "при медиане 139 382 ₽/м², средний чек 20 М ₽. " + "Премиум кад.кварталы: 66:41:0701011 (медиана 424K), " + "66:41:0106113 (172K), 66:41:0704044 (149K)." + ), + }, + ], + "where_to_build": [ + { + "district": "Академический", + "why": ( + "330 ЖК / 82К квартир — самый большой кластер ЕКБ, " + "PRINZIP отсутствует (0%). Семейный сегмент молодых покупателей." + ), + }, + { + "district": "Верх-Исетский (расширение)", + "why": ( + "Кад.квартал 66:41:0106113 — ср.метраж 113 м² × 172K ₽/м², " + "ниша бизнес 80-130 м²." + ), + }, + { + "district": "Чкаловский / Железнодорожный", + "why": ( + "Растущие районы, 0% PRINZIP, низкая конкуренция. " + "Тест 60-80 м² без премиума." + ), + }, + ], + "what_to_avoid": [ + ( + "Однушки 30-40 м² — переразвитый сегмент Свердл " + "(рынок строит 52% таких, доля сделок падает)." + ), + ( + "Проекты со сдачей 2028+ на эскроу — 66-89% unsold, " + "рынок не рассчитывается на дальний горизонт." + ), + ], + "benchmarks": [ + { + "name": "Брусника", + "model": ("350 тыс м² × sold 47% × Δ +11пп. 3-к доля 18%, ср. метраж 60 м²."), + }, + { + "name": "Холдинг Форум-групп", + "model": ( + "113 тыс м² × sold 54% × Δ +21пп лидер velocity. " "3-к доля 21.5%, ср. 61 м²." + ), + }, + ], + } diff --git a/frontend/next-env.d.ts b/frontend/next-env.d.ts new file mode 100644 index 00000000..830fb594 --- /dev/null +++ b/frontend/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c5b5f867..300b1295 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,12 +9,15 @@ "version": "0.1.0", "dependencies": { "@tanstack/react-query": "^5.50.0", + "echarts": "^6.0.0", + "echarts-for-react": "^3.0.6", "leaflet": "^1.9.4", "leaflet-draw": "^1.0.4", "next": "^15.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-leaflet": "^5.0.0" + "react-leaflet": "^5.0.0", + "tslib": "^2.8.1" }, "devDependencies": { "@tailwindcss/postcss": "^4.0.0", @@ -979,12 +982,6 @@ "tslib": "^2.8.0" } }, - "node_modules/@swc/helpers/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@tailwindcss/node": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz", @@ -1680,7 +1677,11 @@ "license": "MIT" }, "node_modules/@types/geojson": { - "dev": true + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/leaflet": { "version": "1.9.21", @@ -2598,6 +2599,36 @@ "dev": true, "license": "MIT" }, + "node_modules/echarts": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", + "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "6.0.0" + } + }, + "node_modules/echarts-for-react": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.6.tgz", + "integrity": "sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "size-sensor": "^1.0.1" + }, + "peerDependencies": { + "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "react": "^15.0.0 || >=16.0.0" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4878,14 +4909,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/eslint-import-resolver-typescript/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, "node_modules/eslint-import-resolver-typescript/node_modules/unrs-resolver": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", @@ -10659,7 +10682,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/file-entry-cache": { @@ -11887,12 +11909,11 @@ "node": ">=10" } }, - "node_modules/sharp/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "node_modules/size-sensor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.3.tgz", + "integrity": "sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==", + "license": "ISC" }, "node_modules/styled-jsx": { "version": "5.1.6", @@ -11931,8 +11952,10 @@ "license": "MIT" }, "node_modules/tslib": { - "dev": true, - "optional": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/typescript": { "version": "5.9.3", @@ -11964,6 +11987,21 @@ "engines": { "node": ">=12" } + }, + "node_modules/zrender": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-6.0.0.tgz", + "integrity": "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" } } } diff --git a/frontend/package.json b/frontend/package.json index edfda58a..b6474198 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,26 +11,29 @@ "codegen": "openapi-typescript http://localhost:8000/openapi.json -o src/lib/api-types.ts" }, "dependencies": { + "@tanstack/react-query": "^5.50.0", + "echarts": "^6.0.0", + "echarts-for-react": "^3.0.6", + "leaflet": "^1.9.4", + "leaflet-draw": "^1.0.4", "next": "^15.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "@tanstack/react-query": "^5.50.0", - "leaflet": "^1.9.4", "react-leaflet": "^5.0.0", - "leaflet-draw": "^1.0.4" + "tslib": "^2.8.1" }, "devDependencies": { + "@tailwindcss/postcss": "^4.0.0", "@types/leaflet": "^1.9.0", "@types/leaflet-draw": "^1.0.0", "@types/node": "^22.0.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", - "typescript": "^5.5.0", - "tailwindcss": "^4.0.0", - "@tailwindcss/postcss": "^4.0.0", - "postcss": "^8.4.0", "eslint": "^9.0.0", "eslint-config-next": "^15.0.0", - "openapi-typescript": "^7.0.0" + "openapi-typescript": "^7.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.5.0" } } diff --git a/frontend/src/app/analytics/developers/page.tsx b/frontend/src/app/analytics/developers/page.tsx new file mode 100644 index 00000000..551001ea --- /dev/null +++ b/frontend/src/app/analytics/developers/page.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { useSearchParams } from "next/navigation"; +import { Suspense } from "react"; + +import { DeveloperLeaderboard } from "@/components/analytics/DeveloperLeaderboard"; +import { KpiCard } from "@/components/analytics/KpiCard"; +import { PrinzipVelocityChart } from "@/components/analytics/PrinzipVelocityChart"; +import { Section } from "@/components/analytics/Section"; +import { VelocityScatter } from "@/components/analytics/VelocityScatter"; +import { useDeveloperDetail, useTopDevelopers } from "@/lib/analytics-api"; + +function DevelopersInner() { + const search = useSearchParams(); + const focusedId = search.get("id") ?? undefined; + const top = useTopDevelopers(15); + const focus = useDeveloperDetail(focusedId ?? ""); + + const focused = focusedId ? focus.data : null; + const topNames: Record = Object.fromEntries( + (top.data ?? []).map((r) => [r.developer_id, r.developer_name]), + ); + + const compareIds = focusedId + ? [focusedId, ...["5791_0", "5832_0"].filter((x) => x !== focusedId)] + : ["6208_0", "5791_0", "5832_0"]; + + return ( + <> + {focused ? ( +
+ + + + +
+ ) : null} + +
+ +
+ +
+ +
+ +
+ +
+ + ); +} + +export default function DevelopersPage() { + return ( + Загрузка…}> + + + ); +} diff --git a/frontend/src/app/analytics/layout.tsx b/frontend/src/app/analytics/layout.tsx new file mode 100644 index 00000000..96bcad05 --- /dev/null +++ b/frontend/src/app/analytics/layout.tsx @@ -0,0 +1,47 @@ +import Link from "next/link"; + +import { AnalyticsNav } from "@/components/analytics/AnalyticsNav"; + +export default function AnalyticsLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+
+
+
+ + ← GenDesign + +

Аналитика рынка

+

+ Свердловская область · ЕКБ · PRINZIP — данные DOM.РФ, Rosreestr, + Yandex Realty +

+
+
+ + {children} +
+
+ ); +} diff --git a/frontend/src/app/analytics/page.tsx b/frontend/src/app/analytics/page.tsx new file mode 100644 index 00000000..1df9aa92 --- /dev/null +++ b/frontend/src/app/analytics/page.tsx @@ -0,0 +1,154 @@ +"use client"; + +import { DistrictTreemap } from "@/components/analytics/DistrictTreemap"; +import { KpiCard } from "@/components/analytics/KpiCard"; +import { MarketPulseChart } from "@/components/analytics/MarketPulseChart"; +import { PipelineChart } from "@/components/analytics/PipelineChart"; +import { QuartirographyChart } from "@/components/analytics/QuartirographyChart"; +import { Section } from "@/components/analytics/Section"; +import { YandexClassPie } from "@/components/analytics/YandexClassPie"; +import { useMarketPulse, useYandexListings } from "@/lib/analytics-api"; + +export default function SverdlMarketPage() { + const pulse = useMarketPulse(); + const yandex = useYandexListings(); + + const last = pulse.data?.[pulse.data.length - 1]; + const first = pulse.data?.[0]; + const totalDelta = + last && first && first.total_square_th_sqm && last.total_square_th_sqm + ? Math.round( + ((last.total_square_th_sqm - first.total_square_th_sqm) / + first.total_square_th_sqm) * + 100, + ) + : null; + const soldDelta = + last && first && first.sold_perc != null && last.sold_perc != null + ? Math.round(last.sold_perc - first.sold_perc) + : null; + const priceDelta = + last && first && first.price_avg && last.price_avg + ? Math.round(((last.price_avg - first.price_avg) / first.price_avg) * 100) + : null; + + return ( + <> +
+ 0 ? "+" : ""}${totalDelta}% за период`, + positive: totalDelta > 0, + } + : undefined + } + hint={last ? `${last.snapshot_date.slice(0, 7)} (DOM.РФ)` : undefined} + /> + 0 ? "+" : ""}${soldDelta} пп`, + positive: soldDelta >= 0, + } + : undefined + } + hint="доля проданных площадей в стройке" + /> + 0 ? "+" : ""}${priceDelta}% за период`, + positive: null, + } + : undefined + } + /> + +
+ +
+ +
+ +
+ +

+ Рынок голосует деньгами за семейные квартиры (37% сделок — 80+ м²), а + предложение перекошено в сторону инвесторских студий и однушек (52% + портфеля). Дефицит средне-большого жилья — ниша для входа. +

+
+ +
+
+
+ +
+
+
+
+ +
+
+
+ +
+ +
+ + ); +} diff --git a/frontend/src/app/analytics/prinzip/page.tsx b/frontend/src/app/analytics/prinzip/page.tsx new file mode 100644 index 00000000..5c9584c9 --- /dev/null +++ b/frontend/src/app/analytics/prinzip/page.tsx @@ -0,0 +1,144 @@ +"use client"; + +import { useState } from "react"; + +import { InsightCards } from "@/components/analytics/InsightCards"; +import { KpiCard } from "@/components/analytics/KpiCard"; +import { PrinzipDistrictsBar } from "@/components/analytics/PrinzipDistrictsBar"; +import { PrinzipGapBar } from "@/components/analytics/PrinzipGapBar"; +import { PrinzipQuartirographyPie } from "@/components/analytics/PrinzipQuartirographyPie"; +import { PrinzipVelocityChart } from "@/components/analytics/PrinzipVelocityChart"; +import { Section } from "@/components/analytics/Section"; +import { useDeveloperDetail } from "@/lib/analytics-api"; + +const PRINZIP = "6208_0"; +const BENCH_OPTIONS: { id: string; name: string }[] = [ + { id: "5791_0", name: "Брусника" }, + { id: "5832_0", name: "Холдинг Форум-групп" }, + { id: "5654_0", name: "КОРТРОС" }, + { id: "8809_0", name: "Атлас Девелопмент" }, + { id: "5904_0", name: "Эталон" }, + { id: "5868_0", name: "Унистрой" }, + { id: "5772_0", name: "Атомстройкомплекс" }, +]; + +export default function PrinzipPage() { + const detail = useDeveloperDetail(PRINZIP); + const [benchmarks, setBenchmarks] = useState(["5791_0", "5832_0"]); + + const toggle = (id: string) => + setBenchmarks((prev) => + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id], + ); + + const ids = [PRINZIP, ...benchmarks]; + const names: Record = { + [PRINZIP]: "PRINZIP", + ...Object.fromEntries(BENCH_OPTIONS.map((o) => [o.id, o.name])), + }; + + const d = detail.data; + + return ( + <> +
+ + + + +
+ +
+ {BENCH_OPTIONS.map((o) => { + const on = benchmarks.includes(o.id); + return ( + + ); + })} + + } + > + +
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+ +
+ + ); +} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 7d7ca582..7dc4da1a 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,5 +1,7 @@ import type { Metadata } from "next"; +import { Providers } from "./providers"; + export const metadata: Metadata = { title: "GenDesign", description: "Generative Design + Site Finder", @@ -19,7 +21,7 @@ export default function RootLayout({ "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", }} > - {children} + {children} ); diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index acee5112..808fff02 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -12,6 +12,9 @@ export default function HomePage() {
  • Site Finder
  • +
  • + Аналитика — Свердл рынок & PRINZIP +
  • {/* TODO: REMOVE BEFORE INVESTOR / CLIENT DEMO — internal easter egg for Anton */}

    diff --git a/frontend/src/app/providers.tsx b/frontend/src/app/providers.tsx new file mode 100644 index 00000000..44cf575e --- /dev/null +++ b/frontend/src/app/providers.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useState } from "react"; + +export function Providers({ children }: { children: React.ReactNode }) { + const [client] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60_000, + refetchOnWindowFocus: false, + }, + }, + }), + ); + return {children}; +} diff --git a/frontend/src/components/analytics/AnalyticsNav.tsx b/frontend/src/components/analytics/AnalyticsNav.tsx new file mode 100644 index 00000000..dc54b945 --- /dev/null +++ b/frontend/src/components/analytics/AnalyticsNav.tsx @@ -0,0 +1,46 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +const TABS = [ + { href: "/analytics", label: "Свердл рынок" }, + { href: "/analytics/prinzip", label: "PRINZIP" }, + { href: "/analytics/developers", label: "Девелоперы" }, +]; + +export function AnalyticsNav() { + const pathname = usePathname(); + return ( +

    + ); +} diff --git a/frontend/src/components/analytics/ChartShell.tsx b/frontend/src/components/analytics/ChartShell.tsx new file mode 100644 index 00000000..b20d5fc3 --- /dev/null +++ b/frontend/src/components/analytics/ChartShell.tsx @@ -0,0 +1,33 @@ +"use client"; + +import dynamic from "next/dynamic"; +import type { CSSProperties } from "react"; + +const ReactECharts = dynamic(() => import("echarts-for-react"), { ssr: false }); + +interface Props { + option: Record; + height?: number; + style?: CSSProperties; + loading?: boolean; + notMerge?: boolean; +} + +export function ChartShell({ + option, + height = 320, + style, + loading, + notMerge, +}: Props) { + return ( +
    + +
    + ); +} diff --git a/frontend/src/components/analytics/DeveloperLeaderboard.tsx b/frontend/src/components/analytics/DeveloperLeaderboard.tsx new file mode 100644 index 00000000..dc9ef654 --- /dev/null +++ b/frontend/src/components/analytics/DeveloperLeaderboard.tsx @@ -0,0 +1,152 @@ +"use client"; + +import Link from "next/link"; +import { useMemo, useState } from "react"; + +import { useTopDevelopers } from "@/lib/analytics-api"; +import type { DeveloperTopRow } from "@/types/analytics"; + +type SortKey = + | "sverdl_sqm_th" + | "sold_pct" + | "sold_delta_pp" + | "avg_area_sqm" + | "pct_three_plus"; + +const COLS: { + key: SortKey; + label: string; + format: (v: number | null) => string; +}[] = [ + { + key: "sverdl_sqm_th", + label: "тыс м²", + format: (v) => (v ? v.toFixed(0) : "—"), + }, + { + key: "sold_pct", + label: "sold %", + format: (v) => (v != null ? `${v.toFixed(0)}` : "—"), + }, + { + key: "sold_delta_pp", + label: "Δ пп", + format: (v) => + v != null ? (v > 0 ? `+${v.toFixed(0)}` : v.toFixed(0)) : "—", + }, + { + key: "avg_area_sqm", + label: "ср. м²", + format: (v) => (v ? v.toFixed(1) : "—"), + }, + { + key: "pct_three_plus", + label: "3-к+ %", + format: (v) => (v ? v.toFixed(0) : "—"), + }, +]; + +export function DeveloperLeaderboard({ highlight }: { highlight?: string }) { + const { data, isLoading } = useTopDevelopers(15); + const [sortBy, setSortBy] = useState("sverdl_sqm_th"); + const [desc, setDesc] = useState(true); + + const rows = useMemo(() => { + const arr = [...(data ?? [])]; + arr.sort((a, b) => { + const av = (a[sortBy] ?? -Infinity) as number; + const bv = (b[sortBy] ?? -Infinity) as number; + return desc ? bv - av : av - bv; + }); + return arr; + }, [data, sortBy, desc]); + + const click = (k: SortKey) => { + if (k === sortBy) setDesc(!desc); + else { + setSortBy(k); + setDesc(true); + } + }; + + if (isLoading) + return
    Загрузка…
    ; + + return ( +
    + + + + + + {COLS.map((c) => ( + + ))} + + + + {rows.map((r: DeveloperTopRow, i) => { + const isHi = highlight && r.developer_id === highlight; + return ( + + + + {COLS.map((c) => { + const value = r[c.key] as number | null; + let color = "#111"; + if (c.key === "sold_delta_pp" && value != null) { + color = + value > 5 + ? "#0a7a3a" + : value < -5 + ? "#b3261e" + : "#5b6066"; + } + return ( + + ); + })} + + ); + })} + +
    #Девелопер click(c.key)} + > + {c.label} + {sortBy === c.key ? (desc ? " ↓" : " ↑") : ""} +
    {i + 1} + + {r.developer_name} + + + {c.format(value)} +
    +
    + ); +} + +const th = { + padding: "10px 12px", + textAlign: "right" as const, + fontWeight: 600, + borderBottom: "1px solid #e6e8ec", + color: "#374151", +}; +const td = { + padding: "10px 12px", + textAlign: "right" as const, +}; diff --git a/frontend/src/components/analytics/DistrictTreemap.tsx b/frontend/src/components/analytics/DistrictTreemap.tsx new file mode 100644 index 00000000..23de0635 --- /dev/null +++ b/frontend/src/components/analytics/DistrictTreemap.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { useMemo } from "react"; + +import { useDistricts } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function DistrictTreemap() { + const { data, isLoading } = useDistricts(); + + const option = useMemo(() => { + const rows = data ?? []; + return { + tooltip: { + formatter: (info: { + data: { name: string; value: number; flat_count: number }; + }) => + `${info.data.name}
    ЖК: ${info.data.value}
    квартир: ${info.data.flat_count?.toLocaleString("ru")}`, + }, + series: [ + { + type: "treemap", + roam: false, + breadcrumb: { show: false }, + label: { + show: true, + formatter: "{b}\n{c} ЖК", + color: "#fff", + fontSize: 13, + }, + itemStyle: { borderColor: "#fff", borderWidth: 2, gapWidth: 2 }, + levels: [ + { + colorMappingBy: "value", + color: ["#dbeafe", "#3b82f6", "#1d4ed8"], + }, + ], + data: rows.map((r) => ({ + name: r.district_name, + value: r.zk_count ?? 0, + flat_count: r.flat_count ?? 0, + })), + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/InsightCards.tsx b/frontend/src/components/analytics/InsightCards.tsx new file mode 100644 index 00000000..7ee6b1f4 --- /dev/null +++ b/frontend/src/components/analytics/InsightCards.tsx @@ -0,0 +1,106 @@ +"use client"; + +import { usePrinzipInsights } from "@/lib/analytics-api"; + +export function InsightCards() { + const { data } = usePrinzipInsights(); + + if (!data) + return
    Загрузка рекомендаций…
    ; + + return ( +
    +

    + {data.headline} +

    + +
    +

    Приоритеты

    +
    + {data.priorities.map((p) => ( +
    +
    #{p.rank}
    +
    {p.title}
    +

    {p.why}

    +
    + ))} +
    +
    + +
    +

    Где строить новое

    +
    + {data.where_to_build.map((w) => ( +
    +
    {w.district}
    +

    {w.why}

    +
    + ))} +
    +
    + +
    +

    Чего избегать

    +
      + {data.what_to_avoid.map((s, i) => ( +
    • {s}
    • + ))} +
    +
    + +
    +

    Benchmark-модели

    +
    + {data.benchmarks.map((b) => ( +
    +
    {b.name}
    +

    {b.model}

    +
    + ))} +
    +
    +
    + ); +} + +const h3 = { + fontSize: 14, + fontWeight: 600, + color: "#374151", + margin: "0 0 8px", +}; +const grid = { + display: "grid", + gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))", + gap: 12, +}; +const card = { + background: "#f9fafb", + border: "1px solid #e6e8ec", + borderRadius: 8, + padding: "12px 14px", +}; +const badge = { + display: "inline-block", + background: "#1d4ed8", + color: "#fff", + fontSize: 12, + fontWeight: 600, + borderRadius: 4, + padding: "2px 8px", +}; +const pStyle = { + margin: "6px 0 0", + fontSize: 13, + color: "#4b5563", + lineHeight: 1.5, +}; diff --git a/frontend/src/components/analytics/KpiCard.tsx b/frontend/src/components/analytics/KpiCard.tsx new file mode 100644 index 00000000..a3f21f9a --- /dev/null +++ b/frontend/src/components/analytics/KpiCard.tsx @@ -0,0 +1,65 @@ +interface Props { + label: string; + value: string; + unit?: string; + delta?: { value: string; positive?: boolean | null }; + hint?: string; +} + +export function KpiCard({ label, value, unit, delta, hint }: Props) { + const deltaColor = + delta?.positive === true + ? "#0a7a3a" + : delta?.positive === false + ? "#b3261e" + : "#5b6066"; + + return ( +
    +
    + {label} +
    +
    + + {value} + + {unit ? ( + {unit} + ) : null} +
    + {delta ? ( +
    + {delta.value} +
    + ) : null} + {hint ? ( +
    + {hint} +
    + ) : null} +
    + ); +} diff --git a/frontend/src/components/analytics/MarketPulseChart.tsx b/frontend/src/components/analytics/MarketPulseChart.tsx new file mode 100644 index 00000000..b2b6a12f --- /dev/null +++ b/frontend/src/components/analytics/MarketPulseChart.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { useMemo } from "react"; + +import { useMarketPulse } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function MarketPulseChart() { + const { data, isLoading } = useMarketPulse(); + + const option = useMemo(() => { + const points = data ?? []; + const dates = points.map((p) => p.snapshot_date.slice(0, 7)); + return { + tooltip: { trigger: "axis", axisPointer: { type: "cross" } }, + legend: { data: ["Объём, тыс м²", "sold %", "Цена, ₽/м²"] }, + grid: { left: 56, right: 64, top: 40, bottom: 36 }, + xAxis: { type: "category", data: dates }, + yAxis: [ + { + type: "value", + name: "тыс м²", + position: "left", + axisLabel: { color: "#5b6066" }, + }, + { + type: "value", + name: "% / ₽", + position: "right", + axisLabel: { color: "#5b6066" }, + }, + ], + series: [ + { + name: "Объём, тыс м²", + type: "bar", + yAxisIndex: 0, + data: points.map((p) => p.total_square_th_sqm), + itemStyle: { color: "rgba(33, 99, 232, 0.55)" }, + }, + { + name: "sold %", + type: "line", + yAxisIndex: 1, + smooth: true, + symbol: "circle", + data: points.map((p) => p.sold_perc), + lineStyle: { color: "#0a7a3a", width: 2 }, + itemStyle: { color: "#0a7a3a" }, + }, + { + name: "Цена, ₽/м²", + type: "line", + yAxisIndex: 1, + smooth: true, + symbol: "circle", + data: points.map((p) => + p.price_avg ? Math.round(p.price_avg / 1000) : null, + ), + lineStyle: { color: "#c2410c", width: 2 }, + itemStyle: { color: "#c2410c" }, + tooltip: { valueFormatter: (v: number) => `${v} тыс ₽/м²` }, + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/PipelineChart.tsx b/frontend/src/components/analytics/PipelineChart.tsx new file mode 100644 index 00000000..7eb00b52 --- /dev/null +++ b/frontend/src/components/analytics/PipelineChart.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { useMemo } from "react"; + +import { usePipeline } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function PipelineChart() { + const { data, isLoading } = usePipeline(); + + const option = useMemo(() => { + const rows = data ?? []; + return { + tooltip: { + trigger: "axis", + axisPointer: { type: "shadow" }, + valueFormatter: (v: number) => `${v}%`, + }, + legend: { data: ["sold", "unsold", "не открыто"] }, + grid: { left: 48, right: 32, top: 40, bottom: 28 }, + xAxis: { type: "category", data: rows.map((r) => r.year) }, + yAxis: { type: "value", max: 100, axisLabel: { formatter: "{value}%" } }, + series: [ + { + name: "sold", + type: "bar", + stack: "p", + data: rows.map((r) => r.sold_perc), + itemStyle: { color: "#0a7a3a" }, + }, + { + name: "unsold", + type: "bar", + stack: "p", + data: rows.map((r) => r.unsold_perc), + itemStyle: { color: "#f59e0b" }, + }, + { + name: "не открыто", + type: "bar", + stack: "p", + data: rows.map((r) => r.unopened_perc), + itemStyle: { color: "#b3261e" }, + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/PrinzipDistrictsBar.tsx b/frontend/src/components/analytics/PrinzipDistrictsBar.tsx new file mode 100644 index 00000000..0a47fd9c --- /dev/null +++ b/frontend/src/components/analytics/PrinzipDistrictsBar.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { useMemo } from "react"; + +import { useDistricts, usePrinzipDistricts } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function PrinzipDistrictsBar() { + const districts = useDistricts(); + const prinzip = usePrinzipDistricts(); + + const option = useMemo(() => { + const dRows = districts.data ?? []; + const pRows = prinzip.data ?? []; + const order = [...dRows] + .filter((r) => r.district_name !== "не определён") + .sort((a, b) => (b.zk_count ?? 0) - (a.zk_count ?? 0)) + .map((r) => r.district_name); + + return { + tooltip: { + trigger: "axis", + axisPointer: { type: "shadow" }, + formatter: ( + params: { + axisValueLabel: string; + marker: string; + seriesName: string; + value: number; + }[], + ) => { + const district = params[0]?.axisValueLabel ?? ""; + const total = + dRows.find((d) => d.district_name === district)?.zk_count ?? 0; + const prinzipRow = pRows.find((p) => p.district_name === district); + const share = prinzipRow?.share_in_district_pct ?? 0; + return [ + `${district}`, + `Всего ЖК: ${total}`, + `PRINZIP: ${prinzipRow?.prinzip_zk ?? 0} (${share}%)`, + ].join("
    "); + }, + }, + legend: { data: ["Все девелоперы", "PRINZIP"] }, + grid: { left: 120, right: 32, top: 40, bottom: 28 }, + xAxis: { type: "value" }, + yAxis: { type: "category", data: order, inverse: true }, + series: [ + { + name: "Все девелоперы", + type: "bar", + data: order.map( + (n) => dRows.find((d) => d.district_name === n)?.zk_count ?? 0, + ), + itemStyle: { color: "#94a3b8" }, + }, + { + name: "PRINZIP", + type: "bar", + data: order.map( + (n) => pRows.find((p) => p.district_name === n)?.prinzip_zk ?? 0, + ), + itemStyle: { color: "#1d4ed8" }, + }, + ], + }; + }, [districts.data, prinzip.data]); + + return ( + + ); +} diff --git a/frontend/src/components/analytics/PrinzipGapBar.tsx b/frontend/src/components/analytics/PrinzipGapBar.tsx new file mode 100644 index 00000000..1dd232ec --- /dev/null +++ b/frontend/src/components/analytics/PrinzipGapBar.tsx @@ -0,0 +1,70 @@ +"use client"; + +import { useMemo } from "react"; + +import { usePrinzipInsights } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function PrinzipGapBar() { + const { data, isLoading } = usePrinzipInsights(); + + const option = useMemo(() => { + const rows = data?.key_gaps ?? []; + return { + tooltip: { + trigger: "axis", + axisPointer: { type: "shadow" }, + formatter: ( + params: { + axisValueLabel: string; + marker: string; + seriesName: string; + value: number; + }[], + ) => { + const label = params[0]?.axisValueLabel ?? ""; + const unit = rows.find((r) => r.label === label)?.unit ?? ""; + return [ + `${label}`, + ...params.map( + (p) => `${p.marker}${p.seriesName}: ${p.value}${unit}`, + ), + ].join("
    "); + }, + }, + legend: { data: ["PRINZIP", "Рынок Свердл", "Брусника", "Форум-групп"] }, + grid: { left: 120, right: 32, top: 40, bottom: 28 }, + xAxis: { type: "value" }, + yAxis: { type: "category", data: rows.map((r) => r.label) }, + series: [ + { + name: "PRINZIP", + type: "bar", + data: rows.map((r) => r.prinzip), + itemStyle: { color: "#1d4ed8" }, + }, + { + name: "Рынок Свердл", + type: "bar", + data: rows.map((r) => r.market), + itemStyle: { color: "#94a3b8" }, + }, + { + name: "Брусника", + type: "bar", + data: rows.map((r) => r.brusnika), + itemStyle: { color: "#0a7a3a" }, + }, + { + name: "Форум-групп", + type: "bar", + data: rows.map((r) => r.forum), + itemStyle: { color: "#c2410c" }, + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/PrinzipQuartirographyPie.tsx b/frontend/src/components/analytics/PrinzipQuartirographyPie.tsx new file mode 100644 index 00000000..6ca085fb --- /dev/null +++ b/frontend/src/components/analytics/PrinzipQuartirographyPie.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useMemo } from "react"; + +import { useDeveloperDetail } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function PrinzipQuartirographyPie({ + developerId = "6208_0", +}: { + developerId?: string; +}) { + const { data, isLoading } = useDeveloperDetail(developerId); + + const option = useMemo(() => { + const rows = data + ? [ + { name: "1-к", value: data.agg_one_room ?? 0 }, + { name: "2-к", value: data.agg_two_room ?? 0 }, + { name: "3-к", value: data.agg_three_room ?? 0 }, + { name: "4+", value: data.agg_four_plus ?? 0 }, + ] + : []; + return { + tooltip: { trigger: "item", formatter: "{b}: {c} ({d}%)" }, + legend: { bottom: 0 }, + series: [ + { + type: "pie", + radius: ["45%", "70%"], + label: { formatter: "{b}\n{d}%" }, + data: rows, + color: ["#94a3b8", "#3b82f6", "#0a7a3a", "#c2410c"], + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/PrinzipVelocityChart.tsx b/frontend/src/components/analytics/PrinzipVelocityChart.tsx new file mode 100644 index 00000000..e67b59db --- /dev/null +++ b/frontend/src/components/analytics/PrinzipVelocityChart.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { useMemo } from "react"; + +import { useDeveloperHistory } from "@/lib/analytics-api"; + +const PALETTE = [ + "#1d4ed8", + "#0a7a3a", + "#c2410c", + "#9333ea", + "#0891b2", + "#5b6066", +]; + +import { ChartShell } from "./ChartShell"; + +interface Props { + developerIds: string[]; + developerNames: Record; +} + +export function PrinzipVelocityChart({ developerIds, developerNames }: Props) { + const { data, isLoading } = useDeveloperHistory(developerIds); + + const option = useMemo(() => { + const points = data ?? []; + const byDev: Record = {}; + for (const p of points) { + if (!byDev[p.developer_id]) byDev[p.developer_id] = []; + byDev[p.developer_id].push({ + date: p.snapshot_date.slice(0, 7), + sold: p.sold_perc, + }); + } + const dates = Array.from( + new Set(points.map((p) => p.snapshot_date.slice(0, 7))), + ).sort(); + const series = developerIds.map((id, i) => ({ + name: developerNames[id] ?? id, + type: "line", + smooth: true, + symbol: "circle", + lineStyle: { + width: id === "6208_0" ? 3 : 2, + color: PALETTE[i % PALETTE.length], + }, + itemStyle: { color: PALETTE[i % PALETTE.length] }, + data: dates.map( + (d) => byDev[id]?.find((p) => p.date === d)?.sold ?? null, + ), + connectNulls: true, + })); + return { + tooltip: { trigger: "axis", valueFormatter: (v: number) => `${v}%` }, + legend: { data: series.map((s) => s.name as string) }, + grid: { left: 48, right: 32, top: 40, bottom: 28 }, + xAxis: { type: "category", data: dates }, + yAxis: { type: "value", axisLabel: { formatter: "{value}%" } }, + series, + }; + }, [data, developerIds, developerNames]); + + return ; +} diff --git a/frontend/src/components/analytics/QuartirographyChart.tsx b/frontend/src/components/analytics/QuartirographyChart.tsx new file mode 100644 index 00000000..d456baac --- /dev/null +++ b/frontend/src/components/analytics/QuartirographyChart.tsx @@ -0,0 +1,71 @@ +"use client"; + +import { useMemo } from "react"; + +import { + useQuartirographyDeals, + useQuartirographyPortfolio, +} from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function QuartirographyChart() { + const portfolio = useQuartirographyPortfolio(); + const deals = useQuartirographyDeals(); + + const option = useMemo(() => { + const portfolioRows = portfolio.data ?? []; + const dealsRows = deals.data ?? []; + const buckets = [ + "Студии 15-30", + "1-к 30-45", + "2-к 45-60", + "3-к 60-80", + "80+ м²", + ]; + const portfolioMap: Record = { + "1-к 30-45": portfolioRows.find((r) => r.bucket === "1-к")?.percent ?? 0, + "2-к 45-60": portfolioRows.find((r) => r.bucket === "2-к")?.percent ?? 0, + "3-к 60-80": portfolioRows.find((r) => r.bucket === "3-к")?.percent ?? 0, + "80+ м²": portfolioRows.find((r) => r.bucket === "4+")?.percent ?? 0, + }; + const dealsPercents = buckets.map( + (b) => dealsRows.find((r) => r.bucket === b)?.percent ?? 0, + ); + const portfolioPercents = buckets.map((b) => portfolioMap[b] ?? 0); + + return { + tooltip: { + trigger: "axis", + axisPointer: { type: "shadow" }, + valueFormatter: (v: number) => `${v}%`, + }, + legend: { data: ["Что строится (портфель)", "Что покупают (ДДУ)"] }, + grid: { left: 110, right: 32, top: 40, bottom: 28 }, + xAxis: { type: "value", axisLabel: { formatter: "{value}%" } }, + yAxis: { type: "category", data: buckets, inverse: true }, + series: [ + { + name: "Что строится (портфель)", + type: "bar", + data: portfolioPercents, + itemStyle: { color: "#94a3b8" }, + }, + { + name: "Что покупают (ДДУ)", + type: "bar", + data: dealsPercents, + itemStyle: { color: "#0a7a3a" }, + }, + ], + }; + }, [portfolio.data, deals.data]); + + return ( + + ); +} diff --git a/frontend/src/components/analytics/Section.tsx b/frontend/src/components/analytics/Section.tsx new file mode 100644 index 00000000..5c7d2898 --- /dev/null +++ b/frontend/src/components/analytics/Section.tsx @@ -0,0 +1,43 @@ +import type { ReactNode } from "react"; + +interface Props { + title: string; + subtitle?: string; + right?: ReactNode; + children: ReactNode; +} + +export function Section({ title, subtitle, right, children }: Props) { + return ( +
    +
    +
    +

    {title}

    + {subtitle ? ( +

    + {subtitle} +

    + ) : null} +
    + {right ?
    {right}
    : null} +
    + {children} +
    + ); +} diff --git a/frontend/src/components/analytics/VelocityScatter.tsx b/frontend/src/components/analytics/VelocityScatter.tsx new file mode 100644 index 00000000..28b4a92e --- /dev/null +++ b/frontend/src/components/analytics/VelocityScatter.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useMemo } from "react"; + +import { useTopDevelopers } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +export function VelocityScatter() { + const { data, isLoading } = useTopDevelopers(30); + + const option = useMemo(() => { + const rows = data ?? []; + return { + tooltip: { + trigger: "item", + formatter: (info: { data: [number, number, string, number] }) => { + const [x, y, name, sold] = info.data; + return `${name}
    Объём: ${x} тыс м²
    Δ sold: ${y > 0 ? "+" : ""}${y} пп
    текущий sold%: ${sold}%`; + }, + }, + grid: { left: 56, right: 32, top: 32, bottom: 56 }, + xAxis: { + name: "Объём, тыс м²", + nameLocation: "middle", + nameGap: 32, + type: "value", + }, + yAxis: { + name: "Δ sold % (пп)", + nameLocation: "middle", + nameGap: 36, + type: "value", + axisLine: { show: true }, + }, + series: [ + { + type: "scatter", + symbolSize: 14, + data: rows + .filter((r) => r.sold_delta_pp != null && r.sverdl_sqm_th != null) + .map((r) => [ + r.sverdl_sqm_th, + r.sold_delta_pp, + r.developer_name, + r.sold_pct ?? 0, + ]), + itemStyle: { + color: (p: { data: [number, number, string, number] }) => + p.data[1] > 5 + ? "#0a7a3a" + : p.data[1] < -5 + ? "#b3261e" + : "#5b6066", + }, + label: { + show: true, + position: "right", + formatter: (p: { data: [number, number, string, number] }) => + p.data[2], + fontSize: 11, + color: "#374151", + }, + markLine: { + silent: true, + symbol: "none", + lineStyle: { color: "#cbd5e1", type: "dashed" }, + data: [{ yAxis: 0 }], + }, + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/components/analytics/YandexClassPie.tsx b/frontend/src/components/analytics/YandexClassPie.tsx new file mode 100644 index 00000000..51bc31a7 --- /dev/null +++ b/frontend/src/components/analytics/YandexClassPie.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useMemo } from "react"; + +import { useYandexListings } from "@/lib/analytics-api"; + +import { ChartShell } from "./ChartShell"; + +const CLASS_LABELS: Record = { + ECONOM: "Эконом", + COMFORT: "Комфорт", + COMFORT_PLUS: "Комфорт+", + BUSINESS: "Бизнес", + ELITE: "Элит", +}; + +export function YandexClassPie() { + const { data, isLoading } = useYandexListings(); + + const option = useMemo(() => { + const rows = data?.by_class ?? []; + return { + tooltip: { trigger: "item" }, + legend: { bottom: 0 }, + series: [ + { + type: "pie", + radius: ["45%", "70%"], + avoidLabelOverlap: false, + label: { formatter: "{b}: {c}" }, + data: rows.map((r) => ({ + name: CLASS_LABELS[r.obj_class] ?? r.obj_class, + value: r.count, + })), + }, + ], + }; + }, [data]); + + return ; +} diff --git a/frontend/src/lib/analytics-api.ts b/frontend/src/lib/analytics-api.ts new file mode 100644 index 00000000..00279f21 --- /dev/null +++ b/frontend/src/lib/analytics-api.ts @@ -0,0 +1,125 @@ +"use client"; + +import { useQuery } from "@tanstack/react-query"; + +import { apiFetch } from "./api"; +import type { + DeveloperDetail, + DeveloperHistoryPoint, + DeveloperPortfolioObject, + DeveloperTopRow, + DistrictRow, + MarketPulsePoint, + PipelineRow, + PrinzipDistrictRow, + PrinzipInsights, + QuartirographyDealsRow, + QuartirographyPortfolioRow, + YandexListingsSummary, +} from "@/types/analytics"; + +const BASE = "/api/v1/analytics"; + +export function useMarketPulse() { + return useQuery({ + queryKey: ["analytics", "market-pulse"], + queryFn: () => apiFetch(`${BASE}/sverdl/market-pulse`), + }); +} + +export function useQuartirographyPortfolio() { + return useQuery({ + queryKey: ["analytics", "quartirography", "portfolio"], + queryFn: () => + apiFetch( + `${BASE}/sverdl/quartirography?source=portfolio`, + ), + }); +} + +export function useQuartirographyDeals() { + return useQuery({ + queryKey: ["analytics", "quartirography", "deals"], + queryFn: () => + apiFetch( + `${BASE}/sverdl/quartirography?source=deals`, + ), + }); +} + +export function usePipeline() { + return useQuery({ + queryKey: ["analytics", "pipeline"], + queryFn: () => apiFetch(`${BASE}/sverdl/pipeline`), + }); +} + +export function useDistricts() { + return useQuery({ + queryKey: ["analytics", "districts"], + queryFn: () => apiFetch(`${BASE}/sverdl/districts`), + }); +} + +export function useYandexListings() { + return useQuery({ + queryKey: ["analytics", "yandex"], + queryFn: () => + apiFetch(`${BASE}/sverdl/yandex-listings`), + }); +} + +export function useTopDevelopers(limit = 15) { + return useQuery({ + queryKey: ["analytics", "top-devs", limit], + queryFn: () => + apiFetch(`${BASE}/developers/top?limit=${limit}`), + }); +} + +export function useDeveloperDetail(developerId: string) { + return useQuery({ + queryKey: ["analytics", "dev", developerId], + queryFn: () => + apiFetch(`${BASE}/developers/${developerId}`), + enabled: !!developerId, + }); +} + +export function useDeveloperHistory(developerIds: string[]) { + const idsParam = developerIds.join(","); + return useQuery({ + queryKey: ["analytics", "dev-history", idsParam], + queryFn: () => + apiFetch( + `${BASE}/developers/history?ids=${encodeURIComponent(idsParam)}`, + ), + enabled: developerIds.length > 0, + }); +} + +export function useDeveloperPortfolio(developerId: string) { + return useQuery({ + queryKey: ["analytics", "dev-portfolio", developerId], + queryFn: () => + apiFetch( + `${BASE}/developers/${developerId}/portfolio`, + ), + enabled: !!developerId, + }); +} + +export function usePrinzipInsights() { + return useQuery({ + queryKey: ["analytics", "prinzip-insights"], + queryFn: () => apiFetch(`${BASE}/prinzip/insights`), + staleTime: Infinity, + }); +} + +export function usePrinzipDistricts() { + return useQuery({ + queryKey: ["analytics", "prinzip-districts"], + queryFn: () => apiFetch(`${BASE}/prinzip/districts`), + }); +} diff --git a/frontend/src/types/analytics.ts b/frontend/src/types/analytics.ts new file mode 100644 index 00000000..7e331294 --- /dev/null +++ b/frontend/src/types/analytics.ts @@ -0,0 +1,146 @@ +export interface MarketPulsePoint { + snapshot_date: string; + rep_year: number; + rep_month: number; + total_square_th_sqm: number | null; + sold_perc: number | null; + price_avg: number | null; +} + +export interface QuartirographyPortfolioRow { + bucket: string; + flat_count: number; + area_sqm: number | null; + percent: number | null; + avg_area: number | null; +} + +export interface QuartirographyDealsRow { + bucket: string; + deals: number; + percent: number; + median_price: number | null; +} + +export interface PipelineRow { + year: string; + total_th_sqm: number | null; + sold_perc: number | null; + unsold_perc: number | null; + unopened_perc: number | null; +} + +export interface DistrictRow { + district_name: string; + zk_count: number | null; + flat_count: number | null; + area_m2: number | null; + median_price_per_m2: number | null; + mean_price_per_m2: number | null; +} + +export interface YandexListing { + yid: number; + name: string; + developer: string | null; + obj_class: string | null; + flats_total: number; + price_from: number | null; + price_to: number | null; + address: string | null; + lat: number | null; + lon: number | null; +} + +export interface YandexListingsSummary { + snapshot_date: string | null; + total: number; + by_class: { obj_class: string; count: number }[]; + items: YandexListing[]; +} + +export interface DeveloperTopRow { + developer_id: string; + developer_name: string; + jk_count: number | null; + jk_flats_total: number | null; + sverdl_sqm_th: number | null; + sold_pct: number | null; + sold_delta_pp: number | null; + sold_first: number | null; + sold_last: number | null; + first_dt: string | null; + last_dt: string | null; + avg_area_sqm: number | null; + pct_one: number | null; + pct_three_plus: number | null; +} + +export interface DeveloperDetail { + developer_id: string; + developer_name: string; + jk_count: number | null; + jk_flats_total: number | null; + jk_sqm_total: number | null; + jk_ekb: number | null; + jk_completed: number | null; + jk_in_progress: number | null; + jk_escrow: number | null; + agg_flats_total: number | null; + agg_one_room: number | null; + agg_two_room: number | null; + agg_three_room: number | null; + agg_four_plus: number | null; + pct_one: number | null; + pct_three_plus: number | null; + avg_area_sqm: number | null; + sverdl_sqm_th: number | null; + sverdl_sold_pct: number | null; + sverdl_unsold_pct: number | null; + sverdl_price_avg: number | null; +} + +export interface DeveloperHistoryPoint { + developer_id: string; + snapshot_date: string; + sold_perc: number | null; + total_th_sqm: number | null; +} + +export interface DeveloperPortfolioObject { + obj_id: number; + comm_name: string | null; + addr: string | null; + region_cd: number | null; + flat_count: number | null; + square_living: number | null; + ready_dt: string | null; + obj_class: string | null; + escrow: boolean | null; + problem_flag: string | null; + lat: number | null; + lon: number | null; + is_ekb: boolean | null; +} + +export interface PrinzipDistrictRow { + district_name: string; + prinzip_zk: number; + share_in_district_pct: number; +} + +export interface PrinzipInsights { + headline: string; + key_gaps: { + label: string; + prinzip: number; + market: number; + brusnika: number; + forum: number; + unit: string; + }[]; + priorities: { rank: number; title: string; why: string }[]; + where_to_build: { district: string; why: string }[]; + what_to_avoid: string[]; + benchmarks: { name: string; model: string }[]; +} diff --git a/frontend/tsconfig.tsbuildinfo b/frontend/tsconfig.tsbuildinfo new file mode 100644 index 00000000..2e630546 --- /dev/null +++ b/frontend/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/web-globals/navigator.d.ts","./node_modules/@types/node/web-globals/storage.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/sqlite.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/build/webpack/plugins/app-build-manifest-plugin.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/prefetch-rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/root-params.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./next.config.ts","./node_modules/@tanstack/query-core/build/modern/_tsup-dts-rollup.d.ts","./node_modules/@tanstack/query-core/build/modern/index.d.ts","./node_modules/@tanstack/react-query/build/modern/_tsup-dts-rollup.d.ts","./node_modules/@tanstack/react-query/build/modern/index.d.ts","./src/lib/api.ts","./src/types/analytics.ts","./src/lib/analytics-api.ts","./src/app/providers.tsx","./src/app/layout.tsx","./src/app/page.tsx","./src/components/analytics/analyticsnav.tsx","./src/app/analytics/layout.tsx","./node_modules/echarts/types/dist/echarts.d.ts","./node_modules/echarts/index.d.ts","./node_modules/echarts-for-react/lib/types.d.ts","./node_modules/echarts-for-react/lib/core.d.ts","./node_modules/echarts-for-react/lib/index.d.ts","./src/components/analytics/chartshell.tsx","./src/components/analytics/districttreemap.tsx","./src/components/analytics/kpicard.tsx","./src/components/analytics/marketpulsechart.tsx","./src/components/analytics/pipelinechart.tsx","./src/components/analytics/quartirographychart.tsx","./src/components/analytics/section.tsx","./src/components/analytics/yandexclasspie.tsx","./src/app/analytics/page.tsx","./src/components/analytics/developerleaderboard.tsx","./src/components/analytics/prinzipvelocitychart.tsx","./src/components/analytics/velocityscatter.tsx","./src/app/analytics/developers/page.tsx","./src/components/analytics/insightcards.tsx","./src/components/analytics/prinzipdistrictsbar.tsx","./src/components/analytics/prinzipgapbar.tsx","./src/components/analytics/prinzipquartirographypie.tsx","./src/app/analytics/prinzip/page.tsx","./src/app/concept/page.tsx","./src/app/site-finder/page.tsx","./node_modules/@types/estree/index.d.ts","./node_modules/@types/leaflet/index.d.ts","./node_modules/@types/leaflet-draw/index.d.ts"],"fileIdsList":[[99,147,164,165,498],[99,147,164,165],[99,147,164,165,500],[85,99,147,164,165,265,501],[99,147,164,165,502],[99,147,164,165,538,539],[99,144,145,147,164,165],[99,146,147,164,165],[147,164,165],[99,147,152,164,165,182],[99,147,148,153,158,164,165,167,179,190],[99,147,148,149,158,164,165,167],[94,95,96,99,147,164,165],[99,147,150,164,165,191],[99,147,151,152,159,164,165,168],[99,147,152,164,165,179,187],[99,147,153,155,158,164,165,167],[99,146,147,154,164,165],[99,147,155,156,164,165],[99,147,157,158,164,165],[99,146,147,158,164,165],[99,147,158,159,160,164,165,179,190],[99,147,158,159,160,164,165,174,179,182],[99,140,147,155,158,161,164,165,167,179,190],[99,147,158,159,161,162,164,165,167,179,187,190],[99,147,161,163,164,165,179,187,190],[97,98,99,100,101,102,103,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,183,184,185,186,187,188,189,190,191,192,193,194,195,196],[99,147,158,164,165],[99,147,164,165,166,190],[99,147,155,158,164,165,167,179],[99,147,164,165,168],[99,147,164,165,169],[99,146,147,164,165,170],[99,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,183,184,185,186,187,188,189,190,191,192,193,194,195,196],[99,147,164,165,172],[99,147,164,165,173],[99,147,158,164,165,174,175],[99,147,164,165,174,176,191,193],[99,147,159,164,165],[99,147,158,164,165,179,180,182],[99,147,164,165,181,182],[99,147,164,165,179,180],[99,147,164,165,182],[99,147,164,165,183],[99,144,147,164,165,179,184,190],[99,147,158,164,165,185,186],[99,147,164,165,185,186],[99,147,152,164,165,167,179,187],[99,147,164,165,188],[99,147,164,165,167,189],[99,147,161,164,165,173,190],[99,147,152,164,165,191],[99,147,164,165,179,192],[99,147,164,165,166,193],[99,147,164,165,194],[99,140,147,164,165],[99,140,147,158,160,164,165,170,179,182,190,192,193,195],[99,147,164,165,179,196],[85,89,99,147,164,165,198,199,200,202,442,490],[85,99,147,164,165],[85,89,99,147,164,165,198,199,200,201,357,442,490],[85,89,99,147,164,165,198,199,201,202,442,490],[85,99,147,164,165,202,357,358],[85,99,147,164,165,202,357],[85,89,99,147,164,165,199,200,201,202,442,490],[85,89,99,147,164,165,198,200,201,202,442,490],[83,84,99,147,164,165],[85,99,147,164,165,513,514],[99,147,164,165,514,515],[85,99,147,164,165,513],[99,147,164,165,512],[91,99,147,164,165],[99,147,164,165,445],[99,147,164,165,447,448,449,450],[99,147,164,165,452],[99,147,164,165,206,220,221,222,224,439],[99,147,164,165,206,245,247,249,250,253,439,441],[99,147,164,165,206,210,212,213,214,215,216,428,439,441],[99,147,164,165,439],[99,147,164,165,221,323,409,418,435],[99,147,164,165,206],[99,147,164,165,203,435],[99,147,164,165,257],[99,147,164,165,256,439,441],[99,147,161,164,165,305,323,352,496],[99,147,161,164,165,316,332,418,434],[99,147,161,164,165,370],[99,147,164,165,422],[99,147,164,165,421,422,423],[99,147,164,165,421],[93,99,147,161,164,165,203,206,210,213,217,218,219,221,225,233,234,363,388,419,439,442],[99,147,164,165,206,223,241,245,246,251,252,439,496],[99,147,164,165,223,496],[99,147,164,165,234,241,303,439,496],[99,147,164,165,496],[99,147,164,165,206,223,224,496],[99,147,164,165,248,496],[99,147,164,165,217,420,427],[99,147,164,165,173,265,435],[99,147,164,165,265,435],[85,99,147,164,165,265],[85,99,147,164,165,324],[99,147,164,165,320,368,435,478,479],[99,147,164,165,415,472,473,474,475,477],[99,147,164,165,414],[99,147,164,165,414,415],[99,147,164,165,214,364,365,366],[99,147,164,165,364,367,368],[99,147,164,165,476],[99,147,164,165,364,368],[85,99,147,164,165,207,466],[85,99,147,164,165,190],[85,99,147,164,165,223,293],[85,99,147,164,165,223],[99,147,164,165,291,295],[85,99,147,164,165,292,444],[85,89,99,147,161,164,165,197,198,199,200,201,202,442,488,489],[99,147,161,164,165],[99,147,161,164,165,210,272,364,374,389,409,424,425,439,440,496],[99,147,164,165,233,426],[99,147,164,165,442],[99,147,164,165,205],[85,99,147,164,165,305,319,331,341,343,434],[99,147,164,165,173,305,319,340,341,342,434,495],[99,147,164,165,334,335,336,337,338,339],[99,147,164,165,336],[99,147,164,165,340],[99,147,164,165,263,264,265,267],[85,99,147,164,165,258,259,260,266],[99,147,164,165,263,266],[99,147,164,165,261],[99,147,164,165,262],[85,99,147,164,165,265,292,444],[85,99,147,164,165,265,443,444],[85,99,147,164,165,265,444],[99,147,164,165,389,431],[99,147,164,165,431],[99,147,161,164,165,440,444],[99,147,164,165,328],[99,146,147,164,165,327],[99,147,164,165,235,273,311,313,315,316,317,318,361,364,434,437,440],[99,147,164,165,235,349,364,368],[99,147,164,165,316,434],[85,99,147,164,165,316,325,326,328,329,330,331,332,333,344,345,346,347,348,350,351,434,435,496],[99,147,164,165,310],[99,147,161,164,165,173,235,236,272,287,317,361,362,363,368,389,409,430,439,440,441,442,496],[99,147,164,165,434],[99,146,147,164,165,221,314,317,363,430,432,433,440],[99,147,164,165,316],[99,146,147,164,165,272,277,306,307,308,309,310,311,312,313,315,434,435],[99,147,161,164,165,277,278,306,440,441],[99,147,164,165,221,363,364,389,430,434,440],[99,147,161,164,165,439,441],[99,147,161,164,165,179,437,440,441],[99,147,161,164,165,173,190,203,210,223,235,236,238,273,274,279,284,287,313,317,364,374,376,379,381,384,385,386,387,388,409,429,430,435,437,439,440,441],[99,147,161,164,165,179],[99,147,164,165,206,207,208,210,215,218,223,241,429,437,438,442,444,496],[99,147,161,164,165,179,190,253,255,257,258,259,260,267,496],[99,147,164,165,173,190,203,245,255,283,284,285,286,313,364,379,388,389,395,398,399,409,430,435,437],[99,147,164,165,217,218,233,363,388,430,439],[99,147,161,164,165,190,207,210,313,393,437,439],[99,147,164,165,304],[99,147,161,164,165,396,397,406],[99,147,164,165,437,439],[99,147,164,165,311,314],[99,147,164,165,313,317,429,444],[99,147,161,164,165,173,239,245,286,379,389,395,398,401,437],[99,147,161,164,165,217,233,245,402],[99,147,164,165,206,238,404,429,439],[99,147,161,164,165,190,439],[99,147,161,164,165,223,237,238,239,250,268,403,405,429,439],[93,99,147,164,165,235,317,408,442,444],[99,147,161,164,165,173,190,210,217,225,233,236,273,279,283,284,285,286,287,313,364,376,389,390,392,394,409,429,430,435,436,437,444],[99,147,161,164,165,179,217,395,400,406,437],[99,147,164,165,228,229,230,231,232],[99,147,164,165,274,380],[99,147,164,165,382],[99,147,164,165,380],[99,147,164,165,382,383],[99,147,161,164,165,210,213,214,272,440],[99,147,161,164,165,173,205,207,235,273,287,317,372,373,409,437,441,442,444],[99,147,161,164,165,173,190,209,214,313,373,436,440],[99,147,164,165,306],[99,147,164,165,307],[99,147,164,165,308],[99,147,164,165,435],[99,147,164,165,254,270],[99,147,161,164,165,210,254,273],[99,147,164,165,269,270],[99,147,164,165,271],[99,147,164,165,254,255],[99,147,164,165,254,288],[99,147,164,165,254],[99,147,164,165,274,378,436],[99,147,164,165,377],[99,147,164,165,255,435,436],[99,147,164,165,375,436],[99,147,164,165,255,435],[99,147,164,165,361],[99,147,164,165,210,215,273,302,305,311,313,317,319,322,353,356,360,364,408,429,437,440],[99,147,164,165,296,299,300,301,320,321,368],[85,99,147,164,165,200,202,265,354,355],[85,99,147,164,165,200,202,265,354,355,359],[99,147,164,165,417],[99,147,164,165,221,278,316,317,328,332,364,408,410,411,412,413,415,416,419,429,434,439],[99,147,164,165,368],[99,147,164,165,372],[99,147,161,164,165,273,289,369,371,374,408,437,442,444],[99,147,164,165,296,297,298,299,300,301,320,321,368,443],[93,99,147,161,164,165,173,190,236,254,255,287,313,317,406,407,409,429,430,439,440,442],[99,147,164,165,278,280,283,430],[99,147,161,164,165,274,439],[99,147,164,165,277,316],[99,147,164,165,276],[99,147,164,165,278,279],[99,147,164,165,275,277,439],[99,147,161,164,165,209,278,280,281,282,439,440],[85,99,147,164,165,364,365,367],[99,147,164,165,240],[85,99,147,164,165,207],[85,99,147,164,165,435],[85,93,99,147,164,165,287,317,442,444],[99,147,164,165,207,466,467],[85,99,147,164,165,295],[85,99,147,164,165,173,190,205,252,290,292,294,444],[99,147,164,165,223,435,440],[99,147,164,165,391,435],[99,147,164,165,364],[85,99,147,159,161,164,165,173,205,241,247,295,442,443],[85,99,147,164,165,198,199,200,201,202,442,490],[85,86,87,88,89,99,147,164,165],[99,147,152,164,165],[99,147,164,165,242,243,244],[99,147,164,165,242],[85,89,99,147,161,163,164,165,173,197,198,199,200,201,202,203,205,236,340,401,439,441,444,490],[99,147,164,165,454],[99,147,164,165,456],[99,147,164,165,458],[99,147,164,165,460],[99,147,164,165,462,463,464],[99,147,164,165,468],[90,92,99,147,164,165,446,451,453,455,457,459,461,465,469,471,481,482,484,494,495,496,497],[99,147,164,165,470],[99,147,164,165,480],[99,147,164,165,292],[99,147,164,165,483],[99,146,147,164,165,278,280,281,283,331,435,485,486,487,490,491,492,493],[99,147,164,165,197],[99,147,164,165,179,197],[99,112,116,147,164,165,190],[99,112,147,164,165,179,190],[99,107,147,164,165],[99,109,112,147,164,165,187,190],[99,147,164,165,167,187],[99,107,147,164,165,197],[99,109,112,147,164,165,167,190],[99,104,105,108,111,147,158,164,165,179,190],[99,112,119,147,164,165],[99,104,110,147,164,165],[99,112,133,134,147,164,165],[99,108,112,147,164,165,182,190,197],[99,133,147,164,165,197],[99,106,107,147,164,165,197],[99,112,147,164,165],[99,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,137,138,139,147,164,165],[99,112,127,147,164,165],[99,112,119,120,147,164,165],[99,110,112,120,121,147,164,165],[99,111,147,164,165],[99,104,107,112,147,164,165],[99,112,116,120,121,147,164,165],[99,116,147,164,165],[99,110,112,115,147,164,165,190],[99,104,109,112,119,147,164,165],[99,147,164,165,179],[99,107,112,133,147,164,165,195,197],[85,99,147,164,165,481,506,519,523,526,527,528],[99,147,164,165,471,510],[99,147,164,165,506,518,519,520,521,522,523,524],[85,99,147,164,165,506,519,523,527,530,531,532,533],[99,147,164,165,471],[99,147,164,165,498,507],[85,99,147,164,165,503],[99,147,164,165,471,481],[85,99,147,164,165,457,516],[85,99,147,164,165,471,505,506],[85,99,147,164,165,506,517],[99,147,164,165,506],[99,147,164,165,503,504,505]],"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":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","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":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","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":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"631eff75b0e35d1b1b31081d55209abc43e16b49426546ab5a9b40bdd40b1f60","impliedFormat":1},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"58647d85d0f722a1ce9de50955df60a7489f0593bf1a7015521efe901c06d770","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6f137d651076822d4fe884287e68fd61785a0d3d1fdb250a5059b691fa897db","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"bceb58df66ab8fb00170df20cd813978c5ab84be1d285710c4eb005d8e9d8efb","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"80523c00b8544a2000ae0143e4a90a00b47f99823eb7926c1e03c494216fc363","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"746911b62b329587939560deb5c036aca48aece03147b021fa680223255d5183","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c8d3e5a18ba35629954e48c4cc8f11dc88224650067a172685c736b27a34a4dc","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"2b55d426ff2b9087485e52ac4bc7cfafe1dc420fc76dad926cd46526567c501a","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"358765d5ea8afd285d4fd1532e78b88273f18cb3f87403a9b16fef61ac9fdcfe","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"829b9e6028b29e6a8b1c01ddb713efe59da04d857089298fa79acbdb3cfcfdef","impliedFormat":1},{"version":"24f8562308dd8ba6013120557fa7b44950b619610b2c6cb8784c79f11e3c4f90","impliedFormat":1},{"version":"5f90b8c733a1bda63e42160b15a2301051e83a6f9d5332a59d16eb12f463270d","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"496bbf339f3838c41f164238543e9fe5f1f10659cb30b68903851618464b98ba","impliedFormat":1},{"version":"5178eb4415a172c287c711dc60a619e110c3fd0b7de01ed0627e51a5336aa09c","impliedFormat":1},{"version":"ca6e5264278b53345bc1ce95f42fb0a8b733a09e3d6479c6ccfca55cdc45038c","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"fb1d8e814a3eeb5101ca13515e0548e112bd1ff3fb358ece535b93e94adf5a3a","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"98b18458acb46072947aabeeeab1e410f047e0cacc972943059ca5500b0a5e95","impliedFormat":1},{"version":"361e2b13c6765d7f85bb7600b48fde782b90c7c41105b7dab1f6e7871071ba20","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"b6db56e4903e9c32e533b78ac85522de734b3d3a8541bf24d256058d464bf04b","impliedFormat":1},{"version":"24daa0366f837d22c94a5c0bad5bf1fd0f6b29e1fae92dc47c3072c3fdb2fbd5","impliedFormat":1},{"version":"570bb5a00836ffad3e4127f6adf581bfc4535737d8ff763a4d6f4cc877e60d98","impliedFormat":1},{"version":"889c00f3d32091841268f0b994beba4dceaa5df7573be12c2c829d7c5fbc232c","impliedFormat":1},{"version":"65f43099ded6073336e697512d9b80f2d4fec3182b7b2316abf712e84104db00","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"27ab780875bcbb65e09da7496f2ca36288b0c541abaa75c311450a077d54ec15","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"380647d8f3b7f852cca6d154a376dbf8ac620a2f12b936594504a8a852e71d2f","impliedFormat":1},{"version":"208c9af9429dd3c76f5927b971263174aaa4bc7621ddec63f163640cbd3c473c","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"a23185bc5ef590c287c28a91baf280367b50ae4ea40327366ad01f6f4a8edbc5","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"002eae065e6960458bda3cf695e578b0d1e2785523476f8a9170b103c709cd4f","impliedFormat":1},{"version":"c83bb0c9c5645a46c68356c2f73fdc9de339ce77f7f45a954f560c7e0b8d5ebb","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"6a148329edecbda07c21098639ef4254ef7869fb25a69f58e5d6a8b7b69d4236","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"f63ab283a1c8f5c79fabe7ca4ef85f9633339c4f0e822fce6a767f9d59282af2","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"a54c996c8870ef1728a2c1fa9b8eaec0bf4a8001cd2583c02dd5869289465b10","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"3754982006a3b32c502cff0867ca83584f7a43b1035989ca73603f400de13c96","impliedFormat":1},{"version":"a30ae9bb8a8fa7b90f24b8a0496702063ae4fe75deb27da731ed4a03b2eb6631","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"e9dd71cf12123419c60dab867d44fbee5c358169f99529121eaef277f5c83531","impliedFormat":1},{"version":"5b6a189ba3a0befa1f5d9cb028eb9eec2af2089c32f04ff50e2411f63d70f25d","impliedFormat":1},{"version":"d6e73f8010935b7b4c7487b6fb13ea197cc610f0965b759bec03a561ccf8423a","impliedFormat":1},{"version":"174f3864e398f3f33f9a446a4f403d55a892aa55328cf6686135dfaf9e171657","impliedFormat":1},{"version":"824c76aec8d8c7e65769688cbee102238c0ef421ed6686f41b2a7d8e7e78a931","impliedFormat":1},{"version":"75b868be3463d5a8cfc0d9396f0a3d973b8c297401d00bfb008a42ab16643f13","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","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":"6dcf60530c25194a9ee0962230e874ff29d34c59605d8e069a49928759a17e0a","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"1a42d2ec31a1fe62fdc51591768695ed4a2dc64c01be113e7ff22890bebb5e3f","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"0c7c947ff881c4274c0800deaa0086971e0bfe51f89a33bd3048eaa3792d4876","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","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":"15b36126e0089bfef173ab61329e8286ce74af5e809d8a72edcafd0cc049057f","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"72d63643a657c02d3e51cd99a08b47c9b020a565c55f246907050d3c8a5e77fb","impliedFormat":1},{"version":"1d415445ea58f8033ba199703e55ff7483c52ac6742075b803bd3e7bbe9f5d61","impliedFormat":1},{"version":"d6406c629bb3efc31aedb2de809bef471e475c86c7e67f3ef9b676b5d7e0d6b2","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"71d8ba39a9e024d9e4bb922464d18542ed8d2c25ee78efa7890c27213cc6e5d3","impliedFormat":1},{"version":"8c030e515014c10a2b98f9f48408e3ba18023dfd3f56e3312c6c2f3ae1f55a16","impliedFormat":1},{"version":"dafc31e9e8751f437122eb8582b93d477e002839864410ff782504a12f2a550c","impliedFormat":1},{"version":"754498c5208ce3c5134f6eabd49b25cf5e1a042373515718953581636491f3c3","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"633d58a237f4bb25ec7d565e4ffa32cecdcee8660ac12189c4351c52557cee9e","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"ce791f6ea807560f08065d1af6014581eeb54a05abd73294777a281b6dfd73c2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"e17cd049a1448de4944800399daa4a64c5db8657cc9be7ef46be66e2a2cd0e7c","impliedFormat":1},{"version":"43fa6ea8714e18adc312b30450b13562949ba2f205a1972a459180fa54471018","impliedFormat":1},{"version":"6e89c2c177347d90916bad67714d0fb473f7e37fb3ce912f4ed521fe2892cd0d","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"4d4927cbee21750904af7acf940c5e3c491b4d5ebc676530211e389dd375607a","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"8a97e578a9bc40eb4f1b0ca78f476f2e9154ecbbfd5567ee72943bab37fc156a","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"f22d05663d873ee7a600faf78abb67f3f719d32266803440cf11d5db7ac0cab2","impliedFormat":1},{"version":"d93c544ad20197b3976b0716c6d5cd5994e71165985d31dcab6e1f77feb4b8f2","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"a8b1c79a833ee148251e88a2553d02ce1641d71d2921cce28e79678f3d8b96aa","impliedFormat":1},{"version":"126d4f950d2bba0bd45b3a86c76554d4126c16339e257e6d2fabf8b6bf1ce00c","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"2d3cc2211f352f46ea6b7cf2c751c141ffcdf514d6e7ae7ee20b7b6742da313f","impliedFormat":1},{"version":"c75445151ff8b77d9923191efed7203985b1a9e09eccf4b054e7be864e27923d","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"fa8a8fbf91ee2a4779496225f0312aac6635b0f21aa09cdafa4283fe32d519c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e8aef93d79b000deb6ec336b5645c87de167168e184e84521886f9ecc69a4b5","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"de7052bfee2981443498239a90c04ea5cc07065d5b9bb61b12cb6c84313ad4ef","impliedFormat":1},{"version":"a3e7d932dc9c09daa99141a8e4800fc6c58c625af0d4bbb017773dc36da75426","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"4a2edd238d9104eac35b60d727f1123de5062f452b70ed8e0366cb36387dfdfd","impliedFormat":1},{"version":"ca921bf56756cb6fe957f6af693a35251b134fb932dc13f3dfff0bb7106f80b4","impliedFormat":1},{"version":"fee92c97f1aa59eb7098a0cc34ff4df7e6b11bae71526aca84359a2575f313d8","impliedFormat":1},{"version":"0bd0297484aacea217d0b76e55452862da3c5d9e33b24430e0719d1161657225","impliedFormat":1},{"version":"2ab6d334bcbf2aff3acfc4fd8c73ecd82b981d3c3aa47b3f3b89281772286904","impliedFormat":1},{"version":"d07cbc787a997d83f7bde3877fec5fb5b12ce8c1b7047eb792996ed9726b4dde","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"49179c6a23701c642bd99abe30d996919748014848b738d8e85181fc159685ff","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"45490817629431853543adcb91c0673c25af52a456479588b6486daba34f68bb","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"8514c62ce38e58457d967e9e73f128eedc1378115f712b9eef7127f7c88f82ae","impliedFormat":1},{"version":"f1289e05358c546a5b664fbb35a27738954ec2cc6eb4137350353099d154fc62","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"1d17ba45cfbe77a9c7e0df92f7d95f3eefd49ee23d1104d0548b215be56945ad","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"a1ee88010a64e8647d07dba58ec43e6e05851b9ec7a62e4ca2b9c33be5abb2c8","impliedFormat":1},{"version":"46273e8c29816125d0d0b56ce9a849cc77f60f9a5ba627447501d214466f0ff3","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"e91f7b1344577a02f051b9b471f33044fef8334a76dc9e1de003d17595a5219b","impliedFormat":1},{"version":"3af3584f79c57853028ef9421ec172539e1fe01853296dc05a9d615ade4ffaf6","impliedFormat":1},{"version":"f82579d87701d639ff4e3930a9b24f4ee13ca74221a9a3a792feb47f01881a9c","impliedFormat":1},{"version":"d7e5d5245a8ba34a274717d085174b2c9827722778129b0081fefd341cca8f55","impliedFormat":1},{"version":"d9d32f94056181c31f553b32ce41d0ef75004912e27450738d57efcd2409c324","impliedFormat":1},{"version":"752513f35f6cff294ffe02d6027c41373adf7bfa35e593dbfd53d95c203635ee","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"1a7e2ea171726446850ec72f4d1525d547ff7e86724cc9e7eec509725752a758","impliedFormat":1},{"version":"8c901126d73f09ecdea4785e9a187d1ac4e793e07da308009db04a7283ec2f37","impliedFormat":1},{"version":"db97922b767bd2675fdfa71e08b49c38b7d2c847a1cc4a7274cb77be23b026f1","impliedFormat":1},{"version":"aab290b8e4b7c399f2c09b957666fc95335eb4522b2dd9ead1bf0cb64da6d6ee","impliedFormat":1},{"version":"94fe3281392e1015b22f39535878610b4fa6f1388dc8d78746be3bc4e4bb8950","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"06c25ddfc2242bd06c19f66c9eae4c46d937349a267810f89783680a1d7b5259","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"0427df5c06fafc5fe126d14b9becd24160a288deff40e838bfbd92a35f8d0d00","impliedFormat":1},{"version":"90c54a02432d04e4246c87736e53a6a83084357acfeeba7a489c5422b22f5c7a","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"0a372c2d12a259da78e21b25974d2878502f14d89c6d16b97bd9c5017ab1bc12","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"ec1ca97598eda26b7a5e6c8053623acbd88e43be7c4d29c77ccd57abc4c43999","impliedFormat":1},{"version":"6e2261cd9836b2c25eecb13940d92c024ebed7f8efe23c4b084145cd3a13b8a6","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"a47e6d954d22dd9ebb802e7e431b560ed7c581e79fb885e44dc92ed4f60d4c07","impliedFormat":1},{"version":"f019e57d2491c159d47a107fd90219a1734bdd2e25cd8d1db3c8fae5c6b414c4","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d1c9bf292a54312888a77bb19dba5e2503ad803f5393beafd45d78d2f4fe9b48","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"cb8d8ef7b9ce8ed3e6f1c814fcbf3f90dab0cb8863079236784fc350746e27c4","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"3be035da7bee86b4c3abf392e0edaa44fc6e45092995eefe36b39118c8a84068","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f828825d077c2fa0ea606649faeb122749273a353daab23924fe674e98ba44c","impliedFormat":1},{"version":"2896c2e673a5d3bd9b4246811f79486a073cbb03950c3d252fba10003c57411a","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"407a06ba04eede4074eec470ecba2784cbb3bf4e7de56833b097dd90a2aa0651","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"5c96bad5f78466785cdad664c056e9e2802d5482ca5f862ed19ba34ffbb7b3a4","impliedFormat":1},{"version":"81d8603ac527e75cfec72bb9391228b58f161c2b33514a9d814c7f3ebd3ef466","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"bb0cd7862b72f5eba39909c9889d566e198fcaddf7207c16737d0c2246112678","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"bad68fd0401eb90fe7da408565c8aee9c7a7021c2577aec92fa1382e8876071a","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"fec01479923e169fb52bd4f668dbeef1d7a7ea6e6d491e15617b46f2cacfa37d","impliedFormat":1},{"version":"8a8fb3097ba52f0ae6530ec6ab34e43e316506eb1d9aa29420a4b1e92a81442d","impliedFormat":1},{"version":"44e09c831fefb6fe59b8e65ad8f68a7ecc0e708d152cfcbe7ba6d6080c31c61e","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"4655709c9cb3fd6db2b866cab7c418c40ed9533ce8ea4b66b5f17ec2feea46a9","impliedFormat":1},{"version":"87affad8e2243635d3a191fa72ef896842748d812e973b7510a55c6200b3c2a4","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"3eecb25bb467a948c04874d70452b14ae7edb707660aac17dc053e42f2088b00","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"5f0292a40df210ab94b9fb44c8b775c51e96777e14e073900e392b295ca1061b","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"8627ad129bcf56e82adff0ab5951627c993937aa99f5949c33240d690088b803","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"ecbaf0da125974be39c0aac869e403f72f033a4e7fd0d8cd821a8349b4159628","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"ceec3c81b2d81f5e3b855d9367c1d4c664ab5046dff8fd56552df015b7ccbe8f","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"1d63055b690a582006435ddd3aa9c03aac16a696fac77ce2ed808f3e5a06efab","impliedFormat":1},"751eda1ebd29cc60074e34cf069fdaa23bc6f389cb6335d54a202e449ebe4de9",{"version":"5a2cdf6adeec348bbc876221be4367e8adff0bb78a5680ebd7d71e5c3bad6cc0","impliedFormat":99},{"version":"e004826eac62081f867c66dabd92d3ef7d126d93a70430a2c88429228c3ecc50","impliedFormat":99},{"version":"38d6857b58d2ac42442e396311c542062d4f0dad40f2adb496dd5fd0756ee400","impliedFormat":99},{"version":"34b7d1e2d15845cf08bcf5e3c01adbb92cea1ec27564ee249ba486cdfb28526c","impliedFormat":99},"71d1b48157e4816f38e850326d7d36148e6ab2904cdfc53c0100654b9cc8767c","33ae00fa293556dd2d67d2ff11aa11f3072c995ad9e3b4421471be5f2c804d13","f2cc11974f58c77e0c2b46c97a3969ee143123fd0bae91225a175994893582ec","7db7155cd403d7f5d150a7d3352d76e012326884ee71ef6cb2f677a91dcadfb0","6230434c17eb56d7c6ef405721fe840a4324676a0298dfe455499070152ac6fa","b4acfb503c86f42f718eb48c9eb925795f4e04eb3fc92b9a870c72cc8a44dfc8","2dfb7090f66202e471d103164fe902579ecc92e2c46533a647f70e428f67e62d","fcddaf5926337ae67de51bac0421b744a37db4fa9d5b707c48443bcb053747ec",{"version":"126c84b38fb99188436b4c61e4cc5d8008247f687f9ddb5517358f2128c938d6","impliedFormat":99},{"version":"1f3952b74b8c766a2e602a0ba2db19d3d872d00bab4e01746c6b7229c585086c","impliedFormat":99},{"version":"d02858f618f372be74ac6fc803b19fe0e1a1468da517813f450861f7f0ea8097","impliedFormat":1},{"version":"cd4031a2eae33de12cf8af8f97fd20c2d10047e7de9038f4d71e76b730bee127","impliedFormat":1},{"version":"6f41ed944dca7ffcb3d85a71434cd91167cc91ca24967909a79fc6e10f3411bb","impliedFormat":1},"e59a9822b92f980dd40582c3d76ec340518bec6d940d895ddbe5d34aeeef1d83","c64c01b5465eb2604c8e1a565963e405330b91689996f7aceaa567ac190fa356","57658c86bca2bf4c96da6672398de1d4877aa227e1eaa530871e5b8dfa377431","c94846f75b236dff5b452b09d1ad1be784aa4d9c785adb969d850f46a5155479","456fb75a8b3aaa131cb6e448d24cb07b838c3996ab8f5c179562d2c0d282f88e","1ea53af4043fc044b72d5d225b18d372b54d1d0689f6850ec8cbf8697c440fbf","488a2aaa1bd1987136258f7f7c73ec213b36694387116e740a46c9dd76d2a34f","8dc29befb7ae0a041412386fe741024b14b98c13932fcc3c73bbdf606a771425","7b3fe40b13bbee7ccbe80bb6e5828ea08c2713c6e6bd97cd80ac8c5f5f087fa1","0add76eb6e62558db82521a1e61f260d17c90d1ec0f8a03d6fd29296a29063ef","7d73c0a5b9e0d1db8ea20fd45df0d92c18c7c87abdc64e21990ecc535e920075","2bc01da2bf58ce8b7a6e31fbef2904133fbe3289a42dc2cdf8043bbfe1a822ce","4008caf7c04c448551f59fd6d75e846d2c450123ff12e0624da0e5f6ca94ea97","d9dc68a9cc1e248983b336f075d256865f09584a0daba90731cc2974412992e8","caf8cf97bf0321e49f083b4a5d30439bd9898a589ed5c8de9116a2a2d93db080","89a932dc8b2f31cfafba4f35bcedbebbea144157e3585cfeb9a8966f88593a40","e068bcdecff37288ea51f5a0cce254b65ba2f645f613b3c2eb86515f25dd7a50","660acd5bcce51c5942c6fa494fd07e6b597799231fe71836a98fdaed1a75437d","92bb21d4a938204da692abe67f78005be328001614768ddef20d8d1e11aa6c0d","fed28519df08e7d14c61966ce5d54428237d1cad21a5c74fe7bc152f5fbd8400",{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"a356d9a0ba90d10ec6c0fa33386c0b0e2843fd6f0a49513c44f7809926ac25ff","impliedFormat":1},{"version":"812d73aa8a644bba03aa7dc2a4b563679b3c67f8be539d59a0867a7d08bd5b10","impliedFormat":1}],"root":[499,[504,511],[517,536]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true,"target":9},"referencedMap":[[499,1],[247,2],[500,2],[501,3],[502,4],[503,5],[537,2],[539,6],[538,2],[144,7],[145,7],[146,8],[99,9],[147,10],[148,11],[149,12],[94,2],[97,13],[95,2],[96,2],[150,14],[151,15],[152,16],[153,17],[154,18],[155,19],[156,19],[157,20],[158,21],[159,22],[160,23],[100,2],[98,2],[161,24],[162,25],[163,26],[197,27],[164,28],[165,2],[166,29],[167,30],[168,31],[169,32],[170,33],[171,34],[172,35],[173,36],[174,37],[175,37],[176,38],[177,2],[178,39],[179,40],[181,41],[180,42],[182,43],[183,44],[184,45],[185,46],[186,47],[187,48],[188,49],[189,50],[190,51],[191,52],[192,53],[193,54],[194,55],[101,2],[102,2],[103,2],[141,56],[142,2],[143,2],[195,57],[196,58],[201,59],[357,60],[202,61],[200,62],[359,63],[358,64],[198,65],[355,2],[199,66],[83,2],[85,67],[354,60],[265,60],[84,2],[515,68],[516,69],[514,70],[513,71],[512,2],[92,72],[446,73],[451,74],[453,75],[223,76],[251,77],[429,78],[246,79],[234,2],[215,2],[221,2],[419,80],[282,81],[222,2],[388,82],[256,83],[257,84],[353,85],[416,86],[371,87],[423,88],[424,89],[422,90],[421,2],[420,91],[253,92],[224,93],[303,2],[304,94],[219,2],[235,95],[225,96],[287,95],[284,95],[208,95],[249,97],[248,2],[428,98],[438,2],[214,2],[329,99],[330,100],[324,60],[474,2],[332,2],[333,101],[325,102],[480,103],[478,104],[473,2],[415,105],[414,2],[472,106],[326,60],[367,107],[365,108],[475,2],[479,2],[477,109],[476,2],[366,110],[467,111],[470,112],[294,113],[293,114],[292,115],[483,60],[291,116],[276,2],[486,2],[489,2],[488,60],[490,117],[204,2],[425,118],[426,119],[427,120],[237,2],[213,121],[203,2],[345,60],[206,122],[344,123],[343,124],[334,2],[335,2],[342,2],[337,2],[340,125],[336,2],[338,126],[341,127],[339,126],[220,2],[211,2],[212,95],[266,128],[267,129],[264,130],[262,131],[263,132],[259,2],[351,101],[373,101],[445,133],[454,134],[458,135],[432,136],[431,2],[279,2],[491,137],[441,138],[327,139],[328,140],[319,141],[309,2],[350,142],[310,143],[352,144],[347,145],[346,2],[348,2],[364,146],[433,147],[434,148],[312,149],[316,150],[307,151],[411,152],[440,153],[286,154],[389,155],[209,156],[439,157],[205,79],[260,2],[268,158],[400,159],[258,2],[399,160],[93,2],[394,161],[236,2],[305,162],[390,2],[210,2],[269,2],[398,163],[218,2],[274,164],[315,165],[430,166],[314,2],[397,2],[261,2],[402,167],[403,168],[216,2],[405,169],[407,170],[406,171],[239,2],[396,156],[409,172],[395,173],[401,174],[227,2],[230,2],[228,2],[232,2],[229,2],[231,2],[233,175],[226,2],[381,176],[380,2],[386,177],[382,178],[385,179],[384,179],[387,177],[383,178],[273,180],[374,181],[437,182],[493,2],[462,183],[464,184],[311,2],[463,185],[435,147],[492,186],[331,147],[217,2],[313,187],[270,188],[271,189],[272,190],[302,191],[410,191],[288,191],[375,192],[289,192],[255,193],[254,2],[379,194],[378,195],[377,196],[376,197],[436,198],[323,199],[361,200],[322,201],[356,202],[360,203],[418,204],[417,205],[413,206],[370,207],[372,208],[369,209],[408,210],[363,2],[450,2],[362,211],[412,2],[275,212],[308,118],[306,213],[277,214],[280,215],[487,2],[278,216],[281,216],[448,2],[447,2],[449,2],[485,2],[283,217],[321,60],[91,2],[368,218],[252,2],[241,219],[317,2],[456,60],[466,220],[301,60],[460,101],[300,221],[443,222],[299,220],[207,2],[468,223],[297,60],[298,60],[290,2],[240,2],[296,224],[295,225],[238,226],[318,36],[285,36],[404,2],[392,227],[391,2],[452,2],[349,228],[320,60],[444,229],[86,60],[89,230],[90,231],[87,60],[88,2],[250,232],[245,233],[244,2],[243,234],[242,2],[442,235],[455,236],[457,237],[459,238],[461,239],[465,240],[469,241],[498,242],[471,243],[481,244],[482,245],[484,246],[494,247],[497,121],[496,2],[495,248],[393,249],[81,2],[82,2],[13,2],[14,2],[16,2],[15,2],[2,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[23,2],[24,2],[3,2],[25,2],[26,2],[4,2],[27,2],[31,2],[28,2],[29,2],[30,2],[32,2],[33,2],[34,2],[5,2],[35,2],[36,2],[37,2],[38,2],[6,2],[42,2],[39,2],[40,2],[41,2],[43,2],[7,2],[44,2],[49,2],[50,2],[45,2],[46,2],[47,2],[48,2],[8,2],[54,2],[51,2],[52,2],[53,2],[55,2],[9,2],[56,2],[57,2],[58,2],[60,2],[59,2],[61,2],[62,2],[10,2],[63,2],[64,2],[65,2],[11,2],[66,2],[67,2],[68,2],[69,2],[70,2],[1,2],[71,2],[72,2],[12,2],[76,2],[74,2],[79,2],[78,2],[73,2],[77,2],[75,2],[80,2],[119,250],[129,251],[118,250],[139,252],[110,253],[109,254],[138,248],[132,255],[137,256],[112,257],[126,258],[111,259],[135,260],[107,261],[106,248],[136,262],[108,263],[113,264],[114,2],[117,264],[104,2],[140,265],[130,266],[121,267],[122,268],[124,269],[120,270],[123,271],[133,248],[115,272],[116,273],[125,274],[105,275],[128,266],[127,264],[131,2],[134,276],[529,277],[511,278],[525,279],[534,280],[535,281],[508,282],[509,281],[507,283],[536,281],[510,284],[517,285],[526,286],[518,287],[530,288],[519,2],[520,287],[521,287],[531,287],[532,287],[533,287],[527,287],[522,287],[523,60],[528,287],[524,287],[506,289],[504,2],[505,2]],"affectedFilesPendingEmit":[499,529,511,525,534,535,508,509,507,536,510,517,526,518,530,519,520,521,531,532,533,527,522,523,528,524,506,504,505],"version":"5.9.3"}