{
  "version": 3,
  "sources": ["../server.ts"],
  "sourcesContent": ["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport express from \"express\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { createServer as createViteServer } from \"vite\";\nimport { GoogleGenAI } from \"@google/genai\";\nimport \"dotenv/config\";\nimport AdmZip from \"adm-zip\";\n\nlet aiClient: GoogleGenAI | null = null;\n\nfunction getAIClient(): GoogleGenAI {\n  if (!aiClient) {\n    const apiKey = process.env.GEMINI_API_KEY;\n    if (!apiKey) {\n      throw new Error(\"GEMINI_API_KEY environment variable is required\");\n    }\n    aiClient = new GoogleGenAI({\n      apiKey,\n      httpOptions: {\n        headers: {\n          'User-Agent': 'aistudio-build',\n        }\n      }\n    });\n  }\n  return aiClient;\n}\n\ninterface Role {\n  id: string;\n  roleName: string;\n  description: string;\n}\n\ninterface Permission {\n  id: string;\n  permissionKey: string;\n  description: string;\n}\n\ninterface RolePermission {\n  roleId: string;\n  permissionId: string;\n}\n\ninterface User {\n  id: string;\n  username: string;\n  email: string;\n  fullName: string;\n  phone: string;\n  roleId: string;\n  created_at?: string;\n}\n\ninterface Property {\n  id: string;\n  ownerId: string;\n  ownerName: string;\n  name: string;\n  type: 'hotel' | 'villa' | 'apartment' | 'house' | 'kos';\n  address: string;\n  description: string;\n  priceDay?: number;\n  priceMonth?: number;\n  priceBuy?: number;\n  status: 'available' | 'rented' | 'sold';\n  imageUrl: string;\n  createdAt: string;\n  contactPhone?: string;\n  contactEmail?: string;\n  mapEmbedUrl?: string;\n}\n\ninterface Transaction {\n  id: string;\n  buyerId: string;\n  buyerName: string;\n  propertyId: string;\n  propertyName: string;\n  propertyType: string;\n  roomId?: string;\n  roomNumber?: string;\n  type: 'stay' | 'rent' | 'buy';\n  startDate?: string;\n  endDate?: string;\n  totalPrice: number;\n  status: 'pending' | 'paid' | 'cancelled';\n  createdAt: string;\n}\n\nconst DB_FILE = path.join(process.cwd(), \"database.json\");\n\n// Helper to load or initialize DB\nfunction loadDB() {\n  if (fs.existsSync(DB_FILE)) {\n    try {\n      const parsed = JSON.parse(fs.readFileSync(DB_FILE, \"utf-8\"));\n      // Migrasi jika tabel baru belum ada\n      let changed = false;\n      if (!parsed.roles) {\n        parsed.roles = [\n          { id: \"1\", roleName: \"Owner / Host\", description: \"Pengguna yang memiliki, menyewakan, dan menjual properti mereka.\" },\n          { id: \"2\", roleName: \"Guest / Buyer\", description: \"Pengguna yang mencari akomodasi, menginap, menyewa, atau membeli properti.\" },\n          { id: \"3\", roleName: \"System Administrator\", description: \"Pengguna dengan kekuasaan penuh untuk mengelola master data sistem.\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.permissions) {\n        parsed.permissions = [\n          { id: \"1\", permissionKey: \"create_property\", description: \"Mengolah: Membuat Properti Baru\" },\n          { id: \"2\", permissionKey: \"delete_property\", description: \"Mengolah: Menghapus Properti\" },\n          { id: \"3\", permissionKey: \"order_transaction\", description: \"Mengolah: Membuat Transaksi/Pemesanan\" },\n          { id: \"4\", permissionKey: \"view_dashboard\", description: \"Membuka Menu Dashboard Analisis\" },\n          { id: \"5\", permissionKey: \"manage_roles\", description: \"Mengolah: Mengonfigurasi Peran & Izin\" },\n          { id: \"6\", permissionKey: \"edit_property\", description: \"Mengolah: Mengubah Informasi Properti\" },\n          { id: \"7\", permissionKey: \"view_operations\", description: \"Membuka Menu Operations Hub\" },\n          { id: \"8\", permissionKey: \"view_superadmin\", description: \"Membuka Menu Superadmin Console\" },\n          { id: \"9\", permissionKey: \"view_schema\", description: \"Membuka Menu Master Skema MySQL\" },\n          { id: \"10\", permissionKey: \"view_users\", description: \"Membuka Menu Master Pengguna (CRUD)\" },\n          { id: \"11\", permissionKey: \"view_permissions\", description: \"Membuka Menu Master Hak Izin\" },\n          { id: \"12\", permissionKey: \"view_profiling\", description: \"Membuka Menu Profiling & Log Analisis\" },\n          { id: \"13\", permissionKey: \"view_ci3_template\", description: \"Membuka Menu CI3 & AdminLTE Files\" },\n          { id: \"14\", permissionKey: \"view_ai_prediction\", description: \"Membuka Menu Prediksi & Keputusan AI\" },\n          { id: \"15\", permissionKey: \"view_cloud_storage\", description: \"Membuka Menu Cloud Storage Hub\" },\n          { id: \"16\", permissionKey: \"manage_users\", description: \"Mengolah: Menambah/Edit/Hapus Pengguna\" }\n        ];\n        changed = true;\n      } else {\n        // Dynamic migration for existing DB\n        const defaultPermissions = [\n          { id: \"1\", permissionKey: \"create_property\", description: \"Mengolah: Membuat Properti Baru\" },\n          { id: \"2\", permissionKey: \"delete_property\", description: \"Mengolah: Menghapus Properti\" },\n          { id: \"3\", permissionKey: \"order_transaction\", description: \"Mengolah: Membuat Transaksi/Pemesanan\" },\n          { id: \"4\", permissionKey: \"view_dashboard\", description: \"Membuka Menu Dashboard Analisis\" },\n          { id: \"5\", permissionKey: \"manage_roles\", description: \"Mengolah: Mengonfigurasi Peran & Izin\" },\n          { id: \"6\", permissionKey: \"edit_property\", description: \"Mengolah: Mengubah Informasi Properti\" },\n          { id: \"7\", permissionKey: \"view_operations\", description: \"Membuka Menu Operations Hub\" },\n          { id: \"8\", permissionKey: \"view_superadmin\", description: \"Membuka Menu Superadmin Console\" },\n          { id: \"9\", permissionKey: \"view_schema\", description: \"Membuka Menu Master Skema MySQL\" },\n          { id: \"10\", permissionKey: \"view_users\", description: \"Membuka Menu Master Pengguna (CRUD)\" },\n          { id: \"11\", permissionKey: \"view_permissions\", description: \"Membuka Menu Master Hak Izin\" },\n          { id: \"12\", permissionKey: \"view_profiling\", description: \"Membuka Menu Profiling & Log Analisis\" },\n          { id: \"13\", permissionKey: \"view_ci3_template\", description: \"Membuka Menu CI3 & AdminLTE Files\" },\n          { id: \"14\", permissionKey: \"view_ai_prediction\", description: \"Membuka Menu Prediksi & Keputusan AI\" },\n          { id: \"15\", permissionKey: \"view_cloud_storage\", description: \"Membuka Menu Cloud Storage Hub\" },\n          { id: \"16\", permissionKey: \"manage_users\", description: \"Mengolah: Menambah/Edit/Hapus Pengguna\" }\n        ];\n        for (const dp of defaultPermissions) {\n          if (!parsed.permissions.some((p: any) => p.permissionKey === dp.permissionKey)) {\n            // Find unique numerical ID for new permission\n            const maxId = Math.max(...parsed.permissions.map((p: any) => isNaN(Number(p.id)) ? 0 : Number(p.id)), 0);\n            parsed.permissions.push({\n              id: String(maxId + 1),\n              permissionKey: dp.permissionKey,\n              description: dp.description\n            });\n            changed = true;\n          }\n        }\n      }\n      if (!parsed.rolePermissions) {\n        parsed.rolePermissions = [];\n        changed = true;\n      }\n      \n      // Auto-map default role permissions if they are missing\n      const getPermId = (key: string) => {\n        const found = parsed.permissions.find((p: any) => p.permissionKey === key);\n        return found ? found.id : null;\n      };\n\n      const defaultRolePerms = [\n        { roleId: \"1\", permKey: \"create_property\" },\n        { roleId: \"1\", permKey: \"edit_property\" },\n        { roleId: \"1\", permKey: \"delete_property\" },\n        { roleId: \"1\", permKey: \"view_dashboard\" },\n        { roleId: \"1\", permKey: \"view_operations\" },\n        { roleId: \"1\", permKey: \"view_ai_prediction\" },\n        \n        { roleId: \"2\", permKey: \"order_transaction\" },\n\n        { roleId: \"3\", permKey: \"create_property\" },\n        { roleId: \"3\", permKey: \"edit_property\" },\n        { roleId: \"3\", permKey: \"delete_property\" },\n        { roleId: \"3\", permKey: \"order_transaction\" },\n        { roleId: \"3\", permKey: \"view_dashboard\" },\n        { roleId: \"3\", permKey: \"view_operations\" },\n        { roleId: \"3\", permKey: \"view_superadmin\" },\n        { roleId: \"3\", permKey: \"view_schema\" },\n        { roleId: \"3\", permKey: \"view_users\" },\n        { roleId: \"3\", permKey: \"view_permissions\" },\n        { roleId: \"3\", permKey: \"view_profiling\" },\n        { roleId: \"3\", permKey: \"view_ci3_template\" },\n        { roleId: \"3\", permKey: \"view_ai_prediction\" },\n        { roleId: \"3\", permKey: \"view_cloud_storage\" },\n        { roleId: \"3\", permKey: \"manage_roles\" },\n        { roleId: \"3\", permKey: \"manage_users\" }\n      ];\n\n      for (const drp of defaultRolePerms) {\n        const pId = getPermId(drp.permKey);\n        if (pId) {\n          if (!parsed.rolePermissions.some((rp: any) => rp.roleId === drp.roleId && rp.permissionId === pId)) {\n            parsed.rolePermissions.push({ roleId: drp.roleId, permissionId: pId });\n            changed = true;\n          }\n        }\n      }\n      // Ensure users map to roles properly\n      parsed.users = parsed.users.map((u: any) => {\n        if (!u.roleId) {\n          u.roleId = u.role === \"owner\" ? \"1\" : \"2\";\n          changed = true;\n        }\n        return u;\n      });\n\n      if (!parsed.promos) {\n        parsed.promos = [\n          { id: \"p1\", code: \"HEMAT50\", discount: 50000, type: \"coupon\", maxUse: 100, used: 12, description: \"Potongan Rp 50.000 untuk pengguna baru\" },\n          { id: \"p2\", code: \"WEEKENDSERU\", discount: 100000, type: \"promo\", maxUse: 50, used: 8, description: \"Promo khusus akhir pekan hemat Rp 100.000\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.rooms) {\n        parsed.rooms = [\n          {\n            id: \"r1_101\",\n            propertyId: \"1\",\n            roomNumber: \"101\",\n            type: \"Deluxe Twin Room\",\n            priceDay: 750000,\n            status: \"available\",\n            position: \"Lantai 1, Sayap Timur\",\n            facilities: [\"AC\", \"Twin Bed\", \"Free High-speed Wi-Fi\", \"Mini Bar\", \"TV Cable\", \"Safe Deposit Box\"],\n            facing: \"Timur (Sunrise)\",\n            view: \"Taman Kota & Air Terjun Mini\",\n            imageUrl: \"https://images.unsplash.com/photo-1598928506311-c55ded91a20c?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r1_302\",\n            propertyId: \"1\",\n            roomNumber: \"302\",\n            type: \"Executive King Suite\",\n            priceDay: 1250000,\n            status: \"occupied\",\n            position: \"Lantai 3, Sayap Barat\",\n            facilities: [\"AC\", \"King Bed\", \"Smart TV 55 Inch\", \"Bathtub\", \"Sofa Bed\", \"Nespresso Machine\", \"Balcony\"],\n            facing: \"Selatan\",\n            view: \"City Skyline & Kolam Renang Utama\",\n            imageUrl: \"https://images.unsplash.com/photo-1590490360182-c33d57733427?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: [\"2026-06-25 s/d 2026-06-30\"]\n          },\n          {\n            id: \"r1_501\",\n            propertyId: \"1\",\n            roomNumber: \"501\",\n            type: \"Presidential Penthouse\",\n            priceDay: 3500000,\n            status: \"available\",\n            position: \"Lantai 5 (Penthouse)\",\n            facilities: [\"Private Pool\", \"AC Central\", \"Jacuzzi\", \"Smart Kitchen Set\", \"Butler Service 24H\", \"Home Theater\"],\n            facing: \"Barat (Sunset)\",\n            view: \"Sunset & Megapolitan Jakarta View 360\",\n            imageUrl: \"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r2_v01\",\n            propertyId: \"2\",\n            roomNumber: \"V-01\",\n            type: \"One-Bedroom Private Pool Villa\",\n            priceDay: 2500000,\n            status: \"occupied\",\n            position: \"Ground Level, Area Sunset\",\n            facilities: [\"Private Pool\", \"Gazebo\", \"AC\", \"Outdoor Shower\", \"Floating Breakfast\", \"Mini Kitchen\"],\n            facing: \"Timur (Sunrise)\",\n            view: \"Lembah Sawah Hijau & Gunung Agung\",\n            imageUrl: \"https://images.unsplash.com/photo-1582268611958-ebfd161ef9cf?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: [\"2026-07-01 s/d 2026-07-05\"]\n          },\n          {\n            id: \"r2_v02\",\n            propertyId: \"2\",\n            roomNumber: \"V-02\",\n            type: \"Two-Bedroom Family Pool Villa\",\n            priceDay: 4500000,\n            status: \"available\",\n            position: \"Ground Level, Area Sawah\",\n            facilities: [\"Large Pool\", \"Kitchen Set\", \"AC\", \"Living Room\", \"Gazebo\", \"Alat BBQ\", \"Bathtub\"],\n            facing: \"Selatan\",\n            view: \"Taman Tropis & Sungai Campuhan\",\n            imageUrl: \"https://images.unsplash.com/photo-1540518614846-7eded433c457?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r3_2501\",\n            propertyId: \"3\",\n            roomNumber: \"2501\",\n            type: \"Studio Executive Room\",\n            priceDay: 500000,\n            status: \"occupied\",\n            position: \"Lantai 25, Unit Sudut Utara\",\n            facilities: [\"AC\", \"Kitchenette\", \"Smart Lock\", \"Wi-Fi\", \"Washing Machine\", \"Microwave\"],\n            facing: \"Utara\",\n            view: \"Bundaran HI & MRT Station\",\n            imageUrl: \"https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: [\"2026-05-01 s/d 2026-09-01\"]\n          },\n          {\n            id: \"r3_2502\",\n            propertyId: \"3\",\n            roomNumber: \"2502\",\n            type: \"Two-Bedroom Premium Corner\",\n            priceDay: 950000,\n            status: \"available\",\n            position: \"Lantai 25, Unit Sudut Barat\",\n            facilities: [\"AC\", \"Balcony\", \"Bathtub\", \"Kitchen Set\", \"Smart Home\", \"Smart TV 65 Inch\"],\n            facing: \"Barat (Sunset)\",\n            view: \"Sunset & SCBD Skylines\",\n            imageUrl: \"https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r4_a12\",\n            propertyId: \"4\",\n            roomNumber: \"A-12 Utama\",\n            type: \"Kamar Tidur Utama (Master Bedroom)\",\n            priceDay: 400000,\n            status: \"available\",\n            position: \"Lantai 2\",\n            facilities: [\"AC\", \"Ensuite Bathroom\", \"Balkon Pribadi\", \"Walk-in Closet\", \"King Bed\"],\n            facing: \"Utara\",\n            view: \"Taman Cluster & Boulevard\",\n            imageUrl: \"https://images.unsplash.com/photo-1505691938895-1758d7feb511?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r4_a12b\",\n            propertyId: \"4\",\n            roomNumber: \"A-12 Anak\",\n            type: \"Kamar Tidur Anak (Second Bedroom)\",\n            priceDay: 250000,\n            status: \"available\",\n            position: \"Lantai 2\",\n            facilities: [\"Kipas Angin\", \"Single Bed\", \"Meja Belajar\", \"Wardrobe\"],\n            facing: \"Selatan\",\n            view: \"Halaman Belakang & Gazebo\",\n            imageUrl: \"https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r5_k10\",\n            propertyId: \"5\",\n            roomNumber: \"Kamar 10\",\n            type: \"Standard Single Room\",\n            priceDay: 100000,\n            status: \"available\",\n            position: \"Lantai 1\",\n            facilities: [\"AC\", \"Kamar Mandi Dalam\", \"Meja Belajar\", \"Wi-Fi\", \"Single Bed\"],\n            facing: \"Barat\",\n            view: \"Koridor Hijau & Kebun Mini\",\n            imageUrl: \"https://images.unsplash.com/photo-1522771739844-6a9f6d5f14af?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: []\n          },\n          {\n            id: \"r5_k12\",\n            propertyId: \"5\",\n            roomNumber: \"Kamar 12\",\n            type: \"Deluxe Balcony Room\",\n            priceDay: 150000,\n            status: \"occupied\",\n            position: \"Lantai 2\",\n            facilities: [\"AC\", \"Kamar Mandi Dalam\", \"Water Heater\", \"Balkon Pribadi\", \"Smart TV 32 Inch\", \"Queen Bed\"],\n            facing: \"Timur (Sunrise)\",\n            view: \"Kampus ITB & Gunung Tangkuban Perahu\",\n            imageUrl: \"https://images.unsplash.com/photo-1598928506311-c55ded91a20c?auto=format&fit=crop&w=600&q=80\",\n            bookedDates: [\"2026-06-15 s/d 2026-12-15\"]\n          }\n        ];\n        changed = true;\n      }\n      if (!parsed.advertisements) {\n        parsed.advertisements = [\n          { id: \"ad1\", title: \"Diskon 20% Akhir Bulan di Ubud Paradise Villa!\", imageUrl: \"https://images.unsplash.com/photo-1580587771525-78b9dba3b914?auto=format&fit=crop&w=800&q=80\", link: \"#\", section: \"sidebar\", status: \"active\" },\n          { id: \"ad2\", title: \"Sudirman Suites: Hunian Premium di Jantung Bisnis Jakarta\", imageUrl: \"https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?auto=format&fit=crop&w=800&q=80\", link: \"#\", section: \"banner\", status: \"active\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.buildings) {\n        parsed.buildings = [\n          { id: \"b1\", name: \"Gedung A (Main Tower)\", floors: 12, address: \"Jl. Rasuna Said Kav 1, Jakarta\", unitCount: 120 },\n          { id: \"b2\", name: \"Paviliun Sunset Ubud\", floors: 2, address: \"Jl. Raya Campuhan, Ubud, Bali\", unitCount: 8 }\n        ];\n        changed = true;\n      }\n      if (!parsed.facilities) {\n        parsed.facilities = [\n          { id: \"f1\", name: \"Kolam Renang Infinity\", type: \"Rekreasi\", status: \"Aktif\", location: \"Lantai 3 Tower A\" },\n          { id: \"f2\", name: \"Gym & Fitness Center\", type: \"Kesehatan\", status: \"Maintenance\", location: \"Lantai Dasar Gedung Utama\" },\n          { id: \"f3\", name: \"Lounge & Coworking Space\", type: \"Bisnis\", status: \"Aktif\", location: \"Lantai Penthouse\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.payments) {\n        parsed.payments = [\n          { id: \"pay1\", transactionId: \"101\", propertyName: \"Grand Melia Hotel\", totalAmount: 1500000, amountPaid: 500000, paymentMethod: \"Bank Transfer - Mandiri\", type: \"DP\", status: \"paid\", dueDate: \"2026-06-30\", notes: \"Pembayaran uang muka menginap 2 malam.\" },\n          { id: \"pay2\", transactionId: \"102\", propertyName: \"Sudirman Suites Apartment\", totalAmount: 8500000, amountPaid: 8500000, paymentMethod: \"Credit Card\", type: \"lunas\", status: \"paid\", dueDate: \"2026-07-28\", notes: \"Pembayaran lunas sewa bulan Agustus.\" },\n          { id: \"pay3\", transactionId: \"103\", propertyName: \"Ubud Paradise Villa\", totalAmount: 2500000, amountPaid: 0, paymentMethod: \"E-Wallet (OVO)\", type: \"lunas\", status: \"pending\", dueDate: \"2026-07-01\", notes: \"Tagihan belum dibayar untuk booking Juli.\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.guestCycles) {\n        parsed.guestCycles = [\n          { id: \"gc1\", guestName: \"Ani Wijaya (Guest)\", propertyName: \"Grand Melia Hotel\", roomNumber: \"302\", status: \"Checked In\", checkInTime: \"2026-06-25 14:00\", checkOutTime: \"-\" },\n          { id: \"gc2\", guestName: \"Budi Hartono\", propertyName: \"Ubud Paradise Villa\", roomNumber: \"V-01\", status: \"Reserved\", checkInTime: \"2026-07-01 14:00\", checkOutTime: \"-\" },\n          { id: \"gc3\", guestName: \"Dedi Setiawan\", propertyName: \"Sudirman Suites Apartment\", roomNumber: \"2501\", status: \"Checked Out\", checkInTime: \"2026-05-01 10:00\", checkOutTime: \"2026-06-01 12:00\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.complaints) {\n        parsed.complaints = [\n          { id: \"c1\", guestName: \"Ani Wijaya (Guest)\", propertyName: \"Grand Melia Hotel\", title: \"AC Kamar Kurang Dingin\", description: \"AC di kamar 302 mengeluarkan suara bising dan tidak terlalu dingin meski suhu sudah diset ke 18C.\", category: \"Fasilitas\", priority: \"High\", status: \"in_progress\", resolution: \"Teknisi sedang melakukan pengecekan freon.\", createdAt: \"2026-06-25 15:30\" },\n          { id: \"c2\", guestName: \"Rian Kusuma\", propertyName: \"Sudirman Suites Apartment\", title: \"Wi-Fi Terputus\", description: \"Koneksi internet di kamar 2501 tidak bisa terhubung sejak tadi malam.\", category: \"Layanan\", priority: \"Medium\", status: \"resolved\", resolution: \"Dilakukan restart router dan konfigurasi ulang IP oleh tim IT. Selesai.\", createdAt: \"2026-06-24 09:15\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.logs) {\n        parsed.logs = [\n          { id: \"l1\", type: \"user\", message: \"User budi_owner mengunggah properti baru: Kost Exclusive D`Green.\", user: \"Budi Hartono\", timestamp: \"2026-06-25 11:30\" },\n          { id: \"l2\", type: \"system\", message: \"Sinkronisasi database.json berhasil dilakukan.\", user: \"System\", timestamp: \"2026-06-26 01:00\" },\n          { id: \"l3\", type: \"app\", message: \"Pembayaran Transaksi #101 berhasil diverifikasi melalui Midtrans gateway.\", user: \"System Gateway\", timestamp: \"2026-06-25 14:15\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.maintenances) {\n        parsed.maintenances = [\n          { id: \"m1\", propertyId: \"1\", propertyName: \"Grand Melia Hotel\", assetName: \"Lift Utama Tower Barat\", issue: \"Pintu lift sering tersendat saat menutup\", type: \"preventive\", status: \"scheduled\", cost: 1500000, createdAt: \"2026-06-25 10:00\" },\n          { id: \"m2\", propertyId: \"3\", propertyName: \"Sudirman Suites Apartment\", assetName: \"Genset Cadangan\", issue: \"Kerusakan modul aki starter genset utama\", type: \"corrective\", status: \"in_progress\", cost: 4500000, createdAt: \"2026-06-24 08:30\" },\n          { id: \"m3\", propertyId: \"5\", propertyName: \"Kost Exclusive D`Green\", assetName: \"Pompa Air Sumur Bor\", issue: \"Deteksi getaran abnormal pada motor pompa air\", type: \"predictive\", status: \"pending\", cost: 800000, createdAt: \"2026-06-26 09:00\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.apiKeys) {\n        parsed.apiKeys = [\n          { id: \"k1\", name: \"Internal Web App Client Key\", key: \"sh_live_rw_8df839c\", permissions: \"all\", status: \"active\", createdAt: \"2026-06-25 10:00\" },\n          { id: \"k2\", name: \"Mobile App Android/iOS SDK\", key: \"sh_live_ro_9e27bf8\", permissions: \"read-only\", status: \"active\", createdAt: \"2026-06-26 12:30\" }\n        ];\n        changed = true;\n      }\n      if (!parsed.webhooks) {\n        parsed.webhooks = [\n          { id: \"w1\", name: \"CRM Telegram Notification Webhook\", url: \"https://api.telegram.org/bot682910/sendMessage\", secret: \"whsec_tg_bot_abcd123\", events: [\"check_out\", \"maintenance_started\"], status: \"active\", createdAt: \"2026-06-25 10:15\" },\n          { id: \"w2\", name: \"Main ERP Sync Server\", url: \"https://httpbin.org/post\", secret: \"whsec_erp_sync_efgh456\", events: [\"check_in\", \"check_out\", \"cleaning_completed\", \"maintenance_completed\"], status: \"inactive\", createdAt: \"2026-06-26 15:45\" }\n        ];\n        changed = true;\n      }\n\n      if (parsed.properties) {\n        parsed.properties = parsed.properties.map((p: any) => {\n          let updated = false;\n          if (!p.contactPhone) {\n            if (p.id === \"1\") p.contactPhone = \"021-5268080\";\n            else if (p.id === \"2\") p.contactPhone = \"0361-975555\";\n            else if (p.id === \"3\") p.contactPhone = \"021-2525566\";\n            else if (p.id === \"4\") p.contactPhone = \"0812-3456-7890\";\n            else if (p.id === \"5\") p.contactPhone = \"0811-2222-3333\";\n            else p.contactPhone = \"0812-9999-8888\";\n            updated = true;\n          }\n          if (!p.contactEmail) {\n            if (p.id === \"1\") p.contactEmail = \"info@grandmeliajakarta.com\";\n            else if (p.id === \"2\") p.contactEmail = \"stay@ubudparadise.com\";\n            else if (p.id === \"3\") p.contactEmail = \"management@sudirmansuites.com\";\n            else if (p.id === \"4\") p.contactEmail = \"sales@lavendercluster.com\";\n            else if (p.id === \"5\") p.contactEmail = \"dgreen@kostbandung.com\";\n            else p.contactEmail = \"kontak@sewabelipro.com\";\n            updated = true;\n          }\n          if (!p.mapEmbedUrl) {\n            p.mapEmbedUrl = `https://maps.google.com/maps?q=${encodeURIComponent(p.address)}&t=&z=15&ie=UTF8&iwloc=&output=embed`;\n            updated = true;\n          }\n          if (updated) changed = true;\n          return p;\n        });\n      }\n\n      if (changed) {\n        saveDB(parsed);\n      }\n      return parsed;\n    } catch (e) {\n      console.error(\"Error reading database file, resetting...\", e);\n    }\n  }\n\n  // Initial Seeding data matching the database.sql design\n  const initialData = {\n    roles: [\n      { id: \"1\", roleName: \"Owner / Host\", description: \"Pengguna yang memiliki, menyewakan, dan menjual properti mereka.\" },\n      { id: \"2\", roleName: \"Guest / Buyer\", description: \"Pengguna yang mencari akomodasi, menginap, menyewa, atau membeli properti.\" },\n      { id: \"3\", roleName: \"System Administrator\", description: \"Pengguna dengan kekuasaan penuh untuk mengelola master data sistem.\" }\n    ],\n    permissions: [\n      { id: \"1\", permissionKey: \"create_property\", description: \"Mendaftarkan dan memasarkan properti baru\" },\n      { id: \"2\", permissionKey: \"delete_property\", description: \"Menghapus properti milik sendiri\" },\n      { id: \"3\", permissionKey: \"order_transaction\", description: \"Melakukan transaksi/pemesanan properti\" },\n      { id: \"4\", permissionKey: \"view_dashboard\", description: \"Melihat grafik statistik pendapatan\" },\n      { id: \"5\", permissionKey: \"manage_roles\", description: \"Mengonfigurasi peran & perizinan sistem\" }\n    ],\n    rolePermissions: [\n      { roleId: \"1\", permissionId: \"1\" },\n      { roleId: \"1\", permissionId: \"2\" },\n      { roleId: \"1\", permissionId: \"4\" },\n      { roleId: \"2\", permissionId: \"3\" },\n      { roleId: \"3\", permissionId: \"1\" },\n      { roleId: \"3\", permissionId: \"2\" },\n      { roleId: \"3\", permissionId: \"3\" },\n      { roleId: \"3\", permissionId: \"4\" },\n      { roleId: \"3\", permissionId: \"5\" }\n    ],\n    users: [\n      {\n        id: \"1\",\n        username: \"budi_owner\",\n        email: \"budi@owner.com\",\n        fullName: \"Budi Hartono (Owner)\",\n        phone: \"08123456789\",\n        roleId: \"1\"\n      },\n      {\n        id: \"2\",\n        username: \"ani_guest\",\n        email: \"ani@guest.com\",\n        fullName: \"Ani Wijaya (Guest)\",\n        phone: \"08987654321\",\n        roleId: \"2\"\n      },\n      {\n        id: \"3\",\n        username: \"admin_hub\",\n        email: \"admin@hub.com\",\n        fullName: \"Super Admin (SewaBeliPro)\",\n        phone: \"08111222333\",\n        roleId: \"3\"\n      },\n      {\n        id: \"7\",\n        username: \"admin_all\",\n        email: \"admin_all@hub.com\",\n        fullName: \"Admin Konsolidasi Utama (admin_all)\",\n        phone: \"08111222999\",\n        roleId: \"3\"\n      }\n    ],\n    properties: [\n      {\n        id: \"1\",\n        ownerId: \"1\",\n        ownerName: \"Budi Hartono (Owner)\",\n        name: \"Grand Melia Hotel\",\n        type: \"hotel\",\n        address: \"Jl. Rasuna Said Kav 1, Jakarta\",\n        description: \"Hotel bintang 5 mewah di pusat bisnis Jakarta dengan fasilitas kolam renang, spa, restoran gourmet, dan akses mudah ke pusat perkantoran.\",\n        priceDay: 750000,\n        status: \"available\",\n        imageUrl: \"https://images.unsplash.com/photo-1566073771259-6a8506099945?auto=format&fit=crop&w=800&q=80\",\n        createdAt: new Date().toISOString()\n      },\n      {\n        id: \"2\",\n        ownerId: \"1\",\n        ownerName: \"Budi Hartono (Owner)\",\n        name: \"Ubud Paradise Villa\",\n        type: \"villa\",\n        address: \"Jl. Raya Campuhan, Ubud, Bali\",\n        description: \"Villa asri dengan private pool, gazebo, dan pemandangan langsung ke lembah sawah hijau Ubud yang menenangkan.\",\n        priceDay: 2500000,\n        status: \"available\",\n        imageUrl: \"https://images.unsplash.com/photo-1580587771525-78b9dba3b914?auto=format&fit=crop&w=800&q=80\",\n        createdAt: new Date().toISOString()\n      },\n      {\n        id: \"3\",\n        ownerId: \"1\",\n        ownerName: \"Budi Hartono (Owner)\",\n        name: \"Sudirman Suites Apartment\",\n        type: \"apartment\",\n        address: \"Jl. Jend Sudirman No. 21, Jakarta\",\n        description: \"Apartemen mewah di lantai 25, fully furnished dengan kitchen set lengkap, smart home system, dan tepat di samping stasiun MRT.\",\n        priceMonth: 8500000,\n        priceBuy: 1800000000,\n        status: \"available\",\n        imageUrl: \"https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?auto=format&fit=crop&w=800&q=80\",\n        createdAt: new Date().toISOString()\n      },\n      {\n        id: \"4\",\n        ownerId: \"1\",\n        ownerName: \"Budi Hartono (Owner)\",\n        name: \"Cluster Minimalis Lavender\",\n        type: \"house\",\n        address: \"Perumahan Lavanya Blok B4, Tangerang Selatan\",\n        description: \"Rumah tinggal modern minimalis 2 lantai di dalam cluster satu gerbang (one gate system). Memiliki 3 kamar tidur dan 2 kamar mandi.\",\n        priceBuy: 1250000000,\n        status: \"available\",\n        imageUrl: \"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=800&q=80\",\n        createdAt: new Date().toISOString()\n      },\n      {\n        id: \"5\",\n        ownerId: \"1\",\n        ownerName: \"Budi Hartono (Owner)\",\n        name: \"Kost Exclusive D`Green\",\n        type: \"kos\",\n        address: \"Jl. Ganesha No. 10, Bandung\",\n        description: \"Kost mahasiswa dan pekerja profesional exclusive dekat kampus ITB. Sudah termasuk fasilitas AC, kamar mandi dalam, air panas, high-speed Wi-Fi, dan parkir luas.\",\n        priceMonth: 1800000,\n        status: \"available\",\n        imageUrl: \"https://images.unsplash.com/photo-1522771739844-6a9f6d5f14af?auto=format&fit=crop&w=800&q=80\",\n        createdAt: new Date().toISOString()\n      }\n    ],\n    transactions: [\n      {\n        id: \"101\",\n        buyerId: \"2\",\n        buyerName: \"Ani Wijaya (Guest)\",\n        propertyId: \"1\",\n        propertyName: \"Grand Melia Hotel\",\n        propertyType: \"hotel\",\n        type: \"stay\",\n        startDate: \"2026-07-01\",\n        endDate: \"2026-07-03\",\n        totalPrice: 1500000,\n        status: \"paid\",\n        createdAt: new Date().toISOString()\n      },\n      {\n        id: \"102\",\n        buyerId: \"2\",\n        buyerName: \"Ani Wijaya (Guest)\",\n        propertyId: \"3\",\n        propertyName: \"Sudirman Suites Apartment\",\n        propertyType: \"apartment\",\n        type: \"rent\",\n        startDate: \"2026-08-01\",\n        endDate: \"2026-09-01\",\n        totalPrice: 8500000,\n        status: \"paid\",\n        createdAt: new Date().toISOString()\n      }\n    ]\n  };\n\n  fs.writeFileSync(DB_FILE, JSON.stringify(initialData, null, 2), \"utf-8\");\n  return initialData;\n}\n\nfunction saveDB(data: any) {\n  fs.writeFileSync(DB_FILE, JSON.stringify(data, null, 2), \"utf-8\");\n}\n\n// Helper to resolve user with dynamic role & permissions list\nfunction resolveUserRBAC(user: any, db: any) {\n  const role = db.roles.find((r: any) => r.id === user.roleId) || { id: \"2\", roleName: \"Guest / Buyer\", description: \"\" };\n  const rpMappings = db.rolePermissions.filter((rp: any) => rp.roleId === role.id);\n  const permissionIds = rpMappings.map((rp: any) => rp.permissionId);\n  const activePermissions = db.permissions\n    .filter((p: any) => permissionIds.includes(p.id))\n    .map((p: any) => p.permissionKey);\n\n  let roleFlag: 'owner' | 'guest' | 'superadmin' | 'admin' = \"guest\";\n  if (role.id === \"1\") roleFlag = \"owner\";\n  else if (role.id === \"2\") roleFlag = \"guest\";\n  else if (role.id === \"3\") roleFlag = \"superadmin\";\n  else if (role.id === \"4\") roleFlag = \"admin\";\n\n  return {\n    ...user,\n    roleName: role.roleName,\n    role: roleFlag,\n    permissions: activePermissions\n  };\n}\n\nasync function startServer() {\n  const app = express();\n  const PORT = 3000;\n\n  app.use(express.json());\n\n  // Init DB\n  loadDB();\n\n  // Helper to extract device, IP, and location from request\n  function getLogMeta(req: express.Request) {\n    let ip = (req.headers[\"x-forwarded-for\"] as string || \"\").split(\",\")[0].trim() || req.ip || req.socket.remoteAddress || \"127.0.0.1\";\n    if (ip === \"::1\" || ip === \"::ffff:127.0.0.1\") {\n      ip = \"127.0.0.1\";\n    }\n\n    const ua = req.headers[\"user-agent\"] || \"\";\n    let device = \"Desktop Browser\";\n    if (/mobile/i.test(ua)) {\n      if (/iphone|ipad|ipod/i.test(ua)) device = \"iPhone / iOS\";\n      else if (/android/i.test(ua)) device = \"Android Mobile\";\n      else device = \"Mobile Device\";\n    } else if (/windows/i.test(ua)) {\n      device = \"Windows PC\";\n    } else if (/macintosh/i.test(ua)) {\n      device = \"MacBook / macOS\";\n    } else if (/linux/i.test(ua)) {\n      device = \"Linux OS\";\n    } else if (ua) {\n      device = ua.substring(0, 30);\n    }\n\n    let location = \"Jakarta, Indonesia\";\n    const geoCountry = req.headers[\"cf-ipcountry\"] || req.headers[\"x-appengine-country\"] || req.headers[\"x-client-geo-country\"];\n    const geoCity = req.headers[\"x-client-geo-city\"] || req.headers[\"x-appengine-city\"];\n    if (geoCountry) {\n      location = geoCity ? `${geoCity}, ${geoCountry}` : String(geoCountry);\n    } else if (ip !== \"127.0.0.1\" && !ip.startsWith(\"172.\") && !ip.startsWith(\"192.168.\")) {\n      const randomLocs = [\"Jakarta, Indonesia\", \"Surabaya, Indonesia\", \"Medan, Indonesia\", \"Bandung, Indonesia\", \"Singapore\", \"Semarang, Indonesia\"];\n      let hash = 0;\n      for (let i = 0; i < ip.length; i++) {\n        hash = ip.charCodeAt(i) + ((hash << 5) - hash);\n      }\n      const index = Math.abs(hash) % randomLocs.length;\n      location = randomLocs[index];\n    }\n\n    return { ip, device, location };\n  }\n\n  // Centralized helper to push new logs with device/IP/location\n  function addSystemLog(db: any, type: string, message: string, user?: string, req?: express.Request) {\n    db.logs = db.logs || [];\n    \n    let ip = \"127.0.0.1\";\n    let device = \"Server Core\";\n    let location = \"Jakarta, Indonesia\";\n\n    if (req) {\n      const meta = getLogMeta(req);\n      ip = meta.ip;\n      device = meta.device;\n      location = meta.location;\n    }\n\n    db.logs.push({\n      id: \"log_\" + Date.now() + \"_\" + Math.floor(Math.random() * 1000),\n      type: type || \"app\",\n      message,\n      user: user || \"System\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),\n      ip,\n      device,\n      location\n    });\n\n    if (db.logs.length > 250) {\n      db.logs = db.logs.slice(db.logs.length - 250);\n    }\n  }\n\n  // Middleware to log API requests automatically\n  app.use((req, res, next) => {\n    if (req.originalUrl.startsWith(\"/api\") && !req.originalUrl.startsWith(\"/api/logs\")) {\n      const start = Date.now();\n      res.on(\"finish\", () => {\n        const duration = Date.now() - start;\n        const db = loadDB();\n        \n        const message = `[API REQUEST] ${req.method} ${req.originalUrl} - Status: ${res.statusCode} (${duration}ms)`;\n        const userAgent = req.headers[\"user-agent\"] ? req.headers[\"user-agent\"].substring(0, 30) : \"Client App\";\n        \n        addSystemLog(db, \"api\", message, userAgent, req);\n        saveDB(db);\n      });\n    }\n    next();\n  });\n\n  // Helper untuk membuat notifikasi dan merekam simulasi kirim email & WA\n  function createAndSimulateNotification(db: any, userId: string, title: string, message: string, type: string) {\n    db.notifications = db.notifications || [];\n    const user = db.users.find((u: any) => u.id === String(userId));\n    const emailAddress = user ? user.email : \"user@example.com\";\n    const phoneNumber = user ? user.phone : \"08123456789\";\n    const userFullName = user ? user.fullName : \"Pengguna\";\n\n    const notifId = \"n_\" + Date.now() + \"_\" + Math.floor(Math.random() * 1000);\n    const newNotif = {\n      id: notifId,\n      userId: String(userId),\n      title,\n      message,\n      type,\n      read: false,\n      channels: {\n        email: {\n          sent: true,\n          address: emailAddress,\n          subject: `[SewaBeliPro] ${title}`\n        },\n        whatsapp: {\n          sent: true,\n          phone: phoneNumber,\n          message: `Halo ${userFullName}, pemberitahuan dari SewaBeliPro: ${message}`\n        }\n      },\n      createdAt: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    };\n\n    db.notifications.push(newNotif);\n\n    // Rekam log aplikasi untuk melacak simulasi pengiriman email & WhatsApp\n    db.logs = db.logs || [];\n    db.logs.push({\n      id: \"log_\" + Date.now() + \"_notif_\" + Math.floor(Math.random() * 1000),\n      type: \"app\",\n      message: `[NOTIFIKASI SIMULASI] Kirim Email ke <${emailAddress}> & WhatsApp ke [${phoneNumber}] untuk: \"${title}\".`,\n      user: \"System Notifier\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    return newNotif;\n  }\n\n  // --------------------------------------------------------\n  // API: USER MANAGEMENT (RBAC) - Users, Roles, Permissions\n  // --------------------------------------------------------\n  \n  // Get all users with their resolved RBAC structures\n  app.get(\"/api/users\", (req, res) => {\n    const db = loadDB();\n    const resolvedUsers = db.users.map((u: User) => resolveUserRBAC(u, db));\n    res.json(resolvedUsers);\n  });\n\n  // Assign role to user\n  app.put(\"/api/users/:id/role\", (req, res) => {\n    const { id } = req.params;\n    const { roleId } = req.body;\n    if (!roleId) {\n      return res.status(400).json({ error: \"Kolom roleId wajib ditentukan!\" });\n    }\n\n    const db = loadDB();\n    const user = db.users.find((u: User) => u.id === id);\n    if (!user) {\n      return res.status(404).json({ error: \"Pengguna tidak ditemukan!\" });\n    }\n\n    const roleExists = db.roles.some((r: Role) => r.id === roleId);\n    if (!roleExists) {\n      return res.status(400).json({ error: \"Role ID tidak valid!\" });\n    }\n\n    user.roleId = roleId;\n    saveDB(db);\n\n    res.json({ message: \"Role pengguna berhasil diperbarui!\", user: resolveUserRBAC(user, db) });\n  });\n\n  // Create a new user (CRUD)\n  app.post(\"/api/users\", (req, res) => {\n    const { username, email, fullName, phone, roleId, propertyId } = req.body;\n    if (!username || !email || !fullName || !phone || !roleId) {\n      return res.status(400).json({ error: \"Lengkapi semua data wajib pengguna (Username, Email, Nama, No. HP, Peran)!\" });\n    }\n\n    const db = loadDB();\n    if (db.users.some((u: any) => u.username.toLowerCase() === username.toLowerCase() || u.email.toLowerCase() === email.toLowerCase())) {\n      return res.status(400).json({ error: \"Username atau email sudah digunakan oleh pengguna lain!\" });\n    }\n\n    const newUser = {\n      id: \"u_\" + Date.now(),\n      username,\n      email,\n      fullName,\n      phone,\n      roleId,\n      propertyId: propertyId || undefined\n    };\n\n    db.users.push(newUser);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Pengguna baru berhasil dibuat!\", user: resolveUserRBAC(newUser, db) });\n  });\n\n  // Update general user fields (CRUD)\n  app.put(\"/api/users/:id\", (req, res) => {\n    const { id } = req.params;\n    const { username, email, fullName, phone, roleId, propertyId } = req.body;\n    if (!username || !email || !fullName || !phone || !roleId) {\n      return res.status(400).json({ error: \"Lengkapi semua data wajib pengguna!\" });\n    }\n\n    const db = loadDB();\n    const userIndex = db.users.findIndex((u: any) => u.id === id);\n    if (userIndex === -1) {\n      return res.status(404).json({ error: \"Pengguna tidak ditemukan!\" });\n    }\n\n    if (db.users.some((u: any) => u.id !== id && (u.username.toLowerCase() === username.toLowerCase() || u.email.toLowerCase() === email.toLowerCase()))) {\n      return res.status(400).json({ error: \"Username atau email sudah digunakan oleh pengguna lain!\" });\n    }\n\n    db.users[userIndex] = {\n      ...db.users[userIndex],\n      username,\n      email,\n      fullName,\n      phone,\n      roleId,\n      propertyId: propertyId || undefined\n    };\n\n    saveDB(db);\n    res.json({ message: \"Data pengguna berhasil diperbarui!\", user: resolveUserRBAC(db.users[userIndex], db) });\n  });\n\n  // Delete a user (CRUD)\n  app.delete(\"/api/users/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    const userExists = db.users.some((u: any) => u.id === id);\n    if (!userExists) {\n      return res.status(404).json({ error: \"Pengguna tidak ditemukan!\" });\n    }\n\n    db.users = db.users.filter((u: any) => u.id !== id);\n    saveDB(db);\n    res.json({ message: \"Pengguna berhasil dihapus!\" });\n  });\n\n  // Create a new role (CRUD)\n  app.post(\"/api/roles\", (req, res) => {\n    const { roleName, description } = req.body;\n    if (!roleName || !description) {\n      return res.status(400).json({ error: \"Nama peran (roleName) dan deskripsi wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    if (db.roles.some((r: any) => r.roleName.toLowerCase() === roleName.toLowerCase())) {\n      return res.status(400).json({ error: \"Nama peran sudah terdaftar!\" });\n    }\n\n    const newRole = {\n      id: \"r_\" + Date.now(),\n      roleName,\n      description\n    };\n\n    db.roles.push(newRole);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Peran baru berhasil ditambahkan!\", role: newRole });\n  });\n\n  // Update role (CRUD)\n  app.put(\"/api/roles/:id\", (req, res) => {\n    const { id } = req.params;\n    const { roleName, description } = req.body;\n    if (!roleName || !description) {\n      return res.status(400).json({ error: \"Nama peran dan deskripsi wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    const roleIndex = db.roles.findIndex((r: any) => r.id === id);\n    if (roleIndex === -1) {\n      return res.status(404).json({ error: \"Peran tidak ditemukan!\" });\n    }\n\n    if (db.roles.some((r: any) => r.id !== id && r.roleName.toLowerCase() === roleName.toLowerCase())) {\n      return res.status(400).json({ error: \"Nama peran sudah digunakan!\" });\n    }\n\n    db.roles[roleIndex] = {\n      ...db.roles[roleIndex],\n      roleName,\n      description\n    };\n\n    saveDB(db);\n    res.json({ message: \"Peran berhasil diperbarui!\", role: db.roles[roleIndex] });\n  });\n\n  // Delete a role (CRUD)\n  app.delete(\"/api/roles/:id\", (req, res) => {\n    const { id } = req.params;\n    if ([\"1\", \"2\", \"3\", \"4\"].includes(id)) {\n      return res.status(400).json({ error: \"Peran bawaan sistem (default roles: Owner, Guest, Superadmin, Admin) tidak boleh dihapus demi kestabilan sistem!\" });\n    }\n\n    const db = loadDB();\n    const roleExists = db.roles.some((r: any) => r.id === id);\n    if (!roleExists) {\n      return res.status(404).json({ error: \"Peran tidak ditemukan!\" });\n    }\n\n    db.roles = db.roles.filter((r: any) => r.id !== id);\n    // clean up permissions mapping for this role\n    db.rolePermissions = db.rolePermissions.filter((rp: any) => rp.roleId !== id);\n\n    // switch users with deleted role back to Guest role \"2\"\n    db.users.forEach((u: any) => {\n      if (u.roleId === id) {\n        u.roleId = \"2\";\n      }\n    });\n\n    saveDB(db);\n    res.json({ message: \"Peran berhasil dihapus, dan pengguna dengan peran ini dialihkan ke Guest!\" });\n  });\n\n  // Create a new permission (CRUD)\n  app.post(\"/api/permissions\", (req, res) => {\n    const { permissionKey, description } = req.body;\n    if (!permissionKey || !description) {\n      return res.status(400).json({ error: \"Key izin (permissionKey) dan deskripsi wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    const normalizedKey = permissionKey.toUpperCase().trim().replace(/\\s+/g, '_');\n    if (db.permissions.some((p: any) => p.permissionKey === normalizedKey)) {\n      return res.status(400).json({ error: \"Key izin sudah terdaftar!\" });\n    }\n\n    const newPermission = {\n      id: \"p_\" + Date.now(),\n      permissionKey: normalizedKey,\n      description\n    };\n\n    db.permissions.push(newPermission);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Hak izin baru berhasil ditambahkan!\", permission: newPermission });\n  });\n\n  // Update permission (CRUD)\n  app.put(\"/api/permissions/:id\", (req, res) => {\n    const { id } = req.params;\n    const { permissionKey, description } = req.body;\n    if (!permissionKey || !description) {\n      return res.status(400).json({ error: \"Key izin dan deskripsi wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    const permIndex = db.permissions.findIndex((p: any) => p.id === id);\n    if (permIndex === -1) {\n      return res.status(404).json({ error: \"Hak izin tidak ditemukan!\" });\n    }\n\n    const normalizedKey = permissionKey.toUpperCase().trim().replace(/\\s+/g, '_');\n    if (db.permissions.some((p: any) => p.id !== id && p.permissionKey === normalizedKey)) {\n      return res.status(400).json({ error: \"Key izin sudah terdaftar untuk izin lain!\" });\n    }\n\n    db.permissions[permIndex] = {\n      ...db.permissions[permIndex],\n      permissionKey: normalizedKey,\n      description\n    };\n\n    saveDB(db);\n    res.json({ message: \"Hak izin berhasil diperbarui!\", permission: db.permissions[permIndex] });\n  });\n\n  // Delete permission (CRUD)\n  app.delete(\"/api/permissions/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    const permExists = db.permissions.some((p: any) => p.id === id);\n    if (!permExists) {\n      return res.status(404).json({ error: \"Hak izin tidak ditemukan!\" });\n    }\n\n    db.permissions = db.permissions.filter((p: any) => p.id !== id);\n    // clean up role relationships\n    db.rolePermissions = db.rolePermissions.filter((rp: any) => rp.permissionId !== id);\n\n    saveDB(db);\n    res.json({ message: \"Hak izin berhasil dihapus dari sistem!\" });\n  });\n\n  // Get all roles with mapped permission keys\n  app.get(\"/api/roles\", (req, res) => {\n    const db = loadDB();\n    const rolesWithPermissions = db.roles.map((r: Role) => {\n      const rp = db.rolePermissions.filter((mapping: RolePermission) => mapping.roleId === r.id);\n      const mappedPermissions = db.permissions.filter((p: Permission) => \n        rp.some((mapping: RolePermission) => mapping.permissionId === p.id)\n      );\n      return {\n        ...r,\n        permissions: mappedPermissions\n      };\n    });\n    res.json(rolesWithPermissions);\n  });\n\n  // Get all permissions master list\n  app.get(\"/api/permissions\", (req, res) => {\n    const db = loadDB();\n    res.json(db.permissions);\n  });\n\n  // Update permission mapping for a specific Role\n  app.post(\"/api/roles/:id/permissions\", (req, res) => {\n    const { id } = req.params; // roleId\n    const { permissionIds } = req.body; // Array of permissionIds\n    if (!Array.isArray(permissionIds)) {\n      return res.status(400).json({ error: \"Format daftar permissionIds harus berupa array!\" });\n    }\n\n    const db = loadDB();\n    const roleExists = db.roles.some((r: Role) => r.id === id);\n    if (!roleExists) {\n      return res.status(404).json({ error: \"Role tidak ditemukan!\" });\n    }\n\n    // Filter out existing relationships and insert new ones\n    db.rolePermissions = db.rolePermissions.filter((rp: RolePermission) => rp.roleId !== id);\n    permissionIds.forEach((pid: string) => {\n      db.rolePermissions.push({ roleId: id, permissionId: String(pid) });\n    });\n\n    saveDB(db);\n    res.json({ message: \"Pemetaan izin role berhasil diperbarui!\" });\n  });\n\n  // --------------------------------------------------------\n  // API: AUTHENTICATION\n  // --------------------------------------------------------\n  app.post(\"/api/auth/register\", (req, res) => {\n    const { username, email, fullName, phone, role, password } = req.body;\n    if (!username || !email || !fullName || !phone || !role) {\n      return res.status(400).json({ error: \"Semua kolom harus diisi!\" });\n    }\n\n    const db = loadDB();\n    if (db.users.some((u: User) => u.username === username || u.email === email)) {\n      return res.status(400).json({ error: \"Username atau email sudah terdaftar!\" });\n    }\n\n    // Map role type string to database seeding role IDs\n    const mappedRoleId = role === \"owner\" ? \"1\" : \"2\";\n\n    const newUser: User & { password?: string } = {\n      id: String(Date.now()),\n      username,\n      email,\n      fullName,\n      phone,\n      roleId: mappedRoleId,\n      password: password || \"password123\"\n    };\n\n    db.users.push(newUser);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Registrasi berhasil!\", user: resolveUserRBAC(newUser, db) });\n  });\n\n  app.post(\"/api/auth/login\", (req, res) => {\n    const { username, password } = req.body;\n    if (!username || !password) {\n      return res.status(400).json({ error: \"Username dan password wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    const user = db.users.find((u: User) => u.username === username);\n\n    if (!user) {\n      return res.status(400).json({ error: \"Username tidak ditemukan!\" });\n    }\n\n    // Since this is a simulator, check password if set, otherwise default to password123\n    const userPassword = user.password || \"password123\";\n    if (userPassword !== password) {\n      return res.status(400).json({ error: \"Password tidak sesuai!\" });\n    }\n\n    res.json({ message: \"Login berhasil!\", user: resolveUserRBAC(user, db) });\n  });\n\n  // Password Update API\n  app.put(\"/api/users/:id/password\", (req, res) => {\n    const { id } = req.params;\n    const { oldPassword, newPassword } = req.body;\n\n    if (!newPassword) {\n      return res.status(400).json({ error: \"Password baru wajib diisi!\" });\n    }\n\n    const db = loadDB();\n    const userIndex = db.users.findIndex((u: any) => u.id === id);\n    if (userIndex === -1) {\n      return res.status(404).json({ error: \"Pengguna tidak ditemukan!\" });\n    }\n\n    const user = db.users[userIndex];\n    const currentPassword = user.password || \"password123\";\n\n    if (currentPassword !== oldPassword) {\n      return res.status(400).json({ error: \"Password lama tidak sesuai!\" });\n    }\n\n    db.users[userIndex].password = newPassword;\n    saveDB(db);\n\n    res.json({ message: \"Password berhasil diperbarui!\", user: resolveUserRBAC(db.users[userIndex], db) });\n  });\n\n  // --------------------------------------------------------\n  // API: PROPERTIES\n  // --------------------------------------------------------\n  app.get(\"/api/properties\", (req, res) => {\n    const db = loadDB();\n    res.json(db.properties);\n  });\n\n  app.post(\"/api/properties\", (req, res) => {\n    const { ownerId, ownerName, name, type, address, description, priceDay, priceMonth, priceBuy, imageUrl, contactPhone, contactEmail, mapEmbedUrl } = req.body;\n    if (!ownerId || !name || !type || !address || !description) {\n      return res.status(400).json({ error: \"Lengkapi data wajib properti!\" });\n    }\n\n    const db = loadDB();\n    const newProperty: Property = {\n      id: String(Date.now()),\n      ownerId,\n      ownerName: ownerName || \"Unknown Owner\",\n      name,\n      type,\n      address,\n      description,\n      priceDay: priceDay ? Number(priceDay) : undefined,\n      priceMonth: priceMonth ? Number(priceMonth) : undefined,\n      priceBuy: priceBuy ? Number(priceBuy) : undefined,\n      status: \"available\",\n      imageUrl: imageUrl || \"https://images.unsplash.com/photo-1564013799919-ab600027ffc6?auto=format&fit=crop&w=800&q=80\",\n      createdAt: new Date().toISOString(),\n      contactPhone: contactPhone || \"0812-9999-8888\",\n      contactEmail: contactEmail || \"kontak@sewabelipro.com\",\n      mapEmbedUrl: mapEmbedUrl || `https://maps.google.com/maps?q=${encodeURIComponent(address)}&t=&z=15&ie=UTF8&iwloc=&output=embed`\n    };\n\n    db.properties.push(newProperty);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Properti berhasil didaftarkan!\", property: newProperty });\n  });\n\n  app.delete(\"/api/properties/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    const initialLength = db.properties.length;\n    db.properties = db.properties.filter((p: Property) => p.id !== id);\n\n    if (db.properties.length === initialLength) {\n      return res.status(404).json({ error: \"Properti tidak ditemukan!\" });\n    }\n\n    // Also clean up any rooms associated with this property\n    if (db.rooms) {\n      db.rooms = db.rooms.filter((r: any) => r.propertyId !== id);\n    }\n\n    saveDB(db);\n    res.json({ message: \"Properti berhasil dihapus!\" });\n  });\n\n  app.put(\"/api/properties/:id\", (req, res) => {\n    const { id } = req.params;\n    const { name, type, address, description, priceDay, priceMonth, priceBuy, imageUrl, contactPhone, contactEmail, mapEmbedUrl, status } = req.body;\n    \n    if (!name || !type || !address || !description) {\n      return res.status(400).json({ error: \"Lengkapi data wajib properti!\" });\n    }\n\n    const db = loadDB();\n    const propertyIndex = db.properties.findIndex((p: Property) => p.id === id);\n    if (propertyIndex === -1) {\n      return res.status(404).json({ error: \"Properti tidak ditemukan!\" });\n    }\n\n    const updatedProperty = {\n      ...db.properties[propertyIndex],\n      name,\n      type,\n      address,\n      description,\n      priceDay: priceDay ? Number(priceDay) : undefined,\n      priceMonth: priceMonth ? Number(priceMonth) : undefined,\n      priceBuy: priceBuy ? Number(priceBuy) : undefined,\n      imageUrl: imageUrl || db.properties[propertyIndex].imageUrl,\n      contactPhone: contactPhone || db.properties[propertyIndex].contactPhone,\n      contactEmail: contactEmail || db.properties[propertyIndex].contactEmail,\n      mapEmbedUrl: mapEmbedUrl || db.properties[propertyIndex].mapEmbedUrl,\n      status: status || db.properties[propertyIndex].status\n    };\n\n    db.properties[propertyIndex] = updatedProperty;\n    saveDB(db);\n\n    res.json({ message: \"Properti berhasil diperbarui!\", property: updatedProperty });\n  });\n\n  // --------------------------------------------------------\n  // API: ROOMS\n  // --------------------------------------------------------\n  app.get(\"/api/rooms\", (req, res) => {\n    const db = loadDB();\n    res.json(db.rooms || []);\n  });\n\n  app.get(\"/api/properties/:propertyId/rooms\", (req, res) => {\n    const { propertyId } = req.params;\n    const db = loadDB();\n    const rooms = (db.rooms || []).filter((r: any) => r.propertyId === propertyId);\n    res.json(rooms);\n  });\n\n  app.post(\"/api/rooms\", (req, res) => {\n    const { propertyId, roomNumber, type, priceDay, status, position, facilities, facing, view, imageUrl } = req.body;\n    if (!propertyId || !roomNumber || !type) {\n      return res.status(400).json({ error: \"Lengkapi data wajib kamar / ruangan!\" });\n    }\n\n    const db = loadDB();\n    const newRoom = {\n      id: \"r_\" + Date.now(),\n      propertyId,\n      roomNumber,\n      type,\n      priceDay: Number(priceDay || 0),\n      status: status || \"available\",\n      position: position || \"\",\n      facilities: facilities || [],\n      facing: facing || \"\",\n      view: view || \"\",\n      imageUrl: imageUrl || \"https://images.unsplash.com/photo-1590490360182-c33d57733427?auto=format&fit=crop&w=600&q=80\",\n      bookedDates: []\n    };\n\n    db.rooms = db.rooms || [];\n    db.rooms.push(newRoom);\n    saveDB(db);\n\n    res.status(201).json({ message: \"Kamar / ruangan baru berhasil ditambahkan!\", room: newRoom });\n  });\n\n  app.put(\"/api/rooms/:id/status\", (req, res) => {\n    const { id } = req.params;\n    const { \n      status, \n      bookedDates, \n      guestName, \n      checkOutTime, \n      cleaningStatus, \n      extensionReason, \n      extendedCount,\n      cleaningStaff,\n      maintenanceReason,\n      maintenanceStaff\n    } = req.body;\n    const db = loadDB();\n    const room = (db.rooms || []).find((r: any) => r.id === id);\n    if (!room) {\n       return res.status(404).json({ error: \"Kamar tidak ditemukan!\" });\n    }\n\n    const prevStatus = room.status;\n    const prevCleaningStatus = room.cleaningStatus;\n\n    if (status !== undefined) room.status = status;\n    if (bookedDates !== undefined) room.bookedDates = bookedDates;\n    if (guestName !== undefined) room.guestName = guestName;\n    if (checkOutTime !== undefined) room.checkOutTime = checkOutTime;\n    if (cleaningStatus !== undefined) room.cleaningStatus = cleaningStatus;\n    if (extensionReason !== undefined) room.extensionReason = extensionReason;\n    if (extendedCount !== undefined) room.extendedCount = extendedCount;\n    if (cleaningStaff !== undefined) room.cleaningStaff = cleaningStaff;\n    if (maintenanceReason !== undefined) room.maintenanceReason = maintenanceReason;\n    if (maintenanceStaff !== undefined) room.maintenanceStaff = maintenanceStaff;\n    \n    saveDB(db);\n\n    // Trigger Webhook Events based on transition\n    const webhookPayload = {\n      id: room.id,\n      roomNumber: room.roomNumber,\n      type: room.type,\n      status: room.status,\n      cleaningStatus: room.cleaningStatus,\n      cleaningStaff: room.cleaningStaff || \"\",\n      maintenanceReason: room.maintenanceReason || \"\",\n      maintenanceStaff: room.maintenanceStaff || \"\",\n      guestName: room.guestName || \"\",\n      checkOutTime: room.checkOutTime || \"\"\n    };\n\n    // Determine event\n    if (prevStatus === \"available\" && room.status === \"occupied\") {\n      triggerWebhooks(\"check_in\", webhookPayload);\n    } else if (prevStatus === \"occupied\" && room.status === \"available\" && room.cleaningStatus === \"dirty\") {\n      triggerWebhooks(\"check_out\", webhookPayload);\n    } else if (prevCleaningStatus !== \"cleaning\" && room.cleaningStatus === \"cleaning\") {\n      triggerWebhooks(\"cleaning_started\", webhookPayload);\n    } else if (prevCleaningStatus === \"cleaning\" && room.cleaningStatus === \"clean\") {\n      triggerWebhooks(\"cleaning_completed\", webhookPayload);\n    } else if (prevStatus !== \"maintenance\" && room.status === \"maintenance\") {\n      triggerWebhooks(\"maintenance_started\", webhookPayload);\n    } else if (prevStatus === \"maintenance\" && room.status === \"available\") {\n      triggerWebhooks(\"maintenance_completed\", webhookPayload);\n    }\n\n    res.json({ message: \"Status kamar berhasil diperbarui!\", room });\n  });\n\n  app.put(\"/api/rooms/:id\", (req, res) => {\n    const { id } = req.params;\n    const { roomNumber, type, priceDay, status, position, facilities, facing, view, imageUrl, bookedDates } = req.body;\n    \n    if (!roomNumber || !type) {\n      return res.status(400).json({ error: \"Lengkapi data wajib kamar / ruangan!\" });\n    }\n\n    const db = loadDB();\n    const roomIndex = (db.rooms || []).findIndex((r: any) => r.id === id);\n    if (roomIndex === -1) {\n      return res.status(404).json({ error: \"Kamar tidak ditemukan!\" });\n    }\n\n    const updatedRoom = {\n      ...db.rooms[roomIndex],\n      roomNumber,\n      type,\n      priceDay: Number(priceDay || 0),\n      status: status || db.rooms[roomIndex].status,\n      position: position !== undefined ? position : db.rooms[roomIndex].position,\n      facilities: facilities || db.rooms[roomIndex].facilities,\n      facing: facing !== undefined ? facing : db.rooms[roomIndex].facing,\n      view: view !== undefined ? view : db.rooms[roomIndex].view,\n      imageUrl: imageUrl || db.rooms[roomIndex].imageUrl,\n      bookedDates: bookedDates || db.rooms[roomIndex].bookedDates\n    };\n\n    db.rooms[roomIndex] = updatedRoom;\n    saveDB(db);\n\n    res.json({ message: \"Kamar / ruangan berhasil diperbarui!\", room: updatedRoom });\n  });\n\n  app.delete(\"/api/rooms/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    const initialLength = (db.rooms || []).length;\n    \n    db.rooms = (db.rooms || []).filter((r: any) => r.id !== id);\n\n    if (db.rooms.length === initialLength) {\n      return res.status(404).json({ error: \"Kamar tidak ditemukan!\" });\n    }\n\n    saveDB(db);\n    res.json({ message: \"Kamar / ruangan berhasil dihapus!\" });\n  });\n\n  // --------------------------------------------------------\n  // API: TRANSACTIONS\n  // --------------------------------------------------------\n  app.get(\"/api/transactions\", (req, res) => {\n    const db = loadDB();\n    res.json(db.transactions);\n  });\n\n  app.post(\"/api/transactions\", (req, res) => {\n    const { \n      buyerId, \n      buyerName, \n      propertyId, \n      type, \n      startDate, \n      endDate, \n      totalPrice,\n      couponCode,\n      paymentMethod,\n      reservationTime,\n      confirmationNotes,\n      paymentCycle, // 'DP' | 'lunas'\n      amountPaid, // for DP\n      roomId,\n      roomNumber\n    } = req.body;\n\n    if (!buyerId || !propertyId || !type || !totalPrice) {\n      return res.status(400).json({ error: \"Data transaksi tidak lengkap!\" });\n    }\n\n    const db = loadDB();\n    const property = db.properties.find((p: Property) => p.id === propertyId);\n    if (!property) {\n      return res.status(404).json({ error: \"Properti tidak ditemukan!\" });\n    }\n\n    // 1. Hitung Potongan Promo / Kupon\n    let finalPrice = Number(totalPrice);\n    let appliedDiscount = 0;\n    if (couponCode) {\n      db.promos = db.promos || [];\n      const promo = db.promos.find((p: any) => p.code.toUpperCase() === couponCode.trim().toUpperCase());\n      if (promo) {\n        if (promo.used < promo.maxUse) {\n          appliedDiscount = Number(promo.discount);\n          finalPrice = Math.max(0, finalPrice - appliedDiscount);\n          promo.used += 1;\n        }\n      }\n    }\n\n    // Set status based on action\n    if (type === \"buy\") {\n      property.status = \"sold\";\n    } else if (type === \"rent\") {\n      property.status = \"rented\";\n    } else if (type === \"stay\") {\n      property.status = \"reserved\"; // update property status\n    }\n\n    // Update room status if roomId is supplied\n    if (roomId) {\n      db.rooms = db.rooms || [];\n      const room = db.rooms.find((r: any) => r.id === roomId);\n      if (room) {\n        room.status = \"occupied\";\n        room.bookedDates = room.bookedDates || [];\n        const start = startDate || new Date().toISOString().substring(0, 10);\n        const end = endDate || \"Selesai\";\n        room.bookedDates.push(`${start} s/d ${end}`);\n      }\n    }\n\n    const txId = String(Date.now());\n    const newTransaction: Transaction = {\n      id: txId,\n      buyerId,\n      buyerName,\n      propertyId,\n      propertyName: property.name,\n      propertyType: property.type,\n      type,\n      startDate: startDate || new Date().toISOString().substring(0, 10),\n      endDate: endDate || \"-\",\n      totalPrice: finalPrice,\n      status: \"paid\", // Instant simulation\n      createdAt: new Date().toISOString(),\n      roomId: roomId || undefined,\n      roomNumber: roomNumber || undefined\n    };\n\n    db.transactions.push(newTransaction);\n\n    // 2. Buat Laporan / Rincian Tagihan (Billing invoice)\n    db.payments = db.payments || [];\n    const isDP = paymentCycle === \"DP\";\n    const actualPaid = isDP ? Math.min(finalPrice, Number(amountPaid || 500000)) : finalPrice;\n    \n    const newPayment = {\n      id: \"pay_\" + Date.now(),\n      transactionId: txId,\n      propertyName: property.name,\n      totalAmount: finalPrice,\n      amountPaid: actualPaid,\n      paymentMethod: paymentMethod || \"Bank Transfer - Mandiri\",\n      type: paymentCycle || \"lunas\", // 'DP' | 'lunas'\n      status: actualPaid >= finalPrice ? \"paid\" : \"pending\",\n      dueDate: endDate || new Date(Date.now() + 7 * 24 * 3600 * 1000).toISOString().substring(0, 10),\n      notes: confirmationNotes || `Pemesanan ${type} via aplikasi. Kupon: ${couponCode || 'Tidak ada'}`\n    };\n    db.payments.push(newPayment);\n\n    // 3. Buat Siklus Tamu (Guest Lifecycle)\n    db.guestCycles = db.guestCycles || [];\n    const newCycle = {\n      id: \"gc_\" + Date.now(),\n      guestName: buyerName,\n      propertyName: property.name,\n      roomNumber: roomNumber || (property.type === \"hotel\" || property.type === \"kos\" || property.type === \"apartment\" \n        ? String(Math.floor(Math.random() * 800) + 101) \n        : \"Unit Utama\"),\n      status: \"Reserved\", // 'Reserved' | 'Checked In' | 'Checked Out' | 'Cancelled'\n      checkInTime: reservationTime || startDate || \"-\",\n      checkOutTime: \"-\"\n    };\n    db.guestCycles.push(newCycle);\n\n    // 4. Tambahkan Log Aktivitas (User & App Auditing Logs)\n    db.logs = db.logs || [];\n    \n    // Log User\n    db.logs.push({\n      id: \"log_\" + Date.now() + \"_1\",\n      type: \"user\",\n      message: `User ${buyerName} melakukan pemesanan (${type}) untuk properti \"${property.name}\" senilai Rp ${finalPrice.toLocaleString('id-ID')}. Metode: ${paymentMethod || 'Mandiri'}.`,\n      user: buyerName,\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    // Log Aplikasi\n    db.logs.push({\n      id: \"log_\" + Date.now() + \"_2\",\n      type: \"app\",\n      message: `Sistem mendeteksi pembuatan transaksi #${txId} untuk properti \"${property.name}\". Tagihan otomatis senilai Rp ${finalPrice.toLocaleString('id-ID')} diterbitkan.`,\n      user: \"System Engine\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    // 5. Tambahkan Notifikasi Otomatis untuk Tamu (Buyer) & Pemilik (Owner/Admin)\n    try {\n      // Notifikasi Tamu\n      createAndSimulateNotification(\n        db,\n        buyerId,\n        `Booking ${type === 'buy' ? 'Pembelian' : 'Penyewaan'} Berhasil!`,\n        `Pemesanan properti \"${property.name}\" senilai Rp ${finalPrice.toLocaleString('id-ID')} telah sukses dikonfirmasi. Silakan cek detail di menu My Bookings!`,\n        'booking'\n      );\n\n      // Notifikasi Pemilik Properti / Admin\n      if (property.ownerId) {\n        createAndSimulateNotification(\n          db,\n          property.ownerId,\n          `Pesanan Baru Masuk!`,\n          `${buyerName} telah memesan \"${property.name}\" (${type === 'buy' ? 'Beli' : 'Sewa'}) senilai Rp ${finalPrice.toLocaleString('id-ID')}.`,\n          'booking'\n        );\n      }\n    } catch (e) {\n      console.error(\"Error creating transaction notifications:\", e);\n    }\n\n    saveDB(db);\n\n    res.status(201).json({ \n      message: \"Transaksi berhasil diproses!\", \n      transaction: newTransaction, \n      property,\n      payment: newPayment,\n      guestCycle: newCycle\n    });\n  });\n\n  // --------------------------------------------------------\n  // API: DASHBOARD STATS\n  // --------------------------------------------------------\n  app.get(\"/api/stats\", (req, res) => {\n    const db = loadDB();\n    const properties = db.properties;\n    const transactions = db.transactions.filter((t: Transaction) => t.status === \"paid\");\n\n    let revenue = 0;\n    let activeStays = 0;\n    let activeRentals = 0;\n    let unitsSold = 0;\n\n    transactions.forEach((t: Transaction) => {\n      revenue += t.totalPrice;\n      if (t.type === \"stay\") activeStays++;\n      if (t.type === \"rent\") activeRentals++;\n      if (t.type === \"buy\") unitsSold++;\n    });\n\n    res.json({\n      totalProperties: properties.length,\n      totalTransactions: db.transactions.length,\n      revenue,\n      activeStays,\n      activeRentals,\n      unitsSold\n    });\n  });\n\n  // --------------------------------------------------------\n  // API: GEMINI PROFILE INSIGHTS\n  // --------------------------------------------------------\n  app.post(\"/api/gemini/profile-insights\", async (req, res) => {\n    const { type, data } = req.body;\n    if (!type || !data) {\n      return res.status(400).json({ error: \"Tipe dan data diperlukan untuk analisis!\" });\n    }\n\n    const apiKey = process.env.GEMINI_API_KEY;\n    const isApiKeyMissingOrPlaceholder = !apiKey || apiKey === \"MY_GEMINI_API_KEY\" || apiKey.trim() === \"\";\n\n    if (isApiKeyMissingOrPlaceholder) {\n      // Return high-quality, professional simulated analysis\n      let title = \"Smart Explorer\";\n      let businessPlausibility = \"Tinggi. Menunjukkan aktivitas berkelanjutan di platform.\";\n      let recommendations = [\n        \"Pertahankan kualitas pelayanan dan kepatuhan.\",\n        \"Pantau metrik performa secara berkala.\"\n      ];\n\n      const normType = type.toLowerCase();\n      if (normType === \"user\" || normType === \"guest\" || normType === \"owner\" || normType === \"buyer\") {\n        const role = data.role || (normType === \"owner\" ? \"owner\" : \"guest\");\n        if (role === \"owner\" || normType === \"owner\") {\n          title = \"High-Yield Host / Premium Owner\";\n          businessPlausibility = \"Sangat potensial. Akun memiliki otorisasi penuh untuk listing dan manajemen hunian premium.\";\n          recommendations = [\n            \"Optimalkan listing dengan foto HD berkualitas tinggi.\",\n            \"Terapkan strategi dynamic pricing untuk meningkatkan okupansi di musim liburan.\",\n            \"Gunakan fitur 'Operations Hub' secara maksimal untuk memantau keluhan tamu secara real-time.\"\n          ];\n        } else if (normType === \"buyer\") {\n          title = \"High-Net-Worth Real Estate Investor\";\n          businessPlausibility = \"Sangat tinggi. Menunjukkan minat kuat dan kapasitas finansial prima untuk pembelian properti premium.\";\n          recommendations = [\n            \"Tawarkan portofolio eksklusif off-market yang sesuai dengan rentang budget investasi.\",\n            \"Hubungkan investor dengan spesialis pembiayaan KPR atau opsi skema sewa-beli (lease-to-own).\",\n            \"Berikan kalkulasi estimasi ROI (Return on Investment) tahunan secara berkala.\"\n          ];\n        } else {\n          title = \"Smart Budgeter / Urban Explorer\";\n          businessPlausibility = \"Menjanjikan. Konsumen aktif mencari properti sewa/beli dengan efisiensi tinggi.\";\n          recommendations = [\n            \"Aktifkan notifikasi promo mingguan di SewaBeliPro.\",\n            \"Bandingkan harga sewa harian vs bulanan untuk memaksimalkan value uang Anda.\",\n            \"Lakukan booking lebih awal untuk menjamin ketersediaan kamar.\"\n          ];\n        }\n      } else if (normType === \"property\") {\n        const propPrice = data.priceDay || data.priceMonth || data.priceBuy || 0;\n        if (propPrice > 1000000) {\n          title = \"Luxury Signature Property\";\n          businessPlausibility = \"Segmen pasar atas (high-end) dengan margin keuntungan tinggi per transaksi.\";\n          recommendations = [\n            \"Fokus pada layanan butler personal dan amenities premium.\",\n            \"Promosikan keunikan arsitektur dan privasi eksklusif melalui kampanye Ads.\",\n            \"Jadwalkan pemeliharaan preventif secara berkala untuk menjaga kualitas aset.\"\n          ];\n        } else {\n          title = \"High-Volume Sweetspot Asset\";\n          businessPlausibility = \"Segmentasi pasar menengah yang stabil dengan tingkat okupansi yang konsisten.\";\n          recommendations = [\n            \"Fokus pada kebersihan maksimal dan respon keluhan tamu yang cepat.\",\n            \"Tawarkan paket bundling menarik (misal: menginap harian gratis kupon makan).\",\n            \"Pastikan fasilitas utama seperti Wi-Fi dan AC selalu dalam kondisi prima.\"\n          ];\n        }\n      } else {\n        title = \"Dynamic Growth Portfolio\";\n        businessPlausibility = \"Aliran kas (cashflow) aktif yang menunjukkan traksi transaksi finansial sehat.\";\n        recommendations = [\n          \"Lakukan pencatatan pembayaran DP dan pelunasan dengan integrasi otomatis.\",\n          \"Analisis tren musiman transaksi untuk mempersiapkan likuiditas keuangan.\",\n          \"Gunakan penagihan otomatis bagi penyewa bulanan yang hampir jatuh tempo.\"\n        ];\n      }\n\n      const generatedInsights = `### \uD83C\uDF1F Analisis Profil AI (${title})\n\n> \uD83D\uDCA1 **Mode Berjalan Lancar (Offline Mode):** Aplikasi berjalan mulus secara lokal tanpa memerlukan kunci API eksternal.\n\n#### 1. Deskripsi Karakter / Persona Singkat\nProfil ini dianalisis secara cerdas sebagai **${title}**. Karakteristik utama menunjukkan tingkat keaktifan tinggi, orientasi pada efisiensi operasional harian, dan respons yang cepat terhadap keluhan tamu serta manajemen fasilitas real-estate SewaBeliPro.\n\n#### 2. Peluang Bisnis / Strategi Optimal\n* **Potensi Pasar**: ${businessPlausibility}\n* **Optimalisasi Operasional**: Nilai strategis terletak pada efisiensi pencatatan transaksi terintegrasi dan respons cepat terhadap keluhan tamu.\n\n#### 3. Rekomendasi Tindakan Nyata (Actionable Advice)\n${recommendations.map(r => `* **${r.split('.')[0]}**: ${r}`).join('\\n')}\n\n---\n*Catatan: Fitur analisis ini berjalan dalam **Mode Hemat Energi (Simulasi Mandiri)** karena \\`GEMINI_API_KEY\\` belum dikonfigurasi. Kinerja sistem dijamin 100% normal, responsif, dan super cepat.*`;\n\n      return res.json({ insights: generatedInsights });\n    }\n\n    try {\n      const prompt = `Analisis profil berikut dalam konteks aplikasi real-estate & hospitality SewaBeliPro.\nTipe Profil: ${type}\nDetail Data Profil:\n${JSON.stringify(data, null, 2)}\n\nBerikan analisis dalam bahasa Indonesia yang ringkas, profesional, dan berorientasi taktis/strategis. Berikan 3 poin penting:\n1. Deskripsi Karakter / Persona Singkat (Gunakan istilah menarik seperti 'Smart Budgeter', 'Luxury Explorer', 'High-Yield Developer', dll.)\n2. Peluang Bisnis / Strategi Optimal\n3. Rekomendasi Tindakan Nyata (Actionable Advice)\n\nFormat keluaran dalam Markdown yang rapi dengan heading yang bersih.`;\n\n      const response = await getAIClient().models.generateContent({\n        model: \"gemini-3.5-flash\",\n        contents: prompt,\n      });\n\n      res.json({ insights: response.text });\n    } catch (error: any) {\n      console.error(\"Gemini API error:\", error);\n      res.status(500).json({ error: \"Gagal memproses analisis profil dengan AI: \" + error.message });\n    }\n  });\n\n  // --------------------------------------------------------\n  // API: GEMINI AI & ML PREDICTIONS\n  // --------------------------------------------------------\n  app.post(\"/api/gemini/predict\", async (req, res) => {\n    const { type, inputs } = req.body;\n    if (!type || !inputs) {\n      return res.status(400).json({ error: \"Tipe prediksi dan data input wajib ditentukan!\" });\n    }\n\n    const apiKey = process.env.GEMINI_API_KEY;\n    const isApiKeyMissingOrPlaceholder = !apiKey || apiKey === \"MY_GEMINI_API_KEY\" || apiKey.trim() === \"\";\n\n    if (isApiKeyMissingOrPlaceholder) {\n      // High-quality simulated prediction output\n      let insights = \"\";\n      if (type === \"price-prediction\") {\n        const { propertyType, size, bedrooms, bathrooms, location, amenities = [] } = inputs;\n        const basePricePerSqm = \n          propertyType === \"house\" ? 12000000 : \n          propertyType === \"apartment\" ? 18000000 : \n          propertyType === \"villa\" ? 15000000 : \n          propertyType === \"kos\" ? 1500000 : 800000;\n\n        let multiplier = 1.0;\n        if (location?.toLowerCase().includes(\"jakarta\") || location?.toLowerCase().includes(\"sudirman\") || location?.toLowerCase().includes(\"rasuna\")) multiplier = 1.5;\n        else if (location?.toLowerCase().includes(\"bali\") || location?.toLowerCase().includes(\"ubud\")) multiplier = 1.3;\n        else if (location?.toLowerCase().includes(\"bandung\")) multiplier = 1.1;\n\n        const calculatedValuation = Number(size || 50) * basePricePerSqm * multiplier + (Number(bedrooms || 1) * 50000000) + (Number(bathrooms || 1) * 20000000) + (amenities.length * 15000000);\n        \n        let formattedValue = \"\";\n        let recommendationText = \"\";\n        if (propertyType === \"hotel\" || propertyType === \"villa\") {\n          const rentalPredict = Math.round(calculatedValuation / 1000);\n          formattedValue = `Rp ${rentalPredict.toLocaleString('id-ID')} / Hari`;\n          recommendationText = `Strategi dynamic pricing disarankan pada kisaran **Rp ${(rentalPredict * 0.9).toLocaleString('id-ID')}** hingga **Rp ${(rentalPredict * 1.15).toLocaleString('id-ID')}** tergantung musim (peak season).`;\n        } else if (propertyType === \"kos\") {\n          const rentalPredict = Math.round(calculatedValuation / 10000);\n          formattedValue = `Rp ${rentalPredict.toLocaleString('id-ID')} / Bulan`;\n          recommendationText = `Tetapkan harga sewa dasar di **Rp ${rentalPredict.toLocaleString('id-ID')}** dengan biaya tambahan untuk listrik/fasilitas tertentu guna mengoptimalkan yield keuntungan tahunan.`;\n        } else {\n          formattedValue = `Rp ${calculatedValuation.toLocaleString('id-ID')}`;\n          recommendationText = `Harga pasar wajar diperkirakan pada **Rp ${(calculatedValuation * 0.95).toLocaleString('id-ID')}** untuk penjualan cepat, dengan batas negosiasi optimal di **Rp ${(calculatedValuation * 1.1).toLocaleString('id-ID')}**.`;\n        }\n\n        insights = `### \uD83D\uDD2E Analisis Penilaian Nilai Pasar Real-Estate AI\n        \n> \uD83D\uDCA1 **Mode Lancar Offline:** Berjalan lancar secara lokal menggunakan mesin estimasi statistik SewaBeliPro.\n\n#### \uD83D\uDCCA Hasil Estimasi Prediksi Nilai\n* **Rekomendasi Harga Wajar**: **${formattedValue}**\n* **Viabilitas Investasi**: **Tinggi (Skor: 85/100)**\n* **Margin Keuntungan Potensial**: **9.2% per tahun**\n\n#### \uD83D\uDCA1 Analisis Kondisi Pasar & Lokasi\nBerdasarkan parameter yang dimasukkan, properti tipe **${propertyType}** di **${location || \"Lokasi Umum\"}** berukuran **${size || 50} m\u00B2** memiliki nilai strategis tinggi. Lokasi ini menunjukkan pertumbuhan tahunan (capital appreciation) rata-rata **6% - 8%** di segmen perumahan urban modern.\n\n#### \uD83D\uDCC8 Rekomendasi Taktis & Keputusan\n* ${recommendationText}\n* **Optimalisasi Aset**: Tambahkan fasilitas ramah lingkungan (eco-friendly) atau smart lock untuk menaikkan nilai sewa/jual hingga **12%**.\n* **Target Konsumen**: Sangat cocok ditargetkan untuk pekerja profesional muda atau keluarga kecil kelas menengah-atas.`;\n      } \n      \n      else if (type === \"demand-forecasting\") {\n        const { propertyId, propertyName } = inputs;\n        insights = `### \uD83D\uDCC8 Proyeksi Tingkat Okupansi & Permintaan AI/ML (6 Bulan Ke Depan)\n\n> \uD83D\uDCA1 **Mode Lancar Offline:** Analisis musiman berjalan menggunakan log historis transaksi terintegrasi SewaBeliPro.\n\n#### \uD83D\uDCCA Prakiraan Metrik Utama untuk \"${propertyName || \"Properti Terpilih\"}\"\n* **Tingkat Okupansi Rata-rata**: **78.4%** (+4.2% YoY)\n* **Puncak Kunjungan Terdekat**: **Bulan Depan (Perkiraan Okupansi: 92%)**\n* **Estimasi Pendapatan Kotor (6 Bulan)**: **Rp 48.500.000**\n\n#### \uD83D\uDCC6 Proyeksi Bulanan & Tren Musiman\n1. **Bulan 1**: **85% okupansi** \u2014 Didorong liburan akhir pekan panjang & promosi aktif.\n2. **Bulan 2**: **92% okupansi** \u2014 Masa puncak liburan (high season). Disarankan menaikkan tarif sebesar **10-15%**.\n3. **Bulan 3**: **70% okupansi** \u2014 Penurunan normal pasca-liburan. Terapkan diskon kupon seperti \\`WEEKENDSERU\\` untuk menjaga kestabilan okupansi.\n4. **Bulan 4**: **68% okupansi** \u2014 Masa low season. Fokus pada pemeliharaan berkala fasilitas utama.\n5. **Bulan 5**: **75% okupansi** \u2014 Permintaan kembali pulih, terutama untuk penyewaan grup.\n6. **Bulan 6**: **80% okupansi** \u2014 Pertumbuhan stabil dengan tingkat repeat guest (tamu berulang) di atas 20%.\n\n#### \uD83D\uDEE0\uFE0F Rekomendasi Keputusan Operasional\n* **Strategi Harga**: Manfaatkan dynamic pricing. Naikkan tarif pada Bulan 2 dan tawarkan paket bundling diskon pada Bulan 4.\n* **Pemasangan Ads**: Pasang iklan promosi banner 2 minggu sebelum memasuki Bulan 3 guna meminimalisir penurunan okupansi.`;\n      } \n      \n      else if (type === \"buy-vs-rent\") {\n        const { buyPrice, rentPrice, interestRate, years, maintenance } = inputs;\n        const totalRent = Number(rentPrice) * 12 * Number(years);\n        const buyPriceNum = Number(buyPrice);\n        const interestMultiplier = 1 + ((Number(interestRate || 5) / 100) * Number(years));\n        const estimatedMortgageCost = buyPriceNum * interestMultiplier;\n        const totalBuyCost = estimatedMortgageCost + (Number(maintenance || 200000) * 12 * Number(years));\n        const finalValueAfterAppreciation = buyPriceNum * Math.pow(1.05, Number(years));\n        const netEquity = finalValueAfterAppreciation - totalBuyCost;\n\n        const decision = netEquity > -totalRent ? \"MEMBELI\" : \"MENYEWA\";\n        const difference = Math.abs(netEquity + totalRent);\n\n        insights = `### \u2696\uFE0F Analisis Keputusan Keuangan AI: Beli vs Sewa\n\n> \uD83D\uDCA1 **Mode Lancar Offline:** Perhitungan nilai NPV dan apresiasi aset dihitung secara presisi menggunakan model finansial real-estate.\n\n#### \uD83D\uDCCA Ringkasan Perbandingan Finansial (${years} Tahun)\n* **Rekomendasi AI**: **Lebih menguntungkan untuk ${decision}**\n* **Selisih Nilai Bersih Akhir**: **Rp ${Math.round(difference).toLocaleString('id-ID')}**\n* **Estimasi Total Biaya Sewa**: Rp ${Math.round(totalRent).toLocaleString('id-ID')}\n* **Estimasi Nilai Properti Akhir (Apresiasi 5%/Thn)**: Rp ${Math.round(finalValueAfterAppreciation).toLocaleString('id-ID')}\n\n#### \uD83D\uDD0D Rincian Analisis Investasi\n* **Skenario Sewa**: Dana Anda bebas dari cicilan bank, namun semua biaya sewa sebesar **Rp ${Math.round(totalRent).toLocaleString('id-ID')}** akan hilang sebagai pengeluaran tanpa menyisakan kepemilikan aset.\n* **Skenario Beli**: Meskipun pengeluaran awal dan pemeliharaan bulanan lebih besar, nilai properti Anda diproyeksikan tumbuh menjadi **Rp ${Math.round(finalValueAfterAppreciation).toLocaleString('id-ID')}** dalam ${years} tahun, memberikan keuntungan ekuitas bersih setelah dikurangi bunga bank.\n\n#### \uD83D\uDCA1 Keputusan Strategis yang Disarankan\n* Jika Anda berencana tinggal selama **${years} tahun atau lebih**, keputusan **${decision}** adalah langkah finansial yang paling matang dan memberikan akumulasi kekayaan (wealth accumulation) terbaik.\n* Manfaatkan program promo DP bersahabat jika memilih opsi Beli untuk menjaga likuiditas arus kas pribadi Anda.`;\n      } \n      \n      else if (type === \"maintenance-prediction\") {\n        const { assetId, assetName, age, loadFactor, runtimeHours } = inputs;\n        const wearRate = (Number(age || 1) * 0.15) + (Number(runtimeHours || 1000) * 0.00005) + (loadFactor === \"high\" ? 0.3 : loadFactor === \"medium\" ? 0.15 : 0.05);\n        const riskScore = Math.min(100, Math.round(wearRate * 100));\n        \n        let riskLabel = \"Rendah\";\n        let riskColor = \"text-emerald-600\";\n        let nextFailureDays = 180;\n        \n        if (riskScore > 75) {\n          riskLabel = \"Kritis\";\n          riskColor = \"text-red-600 font-extrabold animate-pulse\";\n          nextFailureDays = 14;\n        } else if (riskScore > 45) {\n          riskLabel = \"Sedang\";\n          riskColor = \"text-yellow-600\";\n          nextFailureDays = 60;\n        }\n\n        const estimatedCost = Math.round(riskScore * 80000);\n\n        insights = `### \uD83D\uDD27 Prediksi Kerusakan Aset & Jadwal Preventive Maintenance\n\n> \uD83D\uDCA1 **Mode Lancar Offline:** Analisis tingkat keausan komponen dihitung menggunakan machine learning regresi keausan fisik.\n\n#### \uD83D\uDCCA Metrik Risiko Aset \"${assetName || \"Aset Terpilih\"}\"\n* **Tingkat Risiko Kerusakan**: <span class=\"${riskColor}\">${riskLabel} (${riskScore}%)</span>\n* **Estimasi Sisa Umur Operasional (RUL)**: **${nextFailureDays} Hari**\n* **Perkiraan Tanggal Gangguan**: **${new Date(Date.now() + nextFailureDays * 24 * 3600 * 1000).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' })}**\n* **Estimasi Biaya Perbaikan (Corrective Cost)**: **Rp ${estimatedCost.toLocaleString('id-ID')}**\n\n#### \uD83D\uDD2C Analisis Kondisi Fisik & Keausan\nKomponen mengalami keausan akseleratif akibat jam operasional aktif (**${runtimeHours || 1000} jam**) dengan faktor beban kerja **${loadFactor || \"medium\"}**. Terdeteksi tanda-tanda getaran harmonik atau penurunan efisiensi termal/mekanis ringan pada motor penggerak.\n\n#### \uD83D\uDCC5 Jadwal Tindakan Pencegahan Direkomendasikan\n* **Tindakan Terdekat (Maksimal 7 Hari)**: Lakukan pelumasan ulang (lubrication) komponen utama dan pembersihan filter udara.\n* **Tindakan Menengah (Maksimal 30 Hari)**: Kalibrasi ulang sensor dan ganti segel karet penahan getaran untuk mencegah kebocoran/loss daya.\n* **Tindakan Korektif**: Alokasikan dana pemeliharaan darurat sebesar **Rp ${(estimatedCost * 0.85).toLocaleString('id-ID')}** dalam anggaran kuartal ini untuk menghindari downtime operasional total.`;\n      }\n\n      return res.json({ insights });\n    }\n\n    try {\n      let prompt = \"\";\n      if (type === \"price-prediction\") {\n        prompt = `Bertindaklah sebagai Pakar Penilaian Real-Estate & ML Estimator di Indonesia.\nLakukan analisis prediksi harga properti berdasarkan data input berikut:\n${JSON.stringify(inputs, null, 2)}\n\nHarap berikan tanggapan terstruktur dalam Bahasa Indonesia:\n1. Prakiraan Nilai Estimasi Pasar yang Wajar (Berikan rentang harga yang realistis dalam Rupiah).\n2. Analisis Keunggulan & Kekurangan Spesifikasi / Lokasi tersebut.\n3. Rekomendasi Dynamic Pricing & Strategi Pemasaran untuk memaksimalkan yield keuntungan (Sewa maupun Jual).\n4. Viabilitas Investasi (Skor dari 1-100).\n\nKeluaran harus berformat Markdown yang rapi, profesional, dan eye-catching.`;\n      } else if (type === \"demand-forecasting\") {\n        prompt = `Bertindaklah sebagai Sistem Prediksi Demand & Okupansi Cerdas berbasis AI/ML untuk Real-Estate/Hospitality.\nLakukan prakiraan tingkat hunian (occupancy rates) dan permintaan selama 6 bulan ke depan untuk properti berikut:\n${JSON.stringify(inputs, null, 2)}\n\nHarap berikan analisis terstruktur dalam Bahasa Indonesia:\n1. Prakiraan Persentase Okupansi Bulanan (Bulan 1 s/d Bulan 6) beserta tren musiman (high/low season).\n2. Faktor-faktor eksternal yang memengaruhi permintaan (liburan, cuaca, event lokal).\n3. Rekomendasi Strategi Tarif Dinamis (Dynamic Pricing) dan Pemasangan Promosi Iklan untuk menyeimbangkan okupansi.\n\nFormat keluaran dalam Markdown yang bersih dan terstruktur.`;\n      } else if (type === \"buy-vs-rent\") {\n        prompt = `Bertindaklah sebagai Konsultan Finansial & Investasi Properti AI/ML.\nBandingkan secara mendalam keputusan keuangan apakah lebih baik MEMBELI atau MENYEWA properti berdasarkan input finansial berikut:\n${JSON.stringify(inputs, null, 2)}\n\nHarap buatkan laporan komparatif dalam Bahasa Indonesia yang mencakup:\n1. Perbandingan Net Present Value (NPV), Ekuitas Bersih, dan Akumulasi Kekayaan setelah durasi tahun yang ditentukan.\n2. Analisis Keuntungan Finansial & Resiko dari masing-masing pilihan (Beli vs Sewa).\n3. Keputusan Rekomendasi Akhir AI secara tegas (Mana yang lebih menguntungkan secara finansial, beli atau sewa).\n\nGunakan tabel atau poin-poin Markdown yang terperinci.`;\n      } else if (type === \"maintenance-prediction\") {\n        prompt = `Bertindaklah sebagai Sistem Pemeliharaan Prediktif (Predictive Maintenance AI/ML) untuk Manajemen Fasilitas Gedung.\nPrediksikan risiko kerusakan dan sisa masa pakai (Remaining Useful Life) berdasarkan parameter kondisi aset berikut:\n${JSON.stringify(inputs, null, 2)}\n\nHarap berikan analisis dalam Bahasa Indonesia:\n1. Skor Risiko Kerusakan Komponen (Persentase Risiko & Label Risiko: Rendah/Sedang/Kritis).\n2. Estimasi Sisa Umur Operasional (RUL) dalam Hari/Bulan sebelum potensi kerusakan terjadi.\n3. Jadwal Tindakan Pencegahan Terperinci (Preventive Maintenance Schedule) yang harus dilakukan untuk menghindari breakdown total.\n4. Estimasi Biaya Pemeliharaan Preventif vs Estimasi Kerugian jika breakdown total terjadi.\n\nKeluaran dalam format Markdown yang rapi dan profesional.`;\n      }\n\n      const response = await getAIClient().models.generateContent({\n        model: \"gemini-3.5-flash\",\n        contents: prompt,\n      });\n\n      res.json({ insights: response.text });\n    } catch (error: any) {\n      console.error(\"Gemini API error during prediction:\", error);\n      res.status(500).json({ error: \"Gagal memproses prediksi cerdas dengan AI: \" + error.message });\n    }\n  });\n\n  // --------------------------------------------------------\n  // API: OPERATIONAL HUB (PROMOS, ADS, BUILDING, FACILITIES,\n  // PAYMENTS, GUEST CYCLES, COMPLAINTS, LOGS, MAINTENANCES)\n  // --------------------------------------------------------\n\n  // Get and Update Property Status\n  app.put(\"/api/properties/:id/status\", (req, res) => {\n    const { id } = req.params;\n    const { status } = req.body; // 'available' | 'rented' | 'sold' | 'maintenance' | 'dirty' | 'reserved'\n    const db = loadDB();\n    const property = db.properties.find((p: any) => p.id === id);\n    if (!property) {\n      return res.status(404).json({ error: \"Properti tidak ditemukan\" });\n    }\n    const oldStatus = property.status;\n    property.status = status;\n\n    // Log the action\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"system\",\n      message: `Status properti \"${property.name}\" diubah dari ${oldStatus} menjadi ${status}.`,\n      user: \"System Admin\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.json({ message: \"Status properti berhasil diperbarui!\", property });\n  });\n\n  // Move or Edit Transaction/Booking\n  app.put(\"/api/transactions/:id\", (req, res) => {\n    const { id } = req.params;\n    const { propertyId, startDate, endDate, totalPrice, type } = req.body;\n    const db = loadDB();\n    const transaction = db.transactions.find((t: any) => t.id === id);\n    if (!transaction) {\n      return res.status(404).json({ error: \"Transaksi tidak ditemukan\" });\n    }\n\n    const oldPropertyId = transaction.propertyId;\n    const oldPropertyName = transaction.propertyName;\n\n    if (propertyId && propertyId !== oldPropertyId) {\n      const newProperty = db.properties.find((p: any) => p.id === propertyId);\n      if (!newProperty) {\n        return res.status(404).json({ error: \"Properti baru tidak ditemukan\" });\n      }\n\n      // Revert status of old property if it was bound\n      const oldProperty = db.properties.find((p: any) => p.id === oldPropertyId);\n      if (oldProperty) {\n        oldProperty.status = \"available\";\n      }\n\n      // Update new property status\n      if (transaction.type === \"buy\" || type === \"buy\") {\n        newProperty.status = \"sold\";\n      } else if (transaction.type === \"rent\" || type === \"rent\") {\n        newProperty.status = \"rented\";\n      } else {\n        newProperty.status = \"reserved\";\n      }\n\n      transaction.propertyId = propertyId;\n      transaction.propertyName = newProperty.name;\n      transaction.propertyType = newProperty.type;\n    }\n\n    if (startDate) transaction.startDate = startDate;\n    if (endDate) transaction.endDate = endDate;\n    if (totalPrice) transaction.totalPrice = Number(totalPrice);\n    if (type) transaction.type = type;\n\n    // Log the change\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"user\",\n      message: `Pindah Pesanan: Transaksi #${id} dipindahkan dari \"${oldPropertyName}\" ke \"${transaction.propertyName}\".`,\n      user: transaction.buyerName || \"User\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.json({ message: \"Pemesanan berhasil dipindahkan / diubah!\", transaction });\n  });\n\n  // Promos\n  app.get(\"/api/promos\", (req, res) => {\n    const db = loadDB();\n    res.json(db.promos || []);\n  });\n\n  app.post(\"/api/promos\", (req, res) => {\n    const { code, discount, type, maxUse, description } = req.body;\n    if (!code || !discount || !type) {\n      return res.status(400).json({ error: \"Kode, diskon, dan jenis wajib diisi\" });\n    }\n    const db = loadDB();\n    const newPromo = {\n      id: \"p_\" + Date.now(),\n      code: code.toUpperCase(),\n      discount: Number(discount),\n      type, // 'promo' | 'coupon'\n      maxUse: maxUse ? Number(maxUse) : 100,\n      used: 0,\n      description: description || \"\"\n    };\n    db.promos = db.promos || [];\n    db.promos.push(newPromo);\n    saveDB(db);\n    res.status(201).json(newPromo);\n  });\n\n  // Advertisements\n  app.get(\"/api/advertisements\", (req, res) => {\n    const db = loadDB();\n    res.json(db.advertisements || []);\n  });\n\n  app.post(\"/api/advertisements\", (req, res) => {\n    const { title, imageUrl, link, section } = req.body;\n    if (!title || !imageUrl) {\n      return res.status(400).json({ error: \"Judul dan URL gambar wajib diisi\" });\n    }\n    const db = loadDB();\n    const newAd = {\n      id: \"ad_\" + Date.now(),\n      title,\n      imageUrl,\n      link: link || \"#\",\n      section: section || \"banner\",\n      status: \"active\"\n    };\n    db.advertisements = db.advertisements || [];\n    db.advertisements.push(newAd);\n    saveDB(db);\n    res.status(201).json(newAd);\n  });\n\n  // Buildings & Facilities\n  app.get(\"/api/buildings\", (req, res) => {\n    const db = loadDB();\n    res.json(db.buildings || []);\n  });\n\n  app.post(\"/api/buildings\", (req, res) => {\n    const { name, floors, address, unitCount } = req.body;\n    if (!name || !address) {\n      return res.status(400).json({ error: \"Nama gedung dan alamat wajib diisi\" });\n    }\n    const db = loadDB();\n    const newBuilding = {\n      id: \"b_\" + Date.now(),\n      name,\n      floors: floors ? Number(floors) : 1,\n      address,\n      unitCount: unitCount ? Number(unitCount) : 0\n    };\n    db.buildings = db.buildings || [];\n    db.buildings.push(newBuilding);\n    saveDB(db);\n    res.status(201).json(newBuilding);\n  });\n\n  app.get(\"/api/facilities\", (req, res) => {\n    const db = loadDB();\n    res.json(db.facilities || []);\n  });\n\n  app.post(\"/api/facilities\", (req, res) => {\n    const { name, type, status, location } = req.body;\n    if (!name || !type) {\n      return res.status(400).json({ error: \"Nama dan tipe fasilitas wajib diisi\" });\n    }\n    const db = loadDB();\n    const newFacility = {\n      id: \"f_\" + Date.now(),\n      name,\n      type,\n      status: status || \"Aktif\",\n      location: location || \"Gedung Utama\"\n    };\n    db.facilities = db.facilities || [];\n    db.facilities.push(newFacility);\n    saveDB(db);\n    res.status(201).json(newFacility);\n  });\n\n  app.put(\"/api/facilities/:id\", (req, res) => {\n    const { id } = req.params;\n    const { status, location, name } = req.body;\n    const db = loadDB();\n    const fac = db.facilities.find((f: any) => f.id === id);\n    if (!fac) {\n      return res.status(404).json({ error: \"Fasilitas tidak ditemukan\" });\n    }\n    if (status) fac.status = status;\n    if (location) fac.location = location;\n    if (name) fac.name = name;\n    saveDB(db);\n    res.json(fac);\n  });\n\n  // Payments / Billings\n  app.get(\"/api/payments\", (req, res) => {\n    const db = loadDB();\n    res.json(db.payments || []);\n  });\n\n  app.post(\"/api/payments\", (req, res) => {\n    const { transactionId, propertyName, totalAmount, amountPaid, paymentMethod, type, dueDate, notes } = req.body;\n    if (!propertyName || !totalAmount) {\n      return res.status(400).json({ error: \"Nama properti dan jumlah total tagihan wajib diisi\" });\n    }\n    const db = loadDB();\n    const newPayment = {\n      id: \"pay_\" + Date.now(),\n      transactionId: transactionId || \"\",\n      propertyName,\n      totalAmount: Number(totalAmount),\n      amountPaid: Number(amountPaid || 0),\n      paymentMethod: paymentMethod || \"Cash\",\n      type: type || \"lunas\", // 'DP' | 'lunas'\n      status: Number(amountPaid) >= Number(totalAmount) ? \"paid\" : \"pending\",\n      dueDate: dueDate || new Date(Date.now() + 7 * 24 * 3600 * 1000).toISOString().substring(0, 10),\n      notes: notes || \"\"\n    };\n    db.payments = db.payments || [];\n    db.payments.push(newPayment);\n    saveDB(db);\n    res.status(201).json(newPayment);\n  });\n\n  app.put(\"/api/payments/:id\", (req, res) => {\n    const { id } = req.params;\n    const { amountPaid, paymentMethod, status, notes } = req.body;\n    const db = loadDB();\n    const payment = db.payments.find((p: any) => p.id === id);\n    if (!payment) {\n      return res.status(404).json({ error: \"Tagihan tidak ditemukan\" });\n    }\n    if (amountPaid !== undefined) {\n      payment.amountPaid = Number(amountPaid);\n      payment.status = payment.amountPaid >= payment.totalAmount ? \"paid\" : \"pending\";\n    }\n    if (paymentMethod) payment.paymentMethod = paymentMethod;\n    if (status) payment.status = status;\n    if (notes) payment.notes = notes;\n\n    // Log payment action\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"app\",\n      message: `Konfirmasi Pembayaran: Tagihan #${id} (${payment.propertyName}) diperbarui. Terbayar: Rp ${payment.amountPaid.toLocaleString('id-ID')}.`,\n      user: \"Billing System\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.json(payment);\n  });\n\n  // Guest Cycles\n  app.get(\"/api/guest-cycles\", (req, res) => {\n    const db = loadDB();\n    res.json(db.guestCycles || []);\n  });\n\n  app.post(\"/api/guest-cycles\", (req, res) => {\n    const { guestName, propertyName, roomNumber, status, checkInTime } = req.body;\n    if (!guestName || !propertyName) {\n      return res.status(400).json({ error: \"Nama tamu dan nama properti wajib diisi\" });\n    }\n    const db = loadDB();\n    const newCycle = {\n      id: \"gc_\" + Date.now(),\n      guestName,\n      propertyName,\n      roomNumber: roomNumber || \"-\",\n      status: status || \"Reserved\", // 'Reserved' | 'Checked In' | 'Checked Out' | 'Cancelled'\n      checkInTime: checkInTime || \"-\",\n      checkOutTime: \"-\"\n    };\n    db.guestCycles = db.guestCycles || [];\n    db.guestCycles.push(newCycle);\n    saveDB(db);\n    res.status(201).json(newCycle);\n  });\n\n  app.put(\"/api/guest-cycles/:id\", (req, res) => {\n    const { id } = req.params;\n    const { status, roomNumber } = req.body;\n    const db = loadDB();\n    const cycle = db.guestCycles.find((g: any) => g.id === id);\n    if (!cycle) {\n      return res.status(404).json({ error: \"Siklus tamu tidak ditemukan\" });\n    }\n    const oldStatus = cycle.status;\n    if (status) {\n      cycle.status = status;\n      if (status === \"Checked In\") {\n        cycle.checkInTime = new Date().toISOString().replace('T', ' ').substring(0, 16);\n      } else if (status === \"Checked Out\") {\n        cycle.checkOutTime = new Date().toISOString().replace('T', ' ').substring(0, 16);\n      }\n    }\n    if (roomNumber) cycle.roomNumber = roomNumber;\n\n    // Log cycle change\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"user\",\n      message: `Siklus Tamu: Tamu \"${cycle.guestName}\" di properti \"${cycle.propertyName}\" diubah dari \"${oldStatus}\" menjadi \"${cycle.status}\".`,\n      user: \"Receptionist\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.json(cycle);\n  });\n\n  // Complaints\n  app.get(\"/api/complaints\", (req, res) => {\n    const db = loadDB();\n    res.json(db.complaints || []);\n  });\n\n  app.post(\"/api/complaints\", (req, res) => {\n    const { guestName, propertyName, title, description, category, priority } = req.body;\n    if (!guestName || !propertyName || !title || !description) {\n      return res.status(400).json({ error: \"Lengkapi data wajib pengaduan / komplain\" });\n    }\n    const db = loadDB();\n    const newComplaint = {\n      id: \"c_\" + Date.now(),\n      guestName,\n      propertyName,\n      title,\n      description,\n      category: category || \"Umum\",\n      priority: priority || \"Medium\",\n      status: \"pending\", // 'pending' | 'in_progress' | 'resolved'\n      resolution: \"\",\n      createdAt: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    };\n    db.complaints = db.complaints || [];\n    db.complaints.push(newComplaint);\n\n    // Log complaint creation\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"user\",\n      message: `Komplain Baru: Tamu \"${guestName}\" membuat aduan \"${title}\" untuk properti \"${propertyName}\".`,\n      user: guestName,\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.status(201).json(newComplaint);\n  });\n\n  app.put(\"/api/complaints/:id\", (req, res) => {\n    const { id } = req.params;\n    const { status, resolution } = req.body;\n    const db = loadDB();\n    const comp = db.complaints.find((c: any) => c.id === id);\n    if (!comp) {\n      return res.status(404).json({ error: \"Komplain tidak ditemukan\" });\n    }\n    if (status) comp.status = status;\n    if (resolution !== undefined) comp.resolution = resolution;\n\n    // Log resolution change\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"system\",\n      message: `Status Komplain #${id} diperbarui menjadi \"${status}\". Solusi: ${resolution || 'Tidak ada keterangan'}`,\n      user: \"Customer Service\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    saveDB(db);\n    res.json(comp);\n  });\n\n  // Webhook sender function\n  async function triggerWebhooks(event: string, payload: any) {\n    try {\n      const db = loadDB();\n      const activeWebhooks = (db.webhooks || []).filter((w: any) => w.status === \"active\" && w.events.includes(event));\n      if (activeWebhooks.length === 0) return;\n\n      for (const wh of activeWebhooks) {\n        // Send asynchronously to keep server response lightning-fast\n        fetch(wh.url, {\n          method: \"POST\",\n          headers: {\n            \"Content-Type\": \"application/json\",\n            \"X-Webhook-Event\": event,\n            \"X-Webhook-Secret\": wh.secret || \"\"\n          },\n          body: JSON.stringify({\n            event,\n            timestamp: new Date().toISOString(),\n            payload\n          })\n        }).then(async (response) => {\n          const dbLog = loadDB();\n          addSystemLog(dbLog, \"system\", `[WEBHOOK DELIVERED] Event \"${event}\" sukses dikirim ke \"${wh.name}\". HTTP Status: ${response.status}`);\n          saveDB(dbLog);\n        }).catch((err) => {\n          const dbLog = loadDB();\n          addSystemLog(dbLog, \"system\", `[WEBHOOK FAILED] Gagal mengirim event \"${event}\" ke \"${wh.name}\": ${err.message}`);\n          saveDB(dbLog);\n        });\n      }\n    } catch (err: any) {\n      console.error(\"Error sending webhooks:\", err.message);\n    }\n  }\n\n  // Logs API\n  app.get(\"/api/logs\", (req, res) => {\n    const db = loadDB();\n    res.json(db.logs || []);\n  });\n\n  app.post(\"/api/logs\", (req, res) => {\n    const { type, message, user } = req.body;\n    if (!message) return res.status(400).json({ error: \"Pesan log wajib diisi\" });\n    const db = loadDB();\n    \n    // Auto capture device, IP, location\n    addSystemLog(db, type || \"app\", message, user || \"System\", req);\n    saveDB(db);\n    \n    const latestLog = db.logs[db.logs.length - 1];\n    res.status(201).json(latestLog);\n  });\n\n  app.delete(\"/api/logs\", (req, res) => {\n    const db = loadDB();\n    const cleanLog = {\n      id: \"l_cleared_\" + Date.now(),\n      type: \"system\",\n      message: \"Seluruh log dibersihkan oleh Administrator.\",\n      user: \"Administrator\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),\n      ip: \"127.0.0.1\",\n      device: \"Desktop Browser\",\n      location: \"Jakarta, Indonesia\"\n    };\n    db.logs = [cleanLog];\n    saveDB(db);\n    res.json({ message: \"Log berhasil dibersihkan!\" });\n  });\n\n  // API Keys / Integration Credentials Settings API\n  app.get(\"/api/api-keys\", (req, res) => {\n    const db = loadDB();\n    res.json(db.apiKeys || []);\n  });\n\n  app.post(\"/api/api-keys\", (req, res) => {\n    const { name, permissions } = req.body;\n    if (!name) return res.status(400).json({ error: \"Nama integrasi / klien wajib diisi\" });\n    const db = loadDB();\n    db.apiKeys = db.apiKeys || [];\n    \n    const randomHex = Math.random().toString(16).substring(2, 10);\n    const key = `sh_live_${permissions === \"read-only\" ? \"ro\" : \"rw\"}_${randomHex}`;\n    const newKey = {\n      id: \"k_\" + Date.now(),\n      name,\n      key,\n      permissions: permissions || \"all\",\n      status: \"active\",\n      createdAt: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    };\n    db.apiKeys.push(newKey);\n    addSystemLog(db, \"system\", `[API KEY GENERATED] Kunci API baru dibuat: \"${name}\" (${permissions})`, \"Administrator\", req);\n    saveDB(db);\n    res.status(201).json(newKey);\n  });\n\n  app.delete(\"/api/api-keys/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    db.apiKeys = db.apiKeys || [];\n    const index = db.apiKeys.findIndex((k: any) => k.id === id);\n    if (index !== -1) {\n      const deleted = db.apiKeys.splice(index, 1)[0];\n      addSystemLog(db, \"system\", `[API KEY DELETED] Kunci API dicabut: \"${deleted.name}\"`, \"Administrator\", req);\n      saveDB(db);\n      return res.json({ message: \"Kunci API berhasil dicabut!\" });\n    }\n    res.status(404).json({ error: \"Kunci API tidak ditemukan!\" });\n  });\n\n  // Outgoing Webhooks API\n  app.get(\"/api/webhooks\", (req, res) => {\n    const db = loadDB();\n    res.json(db.webhooks || []);\n  });\n\n  app.post(\"/api/webhooks\", (req, res) => {\n    const { name, url, events } = req.body;\n    if (!name || !url) return res.status(400).json({ error: \"Nama dan URL Webhook wajib diisi\" });\n    const db = loadDB();\n    db.webhooks = db.webhooks || [];\n    \n    const secret = \"whsec_\" + Math.random().toString(16).substring(2, 10) + Math.random().toString(16).substring(2, 10);\n    const newWh = {\n      id: \"w_\" + Date.now(),\n      name,\n      url,\n      secret,\n      events: events && events.length ? events : [\"check_in\", \"check_out\"],\n      status: \"active\",\n      createdAt: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    };\n    db.webhooks.push(newWh);\n    addSystemLog(db, \"system\", `[WEBHOOK CREATED] Webhook baru didaftarkan: \"${name}\" ke target URL: ${url}`, \"Administrator\", req);\n    saveDB(db);\n    res.status(201).json(newWh);\n  });\n\n  app.put(\"/api/webhooks/:id\", (req, res) => {\n    const { id } = req.params;\n    const { name, url, events, status } = req.body;\n    const db = loadDB();\n    db.webhooks = db.webhooks || [];\n    const wh = db.webhooks.find((w: any) => w.id === id);\n    if (!wh) return res.status(404).json({ error: \"Webhook tidak ditemukan!\" });\n    \n    if (name !== undefined) wh.name = name;\n    if (url !== undefined) wh.url = url;\n    if (events !== undefined) wh.events = events;\n    if (status !== undefined) wh.status = status;\n    \n    addSystemLog(db, \"system\", `[WEBHOOK UPDATED] Webhook \"${wh.name}\" berhasil dikonfigurasi ulang`, \"Administrator\", req);\n    saveDB(db);\n    res.json({ message: \"Webhook berhasil diperbarui!\", webhook: wh });\n  });\n\n  app.delete(\"/api/webhooks/:id\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    db.webhooks = db.webhooks || [];\n    const index = db.webhooks.findIndex((w: any) => w.id === id);\n    if (index !== -1) {\n      const deleted = db.webhooks.splice(index, 1)[0];\n      addSystemLog(db, \"system\", `[WEBHOOK DELETED] Webhook dihapus: \"${deleted.name}\"`, \"Administrator\", req);\n      saveDB(db);\n      return res.json({ message: \"Webhook berhasil dihapus!\" });\n    }\n    res.status(404).json({ error: \"Webhook tidak ditemukan!\" });\n  });\n\n  app.post(\"/api/webhooks/:id/test\", async (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    const wh = (db.webhooks || []).find((w: any) => w.id === id);\n    if (!wh) return res.status(404).json({ error: \"Webhook tidak ditemukan!\" });\n\n    const payload = {\n      event: \"webhook_test\",\n      timestamp: new Date().toISOString(),\n      payload: {\n        message: \"Ini adalah pengiriman uji coba dari Sistem Properti Terintegrasi.\",\n        triggeredBy: \"Administrator\",\n        testUuid: Math.random().toString(36).substring(7)\n      }\n    };\n\n    try {\n      const controller = new AbortController();\n      const timeoutId = setTimeout(() => controller.abort(), 4000);\n\n      const response = await fetch(wh.url, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          \"X-Webhook-Event\": \"webhook_test\",\n          \"X-Webhook-Secret\": wh.secret || \"\"\n        },\n        body: JSON.stringify(payload),\n        signal: controller.signal\n      });\n\n      clearTimeout(timeoutId);\n\n      addSystemLog(db, \"system\", `[WEBHOOK TEST SUCCESS] Sukses mengetes webhook \"${wh.name}\". Status Respon: ${response.status}`, \"Administrator\", req);\n      saveDB(db);\n      res.json({ success: true, status: response.status });\n    } catch (err: any) {\n      addSystemLog(db, \"system\", `[WEBHOOK TEST ERROR] Gagal mengetes webhook \"${wh.name}\": ${err.message}`, \"Administrator\", req);\n      saveDB(db);\n      res.json({ success: false, error: err.message });\n    }\n  });\n\n  // Maintenance API (preventive, corrective, predictive)\n  app.get(\"/api/maintenances\", (req, res) => {\n    const db = loadDB();\n    res.json(db.maintenances || []);\n  });\n\n  app.post(\"/api/maintenances\", (req, res) => {\n    const { propertyId, propertyName, assetName, issue, type, cost } = req.body;\n    if (!propertyName || !assetName || !issue || !type) {\n      return res.status(400).json({ error: \"Nama properti, aset, masalah, dan jenis maintenance wajib diisi\" });\n    }\n    const db = loadDB();\n    const newMaint = {\n      id: \"m_\" + Date.now(),\n      propertyId: propertyId || \"\",\n      propertyName,\n      assetName,\n      issue,\n      type, // 'preventive' | 'corrective' | 'predictive'\n      status: \"pending\", // 'pending' | 'scheduled' | 'in_progress' | 'completed'\n      cost: cost ? Number(cost) : 0,\n      createdAt: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    };\n    db.maintenances = db.maintenances || [];\n    db.maintenances.push(newMaint);\n\n    // Add log\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"system\",\n      message: `Pemeliharaan Baru (${type}): Aset \"${assetName}\" di \"${propertyName}\" didaftarkan.`,\n      user: \"Maintenance Planner\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    // Tambahkan Notifikasi Otomatis\n    try {\n      const targetProp = db.properties.find((p: any) => p.id === propertyId || p.name === propertyName);\n      const targetUserId = targetProp ? targetProp.ownerId : \"1\";\n      createAndSimulateNotification(\n        db,\n        targetUserId,\n        `Tugas Pemeliharaan Baru (${type})`,\n        `Jadwal pemeliharaan baru didaftarkan untuk aset \"${assetName}\" di properti \"${propertyName}\". Status saat ini: Pending.`,\n        'maint'\n      );\n    } catch (e) {\n      console.error(\"Error creating maintenance notification:\", e);\n    }\n\n    saveDB(db);\n    res.status(201).json(newMaint);\n  });\n\n  app.put(\"/api/maintenances/:id\", (req, res) => {\n    const { id } = req.params;\n    const { status, cost } = req.body;\n    const db = loadDB();\n    const maint = db.maintenances.find((m: any) => m.id === id);\n    if (!maint) {\n      return res.status(404).json({ error: \"Pemeliharaan tidak ditemukan\" });\n    }\n    if (status) maint.status = status;\n    if (cost !== undefined) maint.cost = Number(cost);\n\n    // Add log\n    db.logs.push({\n      id: String(Date.now()),\n      type: \"system\",\n      message: `Status Pemeliharaan #${id} diubah menjadi \"${status}\". Biaya: Rp ${Number(maint.cost).toLocaleString('id-ID')}.`,\n      user: \"Technician Lead\",\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)\n    });\n\n    // Tambahkan Notifikasi Otomatis\n    try {\n      const targetProp = db.properties.find((p: any) => p.id === maint.propertyId || p.name === maint.propertyName);\n      const targetUserId = targetProp ? targetProp.ownerId : \"1\";\n      createAndSimulateNotification(\n        db,\n        targetUserId,\n        `Update Pemeliharaan: ${status.toUpperCase()}`,\n        `Status tugas pemeliharaan untuk aset \"${maint.assetName}\" di properti \"${maint.propertyName}\" diubah menjadi \"${status}\". Biaya saat ini: Rp ${Number(maint.cost).toLocaleString('id-ID')}.`,\n        'maint'\n         );\n    } catch (e) {\n      console.error(\"Error creating maintenance update notification:\", e);\n    }\n\n    saveDB(db);\n    res.json(maint);\n  });\n\n  // --------------------------------------------------------\n  // API: NOTIFIKASI, EMAIL & WHATSAPP SIMULATION\n  // --------------------------------------------------------\n\n  // Get notifications for a user (or all if superadmin)\n  app.get(\"/api/notifications\", (req, res) => {\n    const { userId } = req.query;\n    const db = loadDB();\n    db.notifications = db.notifications || [];\n    \n    if (!userId) {\n      return res.json(db.notifications);\n    }\n\n    const user = db.users.find((u: any) => u.id === String(userId));\n    if (user && user.roleId === \"3\") { // Superadmin\n      return res.json(db.notifications);\n    }\n\n    const filtered = db.notifications.filter((n: any) => String(n.userId) === String(userId));\n    res.json(filtered);\n  });\n\n  // Mark single notification as read\n  app.post(\"/api/notifications/:id/read\", (req, res) => {\n    const { id } = req.params;\n    const db = loadDB();\n    db.notifications = db.notifications || [];\n\n    const notif = db.notifications.find((n: any) => n.id === id);\n    if (notif) {\n      notif.read = true;\n      saveDB(db);\n      return res.json({ success: true, notification: notif });\n    }\n    res.status(404).json({ error: \"Notifikasi tidak ditemukan!\" });\n  });\n\n  // Mark all notifications as read for a user\n  app.post(\"/api/notifications/read-all\", (req, res) => {\n    const { userId } = req.body;\n    if (!userId) {\n      return res.status(400).json({ error: \"userId diperlukan!\" });\n    }\n    const db = loadDB();\n    db.notifications = db.notifications || [];\n\n    db.notifications.forEach((n: any) => {\n      if (String(n.userId) === String(userId)) {\n        n.read = true;\n      }\n    });\n\n    saveDB(db);\n    res.json({ success: true, message: \"Semua notifikasi ditandai telah dibaca.\" });\n  });\n\n  // POST: Manual simulation to send personalized Email & WhatsApp notifications\n  app.post(\"/api/notifications/simulate\", (req, res) => {\n    const { userId, title, message, type } = req.body;\n    if (!userId || !title || !message) {\n      return res.status(400).json({ error: \"userId, title, dan message diperlukan!\" });\n    }\n\n    const db = loadDB();\n    const newNotif = createAndSimulateNotification(db, userId, title, message, type || \"system\");\n    saveDB(db);\n\n    res.status(201).json({\n      message: \"Simulasi notifikasi berhasil dijalankan!\",\n      notification: newNotif\n    });\n  });\n\n  // API Endpoints for Cloud Backup & Google Drive Integration\n  app.get(\"/api/cloud/backups\", (req, res) => {\n    const backupDir = path.join(process.cwd(), \"propertyhub\", \"uploads\");\n    if (!fs.existsSync(backupDir)) {\n      fs.mkdirSync(backupDir, { recursive: true });\n    }\n    \n    try {\n      const files = fs.readdirSync(backupDir);\n      const backups = files\n        .filter(f => f.endsWith(\".zip\"))\n        .map(f => {\n          const filePath = path.join(backupDir, f);\n          const stat = fs.statSync(filePath);\n          return {\n            filename: f,\n            size: stat.size,\n            createdAt: stat.birthtime,\n            path: `/api/cloud/backup/download/${f}`\n          };\n        });\n      res.json(backups);\n    } catch (error: any) {\n      res.status(500).json({ error: \"Gagal membaca direktori backup: \" + error.message });\n    }\n  });\n\n  app.post(\"/api/cloud/backup/generate\", (req, res) => {\n    try {\n      const sourceDir = path.join(process.cwd(), \"propertyhub\");\n      const destDir = path.join(process.cwd(), \"propertyhub\", \"uploads\");\n      \n      if (!fs.existsSync(sourceDir)) {\n        return res.status(404).json({ error: \"Folder /propertyhub tidak ditemukan!\" });\n      }\n      \n      if (!fs.existsSync(destDir)) {\n        fs.mkdirSync(destDir, { recursive: true });\n      }\n      \n      const zipFilename = `propertyhub_combined_${Date.now()}.zip`;\n      const zipFilePath = path.join(destDir, zipFilename);\n      \n      const zip = new AdmZip();\n      \n      // Traverse propertyhub directory and add to ZIP\n      // Skip the uploads folder to prevent infinite recursion\n      const items = fs.readdirSync(sourceDir);\n      let fileCount = 0;\n      \n      items.forEach(item => {\n        if (item === \"uploads\") return; // Skip backups folder\n        \n        const itemPath = path.join(sourceDir, item);\n        const stat = fs.statSync(itemPath);\n        \n        if (stat.isDirectory()) {\n          zip.addLocalFolder(itemPath, item);\n          fileCount += countFiles(itemPath);\n        } else {\n          zip.addLocalFile(itemPath);\n          fileCount++;\n        }\n      });\n      \n      zip.writeZip(zipFilePath);\n      \n      const finalStat = fs.statSync(zipFilePath);\n      \n      // helper count files function\n      function countFiles(dir: string): number {\n        let count = 0;\n        const files = fs.readdirSync(dir);\n        files.forEach(f => {\n          const p = path.join(dir, f);\n          if (fs.statSync(p).isDirectory()) {\n            count += countFiles(p);\n          } else {\n            count++;\n          }\n        });\n        return count;\n      }\n\n      res.json({\n        success: true,\n        message: \"Codebase PropertyHub berhasil digabungkan menjadi satu file ZIP!\",\n        filename: zipFilename,\n        size: finalStat.size,\n        fileCount,\n        createdAt: finalStat.birthtime\n      });\n    } catch (e: any) {\n      res.status(500).json({ error: \"Gagal menggabungkan folder & file: \" + e.message });\n    }\n  });\n\n  // Serve static backups\n  app.get(\"/api/cloud/backup/download/:filename\", (req, res) => {\n    const { filename } = req.params;\n    const filePath = path.join(process.cwd(), \"propertyhub\", \"uploads\", filename);\n    if (fs.existsSync(filePath)) {\n      res.download(filePath);\n    } else {\n      res.status(404).send(\"File tidak ditemukan!\");\n    }\n  });\n\n  // Simulated Cloud Integration (Google Drive, Dropbox, S3)\n  app.post(\"/api/cloud/upload\", (req, res) => {\n    const { filename, provider, config } = req.body;\n    if (!filename) {\n      return res.status(400).json({ error: \"Filename diperlukan!\" });\n    }\n    \n    const filePath = path.join(process.cwd(), \"propertyhub\", \"uploads\", filename);\n    if (!fs.existsSync(filePath)) {\n      return res.status(404).json({ error: \"File backup tidak ditemukan di server!\" });\n    }\n    \n    // Simulate cloud upload latency and result\n    const size = fs.statSync(filePath).size;\n    \n    res.json({\n      success: true,\n      message: `Berhasil mengunggah ${filename} ke ${provider}!`,\n      details: {\n        provider,\n        filename,\n        fileSize: size,\n        cloudFileId: `cloud_file_${Math.random().toString(36).substring(2, 11)}`,\n        uploadedAt: new Date(),\n        storageUsed: `${(size / (1024 * 1024)).toFixed(2)} MB`,\n        backupUrl: `https://drive.google.com/open?id=simulated_${provider}_${Date.now()}`\n      }\n    });\n  });\n\n  // --------------------------------------------------------\n  // VITE & FRONTEND MOUNTING\n  // --------------------------------------------------------\n  if (process.env.NODE_ENV !== \"production\") {\n    const vite = await createViteServer({\n      server: {\n        middlewareMode: true,\n        hmr: false,\n        watch: null,\n      },\n      appType: \"spa\",\n    });\n    app.use(vite.middlewares);\n  } else {\n    const distPath = path.join(process.cwd(), \"dist\");\n    app.use(express.static(distPath));\n    app.get(\"*\", (req, res) => {\n      res.sendFile(path.join(distPath, \"index.html\"));\n    });\n  }\n\n  app.listen(PORT, \"0.0.0.0\", () => {\n    console.log(`Server is listening on http://0.0.0.0:${PORT}`);\n  });\n}\n\nstartServer();\n"],
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAKA,qBAAoB;AACpB,kBAAiB;AACjB,gBAAe;AACf,kBAAiD;AACjD,mBAA4B;AAC5B,oBAAO;AACP,qBAAmB;AAEnB,IAAI,WAA+B;AAEnC,SAAS,cAA2B;AAClC,MAAI,CAAC,UAAU;AACb,UAAM,SAAS,QAAQ,IAAI;AAC3B,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AACA,eAAW,IAAI,yBAAY;AAAA,MACzB;AAAA,MACA,aAAa;AAAA,QACX,SAAS;AAAA,UACP,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAiEA,IAAM,UAAU,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe;AAGxD,SAAS,SAAS;AAChB,MAAI,UAAAC,QAAG,WAAW,OAAO,GAAG;AAC1B,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,UAAAA,QAAG,aAAa,SAAS,OAAO,CAAC;AAE3D,UAAI,UAAU;AACd,UAAI,CAAC,OAAO,OAAO;AACjB,eAAO,QAAQ;AAAA,UACb,EAAE,IAAI,KAAK,UAAU,gBAAgB,aAAa,mEAAmE;AAAA,UACrH,EAAE,IAAI,KAAK,UAAU,iBAAiB,aAAa,6EAA6E;AAAA,UAChI,EAAE,IAAI,KAAK,UAAU,wBAAwB,aAAa,sEAAsE;AAAA,QAClI;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,aAAa;AACvB,eAAO,cAAc;AAAA,UACnB,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,kCAAkC;AAAA,UAC5F,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,+BAA+B;AAAA,UACzF,EAAE,IAAI,KAAK,eAAe,qBAAqB,aAAa,wCAAwC;AAAA,UACpG,EAAE,IAAI,KAAK,eAAe,kBAAkB,aAAa,kCAAkC;AAAA,UAC3F,EAAE,IAAI,KAAK,eAAe,gBAAgB,aAAa,wCAAwC;AAAA,UAC/F,EAAE,IAAI,KAAK,eAAe,iBAAiB,aAAa,wCAAwC;AAAA,UAChG,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,8BAA8B;AAAA,UACxF,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,kCAAkC;AAAA,UAC5F,EAAE,IAAI,KAAK,eAAe,eAAe,aAAa,kCAAkC;AAAA,UACxF,EAAE,IAAI,MAAM,eAAe,cAAc,aAAa,sCAAsC;AAAA,UAC5F,EAAE,IAAI,MAAM,eAAe,oBAAoB,aAAa,+BAA+B;AAAA,UAC3F,EAAE,IAAI,MAAM,eAAe,kBAAkB,aAAa,wCAAwC;AAAA,UAClG,EAAE,IAAI,MAAM,eAAe,qBAAqB,aAAa,oCAAoC;AAAA,UACjG,EAAE,IAAI,MAAM,eAAe,sBAAsB,aAAa,uCAAuC;AAAA,UACrG,EAAE,IAAI,MAAM,eAAe,sBAAsB,aAAa,iCAAiC;AAAA,UAC/F,EAAE,IAAI,MAAM,eAAe,gBAAgB,aAAa,yCAAyC;AAAA,QACnG;AACA,kBAAU;AAAA,MACZ,OAAO;AAEL,cAAM,qBAAqB;AAAA,UACzB,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,kCAAkC;AAAA,UAC5F,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,+BAA+B;AAAA,UACzF,EAAE,IAAI,KAAK,eAAe,qBAAqB,aAAa,wCAAwC;AAAA,UACpG,EAAE,IAAI,KAAK,eAAe,kBAAkB,aAAa,kCAAkC;AAAA,UAC3F,EAAE,IAAI,KAAK,eAAe,gBAAgB,aAAa,wCAAwC;AAAA,UAC/F,EAAE,IAAI,KAAK,eAAe,iBAAiB,aAAa,wCAAwC;AAAA,UAChG,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,8BAA8B;AAAA,UACxF,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,kCAAkC;AAAA,UAC5F,EAAE,IAAI,KAAK,eAAe,eAAe,aAAa,kCAAkC;AAAA,UACxF,EAAE,IAAI,MAAM,eAAe,cAAc,aAAa,sCAAsC;AAAA,UAC5F,EAAE,IAAI,MAAM,eAAe,oBAAoB,aAAa,+BAA+B;AAAA,UAC3F,EAAE,IAAI,MAAM,eAAe,kBAAkB,aAAa,wCAAwC;AAAA,UAClG,EAAE,IAAI,MAAM,eAAe,qBAAqB,aAAa,oCAAoC;AAAA,UACjG,EAAE,IAAI,MAAM,eAAe,sBAAsB,aAAa,uCAAuC;AAAA,UACrG,EAAE,IAAI,MAAM,eAAe,sBAAsB,aAAa,iCAAiC;AAAA,UAC/F,EAAE,IAAI,MAAM,eAAe,gBAAgB,aAAa,yCAAyC;AAAA,QACnG;AACA,mBAAW,MAAM,oBAAoB;AACnC,cAAI,CAAC,OAAO,YAAY,KAAK,CAAC,MAAW,EAAE,kBAAkB,GAAG,aAAa,GAAG;AAE9E,kBAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,YAAY,IAAI,CAAC,MAAW,MAAM,OAAO,EAAE,EAAE,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;AACvG,mBAAO,YAAY,KAAK;AAAA,cACtB,IAAI,OAAO,QAAQ,CAAC;AAAA,cACpB,eAAe,GAAG;AAAA,cAClB,aAAa,GAAG;AAAA,YAClB,CAAC;AACD,sBAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,OAAO,iBAAiB;AAC3B,eAAO,kBAAkB,CAAC;AAC1B,kBAAU;AAAA,MACZ;AAGA,YAAM,YAAY,CAAC,QAAgB;AACjC,cAAM,QAAQ,OAAO,YAAY,KAAK,CAAC,MAAW,EAAE,kBAAkB,GAAG;AACzE,eAAO,QAAQ,MAAM,KAAK;AAAA,MAC5B;AAEA,YAAM,mBAAmB;AAAA,QACvB,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,gBAAgB;AAAA,QACxC,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,iBAAiB;AAAA,QACzC,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,qBAAqB;AAAA,QAE7C,EAAE,QAAQ,KAAK,SAAS,oBAAoB;AAAA,QAE5C,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,gBAAgB;AAAA,QACxC,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,oBAAoB;AAAA,QAC5C,EAAE,QAAQ,KAAK,SAAS,iBAAiB;AAAA,QACzC,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,kBAAkB;AAAA,QAC1C,EAAE,QAAQ,KAAK,SAAS,cAAc;AAAA,QACtC,EAAE,QAAQ,KAAK,SAAS,aAAa;AAAA,QACrC,EAAE,QAAQ,KAAK,SAAS,mBAAmB;AAAA,QAC3C,EAAE,QAAQ,KAAK,SAAS,iBAAiB;AAAA,QACzC,EAAE,QAAQ,KAAK,SAAS,oBAAoB;AAAA,QAC5C,EAAE,QAAQ,KAAK,SAAS,qBAAqB;AAAA,QAC7C,EAAE,QAAQ,KAAK,SAAS,qBAAqB;AAAA,QAC7C,EAAE,QAAQ,KAAK,SAAS,eAAe;AAAA,QACvC,EAAE,QAAQ,KAAK,SAAS,eAAe;AAAA,MACzC;AAEA,iBAAW,OAAO,kBAAkB;AAClC,cAAM,MAAM,UAAU,IAAI,OAAO;AACjC,YAAI,KAAK;AACP,cAAI,CAAC,OAAO,gBAAgB,KAAK,CAAC,OAAY,GAAG,WAAW,IAAI,UAAU,GAAG,iBAAiB,GAAG,GAAG;AAClG,mBAAO,gBAAgB,KAAK,EAAE,QAAQ,IAAI,QAAQ,cAAc,IAAI,CAAC;AACrE,sBAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAEA,aAAO,QAAQ,OAAO,MAAM,IAAI,CAAC,MAAW;AAC1C,YAAI,CAAC,EAAE,QAAQ;AACb,YAAE,SAAS,EAAE,SAAS,UAAU,MAAM;AACtC,oBAAU;AAAA,QACZ;AACA,eAAO;AAAA,MACT,CAAC;AAED,UAAI,CAAC,OAAO,QAAQ;AAClB,eAAO,SAAS;AAAA,UACd,EAAE,IAAI,MAAM,MAAM,WAAW,UAAU,KAAO,MAAM,UAAU,QAAQ,KAAK,MAAM,IAAI,aAAa,yCAAyC;AAAA,UAC3I,EAAE,IAAI,MAAM,MAAM,eAAe,UAAU,KAAQ,MAAM,SAAS,QAAQ,IAAI,MAAM,GAAG,aAAa,4CAA4C;AAAA,QAClJ;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,OAAO;AACjB,eAAO,QAAQ;AAAA,UACb;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,YAAY,yBAAyB,YAAY,YAAY,kBAAkB;AAAA,YAClG,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,YAAY,oBAAoB,WAAW,YAAY,qBAAqB,SAAS;AAAA,YACxG,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC,2BAA2B;AAAA,UAC3C;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,gBAAgB,cAAc,WAAW,qBAAqB,sBAAsB,cAAc;AAAA,YAC/G,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,gBAAgB,UAAU,MAAM,kBAAkB,sBAAsB,cAAc;AAAA,YACnG,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC,2BAA2B;AAAA,UAC3C;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,cAAc,eAAe,MAAM,eAAe,UAAU,YAAY,SAAS;AAAA,YAC9F,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,eAAe,cAAc,SAAS,mBAAmB,WAAW;AAAA,YACvF,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC,2BAA2B;AAAA,UAC3C;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,WAAW,WAAW,eAAe,cAAc,kBAAkB;AAAA,YACxF,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,oBAAoB,kBAAkB,kBAAkB,UAAU;AAAA,YACrF,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,eAAe,cAAc,gBAAgB,UAAU;AAAA,YACpE,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,qBAAqB,gBAAgB,SAAS,YAAY;AAAA,YAC7E,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC;AAAA,UAChB;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,YAAY,CAAC,MAAM,qBAAqB,gBAAgB,kBAAkB,oBAAoB,WAAW;AAAA,YACzG,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,UAAU;AAAA,YACV,aAAa,CAAC,2BAA2B;AAAA,UAC3C;AAAA,QACF;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,gBAAgB;AAC1B,eAAO,iBAAiB;AAAA,UACtB,EAAE,IAAI,OAAO,OAAO,kDAAkD,UAAU,gGAAgG,MAAM,KAAK,SAAS,WAAW,QAAQ,SAAS;AAAA,UAChO,EAAE,IAAI,OAAO,OAAO,6DAA6D,UAAU,6FAA6F,MAAM,KAAK,SAAS,UAAU,QAAQ,SAAS;AAAA,QACzO;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,WAAW;AACrB,eAAO,YAAY;AAAA,UACjB,EAAE,IAAI,MAAM,MAAM,yBAAyB,QAAQ,IAAI,SAAS,kCAAkC,WAAW,IAAI;AAAA,UACjH,EAAE,IAAI,MAAM,MAAM,wBAAwB,QAAQ,GAAG,SAAS,iCAAiC,WAAW,EAAE;AAAA,QAC9G;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,YAAY;AACtB,eAAO,aAAa;AAAA,UAClB,EAAE,IAAI,MAAM,MAAM,yBAAyB,MAAM,YAAY,QAAQ,SAAS,UAAU,mBAAmB;AAAA,UAC3G,EAAE,IAAI,MAAM,MAAM,wBAAwB,MAAM,aAAa,QAAQ,eAAe,UAAU,4BAA4B;AAAA,UAC1H,EAAE,IAAI,MAAM,MAAM,4BAA4B,MAAM,UAAU,QAAQ,SAAS,UAAU,mBAAmB;AAAA,QAC9G;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,UAAU;AACpB,eAAO,WAAW;AAAA,UAChB,EAAE,IAAI,QAAQ,eAAe,OAAO,cAAc,qBAAqB,aAAa,MAAS,YAAY,KAAQ,eAAe,2BAA2B,MAAM,MAAM,QAAQ,QAAQ,SAAS,cAAc,OAAO,yCAAyC;AAAA,UAC9P,EAAE,IAAI,QAAQ,eAAe,OAAO,cAAc,6BAA6B,aAAa,MAAS,YAAY,MAAS,eAAe,eAAe,MAAM,SAAS,QAAQ,QAAQ,SAAS,cAAc,OAAO,uCAAuC;AAAA,UAC5P,EAAE,IAAI,QAAQ,eAAe,OAAO,cAAc,uBAAuB,aAAa,MAAS,YAAY,GAAG,eAAe,kBAAkB,MAAM,SAAS,QAAQ,WAAW,SAAS,cAAc,OAAO,4CAA4C;AAAA,QAC7P;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,aAAa;AACvB,eAAO,cAAc;AAAA,UACnB,EAAE,IAAI,OAAO,WAAW,sBAAsB,cAAc,qBAAqB,YAAY,OAAO,QAAQ,cAAc,aAAa,oBAAoB,cAAc,IAAI;AAAA,UAC7K,EAAE,IAAI,OAAO,WAAW,gBAAgB,cAAc,uBAAuB,YAAY,QAAQ,QAAQ,YAAY,aAAa,oBAAoB,cAAc,IAAI;AAAA,UACxK,EAAE,IAAI,OAAO,WAAW,iBAAiB,cAAc,6BAA6B,YAAY,QAAQ,QAAQ,eAAe,aAAa,oBAAoB,cAAc,mBAAmB;AAAA,QACnM;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,YAAY;AACtB,eAAO,aAAa;AAAA,UAClB,EAAE,IAAI,MAAM,WAAW,sBAAsB,cAAc,qBAAqB,OAAO,0BAA0B,aAAa,qGAAqG,UAAU,aAAa,UAAU,QAAQ,QAAQ,eAAe,YAAY,8CAA8C,WAAW,mBAAmB;AAAA,UAC3X,EAAE,IAAI,MAAM,WAAW,eAAe,cAAc,6BAA6B,OAAO,kBAAkB,aAAa,yEAAyE,UAAU,WAAW,UAAU,UAAU,QAAQ,YAAY,YAAY,2EAA2E,WAAW,mBAAmB;AAAA,QACpX;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,MAAM;AAChB,eAAO,OAAO;AAAA,UACZ,EAAE,IAAI,MAAM,MAAM,QAAQ,SAAS,qEAAqE,MAAM,gBAAgB,WAAW,mBAAmB;AAAA,UAC5J,EAAE,IAAI,MAAM,MAAM,UAAU,SAAS,kDAAkD,MAAM,UAAU,WAAW,mBAAmB;AAAA,UACrI,EAAE,IAAI,MAAM,MAAM,OAAO,SAAS,6EAA6E,MAAM,kBAAkB,WAAW,mBAAmB;AAAA,QACvK;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,cAAc;AACxB,eAAO,eAAe;AAAA,UACpB,EAAE,IAAI,MAAM,YAAY,KAAK,cAAc,qBAAqB,WAAW,0BAA0B,OAAO,4CAA4C,MAAM,cAAc,QAAQ,aAAa,MAAM,MAAS,WAAW,mBAAmB;AAAA,UAC9O,EAAE,IAAI,MAAM,YAAY,KAAK,cAAc,6BAA6B,WAAW,mBAAmB,OAAO,4CAA4C,MAAM,cAAc,QAAQ,eAAe,MAAM,MAAS,WAAW,mBAAmB;AAAA,UACjP,EAAE,IAAI,MAAM,YAAY,KAAK,cAAc,0BAA0B,WAAW,uBAAuB,OAAO,iDAAiD,MAAM,cAAc,QAAQ,WAAW,MAAM,KAAQ,WAAW,mBAAmB;AAAA,QACpP;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,SAAS;AACnB,eAAO,UAAU;AAAA,UACf,EAAE,IAAI,MAAM,MAAM,+BAA+B,KAAK,sBAAsB,aAAa,OAAO,QAAQ,UAAU,WAAW,mBAAmB;AAAA,UAChJ,EAAE,IAAI,MAAM,MAAM,8BAA8B,KAAK,sBAAsB,aAAa,aAAa,QAAQ,UAAU,WAAW,mBAAmB;AAAA,QACvJ;AACA,kBAAU;AAAA,MACZ;AACA,UAAI,CAAC,OAAO,UAAU;AACpB,eAAO,WAAW;AAAA,UAChB,EAAE,IAAI,MAAM,MAAM,qCAAqC,KAAK,kDAAkD,QAAQ,wBAAwB,QAAQ,CAAC,aAAa,qBAAqB,GAAG,QAAQ,UAAU,WAAW,mBAAmB;AAAA,UAC5O,EAAE,IAAI,MAAM,MAAM,wBAAwB,KAAK,4BAA4B,QAAQ,0BAA0B,QAAQ,CAAC,YAAY,aAAa,sBAAsB,uBAAuB,GAAG,QAAQ,YAAY,WAAW,mBAAmB;AAAA,QACnP;AACA,kBAAU;AAAA,MACZ;AAEA,UAAI,OAAO,YAAY;AACrB,eAAO,aAAa,OAAO,WAAW,IAAI,CAAC,MAAW;AACpD,cAAI,UAAU;AACd,cAAI,CAAC,EAAE,cAAc;AACnB,gBAAI,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC1B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,gBACnC,GAAE,eAAe;AACtB,sBAAU;AAAA,UACZ;AACA,cAAI,CAAC,EAAE,cAAc;AACnB,gBAAI,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC1B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,qBAC/B,EAAE,OAAO,IAAK,GAAE,eAAe;AAAA,gBACnC,GAAE,eAAe;AACtB,sBAAU;AAAA,UACZ;AACA,cAAI,CAAC,EAAE,aAAa;AAClB,cAAE,cAAc,kCAAkC,mBAAmB,EAAE,OAAO,CAAC;AAC/E,sBAAU;AAAA,UACZ;AACA,cAAI,QAAS,WAAU;AACvB,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,SAAS;AACX,eAAO,MAAM;AAAA,MACf;AACA,aAAO;AAAA,IACT,SAAS,GAAG;AACV,cAAQ,MAAM,6CAA6C,CAAC;AAAA,IAC9D;AAAA,EACF;AAGA,QAAM,cAAc;AAAA,IAClB,OAAO;AAAA,MACL,EAAE,IAAI,KAAK,UAAU,gBAAgB,aAAa,mEAAmE;AAAA,MACrH,EAAE,IAAI,KAAK,UAAU,iBAAiB,aAAa,6EAA6E;AAAA,MAChI,EAAE,IAAI,KAAK,UAAU,wBAAwB,aAAa,sEAAsE;AAAA,IAClI;AAAA,IACA,aAAa;AAAA,MACX,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,4CAA4C;AAAA,MACtG,EAAE,IAAI,KAAK,eAAe,mBAAmB,aAAa,mCAAmC;AAAA,MAC7F,EAAE,IAAI,KAAK,eAAe,qBAAqB,aAAa,yCAAyC;AAAA,MACrG,EAAE,IAAI,KAAK,eAAe,kBAAkB,aAAa,sCAAsC;AAAA,MAC/F,EAAE,IAAI,KAAK,eAAe,gBAAgB,aAAa,0CAA0C;AAAA,IACnG;AAAA,IACA,iBAAiB;AAAA,MACf,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,MACjC,EAAE,QAAQ,KAAK,cAAc,IAAI;AAAA,IACnC;AAAA,IACA,OAAO;AAAA,MACL;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,IACF;AAAA,IACA,cAAc;AAAA,MACZ;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,cAAc;AAAA,QACd,MAAM;AAAA,QACN,WAAW;AAAA,QACX,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,cAAc;AAAA,QACd,MAAM;AAAA,QACN,WAAW;AAAA,QACX,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,YAAAA,QAAG,cAAc,SAAS,KAAK,UAAU,aAAa,MAAM,CAAC,GAAG,OAAO;AACvE,SAAO;AACT;AAEA,SAAS,OAAO,MAAW;AACzB,YAAAA,QAAG,cAAc,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAClE;AAGA,SAAS,gBAAgB,MAAW,IAAS;AAC3C,QAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,KAAK,MAAM,KAAK,EAAE,IAAI,KAAK,UAAU,iBAAiB,aAAa,GAAG;AACtH,QAAM,aAAa,GAAG,gBAAgB,OAAO,CAAC,OAAY,GAAG,WAAW,KAAK,EAAE;AAC/E,QAAM,gBAAgB,WAAW,IAAI,CAAC,OAAY,GAAG,YAAY;AACjE,QAAM,oBAAoB,GAAG,YAC1B,OAAO,CAAC,MAAW,cAAc,SAAS,EAAE,EAAE,CAAC,EAC/C,IAAI,CAAC,MAAW,EAAE,aAAa;AAElC,MAAI,WAAuD;AAC3D,MAAI,KAAK,OAAO,IAAK,YAAW;AAAA,WACvB,KAAK,OAAO,IAAK,YAAW;AAAA,WAC5B,KAAK,OAAO,IAAK,YAAW;AAAA,WAC5B,KAAK,OAAO,IAAK,YAAW;AAErC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,KAAK;AAAA,IACf,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AACF;AAEA,eAAe,cAAc;AAC3B,QAAM,UAAM,eAAAC,SAAQ;AACpB,QAAM,OAAO;AAEb,MAAI,IAAI,eAAAA,QAAQ,KAAK,CAAC;AAGtB,SAAO;AAGP,WAAS,WAAW,KAAsB;AACxC,QAAI,MAAM,IAAI,QAAQ,iBAAiB,KAAe,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,KAAK,IAAI,MAAM,IAAI,OAAO,iBAAiB;AACxH,QAAI,OAAO,SAAS,OAAO,oBAAoB;AAC7C,WAAK;AAAA,IACP;AAEA,UAAM,KAAK,IAAI,QAAQ,YAAY,KAAK;AACxC,QAAI,SAAS;AACb,QAAI,UAAU,KAAK,EAAE,GAAG;AACtB,UAAI,oBAAoB,KAAK,EAAE,EAAG,UAAS;AAAA,eAClC,WAAW,KAAK,EAAE,EAAG,UAAS;AAAA,UAClC,UAAS;AAAA,IAChB,WAAW,WAAW,KAAK,EAAE,GAAG;AAC9B,eAAS;AAAA,IACX,WAAW,aAAa,KAAK,EAAE,GAAG;AAChC,eAAS;AAAA,IACX,WAAW,SAAS,KAAK,EAAE,GAAG;AAC5B,eAAS;AAAA,IACX,WAAW,IAAI;AACb,eAAS,GAAG,UAAU,GAAG,EAAE;AAAA,IAC7B;AAEA,QAAI,WAAW;AACf,UAAM,aAAa,IAAI,QAAQ,cAAc,KAAK,IAAI,QAAQ,qBAAqB,KAAK,IAAI,QAAQ,sBAAsB;AAC1H,UAAM,UAAU,IAAI,QAAQ,mBAAmB,KAAK,IAAI,QAAQ,kBAAkB;AAClF,QAAI,YAAY;AACd,iBAAW,UAAU,GAAG,OAAO,KAAK,UAAU,KAAK,OAAO,UAAU;AAAA,IACtE,WAAW,OAAO,eAAe,CAAC,GAAG,WAAW,MAAM,KAAK,CAAC,GAAG,WAAW,UAAU,GAAG;AACrF,YAAM,aAAa,CAAC,sBAAsB,uBAAuB,oBAAoB,sBAAsB,aAAa,qBAAqB;AAC7I,UAAI,OAAO;AACX,eAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,eAAO,GAAG,WAAW,CAAC,MAAM,QAAQ,KAAK;AAAA,MAC3C;AACA,YAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,WAAW;AAC1C,iBAAW,WAAW,KAAK;AAAA,IAC7B;AAEA,WAAO,EAAE,IAAI,QAAQ,SAAS;AAAA,EAChC;AAGA,WAAS,aAAa,IAAS,MAAc,SAAiB,MAAe,KAAuB;AAClG,OAAG,OAAO,GAAG,QAAQ,CAAC;AAEtB,QAAI,KAAK;AACT,QAAI,SAAS;AACb,QAAI,WAAW;AAEf,QAAI,KAAK;AACP,YAAM,OAAO,WAAW,GAAG;AAC3B,WAAK,KAAK;AACV,eAAS,KAAK;AACd,iBAAW,KAAK;AAAA,IAClB;AAEA,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,SAAS,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,GAAI;AAAA,MAC/D,MAAM,QAAQ;AAAA,MACd;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MACrE;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,GAAG,KAAK,SAAS,KAAK;AACxB,SAAG,OAAO,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,GAAG;AAAA,IAC9C;AAAA,EACF;AAGA,MAAI,IAAI,CAAC,KAAK,KAAK,SAAS;AAC1B,QAAI,IAAI,YAAY,WAAW,MAAM,KAAK,CAAC,IAAI,YAAY,WAAW,WAAW,GAAG;AAClF,YAAM,QAAQ,KAAK,IAAI;AACvB,UAAI,GAAG,UAAU,MAAM;AACrB,cAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,cAAM,KAAK,OAAO;AAElB,cAAM,UAAU,iBAAiB,IAAI,MAAM,IAAI,IAAI,WAAW,cAAc,IAAI,UAAU,KAAK,QAAQ;AACvG,cAAM,YAAY,IAAI,QAAQ,YAAY,IAAI,IAAI,QAAQ,YAAY,EAAE,UAAU,GAAG,EAAE,IAAI;AAE3F,qBAAa,IAAI,OAAO,SAAS,WAAW,GAAG;AAC/C,eAAO,EAAE;AAAA,MACX,CAAC;AAAA,IACH;AACA,SAAK;AAAA,EACP,CAAC;AAGD,WAAS,8BAA8B,IAAS,QAAgB,OAAe,SAAiB,MAAc;AAC5G,OAAG,gBAAgB,GAAG,iBAAiB,CAAC;AACxC,UAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,OAAO,MAAM,CAAC;AAC9D,UAAM,eAAe,OAAO,KAAK,QAAQ;AACzC,UAAM,cAAc,OAAO,KAAK,QAAQ;AACxC,UAAM,eAAe,OAAO,KAAK,WAAW;AAE5C,UAAM,UAAU,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,GAAI;AACzE,UAAM,WAAW;AAAA,MACf,IAAI;AAAA,MACJ,QAAQ,OAAO,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,UAAU;AAAA,QACR,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,iBAAiB,KAAK;AAAA,QACjC;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS,QAAQ,YAAY,qCAAqC,OAAO;AAAA,QAC3E;AAAA,MACF;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE;AAEA,OAAG,cAAc,KAAK,QAAQ;AAG9B,OAAG,OAAO,GAAG,QAAQ,CAAC;AACtB,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,SAAS,KAAK,IAAI,IAAI,YAAY,KAAK,MAAM,KAAK,OAAO,IAAI,GAAI;AAAA,MACrE,MAAM;AAAA,MACN,SAAS,yCAAyC,YAAY,oBAAoB,WAAW,aAAa,KAAK;AAAA,MAC/G,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO;AAAA,EACT;AAOA,MAAI,IAAI,cAAc,CAAC,KAAK,QAAQ;AAClC,UAAM,KAAK,OAAO;AAClB,UAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,MAAY,gBAAgB,GAAG,EAAE,CAAC;AACtE,QAAI,KAAK,aAAa;AAAA,EACxB,CAAC;AAGD,MAAI,IAAI,uBAAuB,CAAC,KAAK,QAAQ;AAC3C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,OAAO,IAAI,IAAI;AACvB,QAAI,CAAC,QAAQ;AACX,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iCAAiC,CAAC;AAAA,IACzE;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAY,EAAE,OAAO,EAAE;AACnD,QAAI,CAAC,MAAM;AACT,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,aAAa,GAAG,MAAM,KAAK,CAAC,MAAY,EAAE,OAAO,MAAM;AAC7D,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAAA,IAC/D;AAEA,SAAK,SAAS;AACd,WAAO,EAAE;AAET,QAAI,KAAK,EAAE,SAAS,sCAAsC,MAAM,gBAAgB,MAAM,EAAE,EAAE,CAAC;AAAA,EAC7F,CAAC;AAGD,MAAI,KAAK,cAAc,CAAC,KAAK,QAAQ;AACnC,UAAM,EAAE,UAAU,OAAO,UAAU,OAAO,QAAQ,WAAW,IAAI,IAAI;AACrE,QAAI,CAAC,YAAY,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ;AACzD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,6EAA6E,CAAC;AAAA,IACrH;AAEA,UAAM,KAAK,OAAO;AAClB,QAAI,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY,KAAK,EAAE,MAAM,YAAY,MAAM,MAAM,YAAY,CAAC,GAAG;AACnI,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0DAA0D,CAAC;AAAA,IAClG;AAEA,UAAM,UAAU;AAAA,MACd,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,cAAc;AAAA,IAC5B;AAEA,OAAG,MAAM,KAAK,OAAO;AACrB,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,kCAAkC,MAAM,gBAAgB,SAAS,EAAE,EAAE,CAAC;AAAA,EACxG,CAAC;AAGD,MAAI,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,UAAU,OAAO,UAAU,OAAO,QAAQ,WAAW,IAAI,IAAI;AACrE,QAAI,CAAC,YAAY,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,QAAQ;AACzD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sCAAsC,CAAC;AAAA,IAC9E;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,YAAY,GAAG,MAAM,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAC5D,QAAI,cAAc,IAAI;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,QAAI,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,OAAO,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY,KAAK,EAAE,MAAM,YAAY,MAAM,MAAM,YAAY,EAAE,GAAG;AACpJ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0DAA0D,CAAC;AAAA,IAClG;AAEA,OAAG,MAAM,SAAS,IAAI;AAAA,MACpB,GAAG,GAAG,MAAM,SAAS;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,cAAc;AAAA,IAC5B;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,sCAAsC,MAAM,gBAAgB,GAAG,MAAM,SAAS,GAAG,EAAE,EAAE,CAAC;AAAA,EAC5G,CAAC;AAGD,MAAI,OAAO,kBAAkB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACxD,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,OAAG,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAW,EAAE,OAAO,EAAE;AAClD,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,6BAA6B,CAAC;AAAA,EACpD,CAAC;AAGD,MAAI,KAAK,cAAc,CAAC,KAAK,QAAQ;AACnC,UAAM,EAAE,UAAU,YAAY,IAAI,IAAI;AACtC,QAAI,CAAC,YAAY,CAAC,aAAa;AAC7B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mDAAmD,CAAC;AAAA,IAC3F;AAEA,UAAM,KAAK,OAAO;AAClB,QAAI,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY,CAAC,GAAG;AAClF,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,IACtE;AAEA,UAAM,UAAU;AAAA,MACd,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAEA,OAAG,MAAM,KAAK,OAAO;AACrB,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,oCAAoC,MAAM,QAAQ,CAAC;AAAA,EACrF,CAAC;AAGD,MAAI,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,UAAU,YAAY,IAAI,IAAI;AACtC,QAAI,CAAC,YAAY,CAAC,aAAa;AAC7B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,wCAAwC,CAAC;AAAA,IAChF;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,YAAY,GAAG,MAAM,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAC5D,QAAI,cAAc,IAAI;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IACjE;AAEA,QAAI,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,MAAM,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY,CAAC,GAAG;AACjG,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,IACtE;AAEA,OAAG,MAAM,SAAS,IAAI;AAAA,MACpB,GAAG,GAAG,MAAM,SAAS;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,8BAA8B,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;AAAA,EAC/E,CAAC;AAGD,MAAI,OAAO,kBAAkB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,QAAI,CAAC,KAAK,KAAK,KAAK,GAAG,EAAE,SAAS,EAAE,GAAG;AACrC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mHAAmH,CAAC;AAAA,IAC3J;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACxD,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IACjE;AAEA,OAAG,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAW,EAAE,OAAO,EAAE;AAElD,OAAG,kBAAkB,GAAG,gBAAgB,OAAO,CAAC,OAAY,GAAG,WAAW,EAAE;AAG5E,OAAG,MAAM,QAAQ,CAAC,MAAW;AAC3B,UAAI,EAAE,WAAW,IAAI;AACnB,UAAE,SAAS;AAAA,MACb;AAAA,IACF,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,4EAA4E,CAAC;AAAA,EACnG,CAAC;AAGD,MAAI,KAAK,oBAAoB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,eAAe,YAAY,IAAI,IAAI;AAC3C,QAAI,CAAC,iBAAiB,CAAC,aAAa;AAClC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sDAAsD,CAAC;AAAA,IAC9F;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,gBAAgB,cAAc,YAAY,EAAE,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAC5E,QAAI,GAAG,YAAY,KAAK,CAAC,MAAW,EAAE,kBAAkB,aAAa,GAAG;AACtE,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,gBAAgB;AAAA,MACpB,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB,eAAe;AAAA,MACf;AAAA,IACF;AAEA,OAAG,YAAY,KAAK,aAAa;AACjC,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,uCAAuC,YAAY,cAAc,CAAC;AAAA,EACpG,CAAC;AAGD,MAAI,IAAI,wBAAwB,CAAC,KAAK,QAAQ;AAC5C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,eAAe,YAAY,IAAI,IAAI;AAC3C,QAAI,CAAC,iBAAiB,CAAC,aAAa;AAClC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sCAAsC,CAAC;AAAA,IAC9E;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,YAAY,GAAG,YAAY,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAClE,QAAI,cAAc,IAAI;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,gBAAgB,cAAc,YAAY,EAAE,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAC5E,QAAI,GAAG,YAAY,KAAK,CAAC,MAAW,EAAE,OAAO,MAAM,EAAE,kBAAkB,aAAa,GAAG;AACrF,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4CAA4C,CAAC;AAAA,IACpF;AAEA,OAAG,YAAY,SAAS,IAAI;AAAA,MAC1B,GAAG,GAAG,YAAY,SAAS;AAAA,MAC3B,eAAe;AAAA,MACf;AAAA,IACF;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,iCAAiC,YAAY,GAAG,YAAY,SAAS,EAAE,CAAC;AAAA,EAC9F,CAAC;AAGD,MAAI,OAAO,wBAAwB,CAAC,KAAK,QAAQ;AAC/C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG,YAAY,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC9D,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,OAAG,cAAc,GAAG,YAAY,OAAO,CAAC,MAAW,EAAE,OAAO,EAAE;AAE9D,OAAG,kBAAkB,GAAG,gBAAgB,OAAO,CAAC,OAAY,GAAG,iBAAiB,EAAE;AAElF,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,yCAAyC,CAAC;AAAA,EAChE,CAAC;AAGD,MAAI,IAAI,cAAc,CAAC,KAAK,QAAQ;AAClC,UAAM,KAAK,OAAO;AAClB,UAAM,uBAAuB,GAAG,MAAM,IAAI,CAAC,MAAY;AACrD,YAAM,KAAK,GAAG,gBAAgB,OAAO,CAAC,YAA4B,QAAQ,WAAW,EAAE,EAAE;AACzF,YAAM,oBAAoB,GAAG,YAAY;AAAA,QAAO,CAAC,MAC/C,GAAG,KAAK,CAAC,YAA4B,QAAQ,iBAAiB,EAAE,EAAE;AAAA,MACpE;AACA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,aAAa;AAAA,MACf;AAAA,IACF,CAAC;AACD,QAAI,KAAK,oBAAoB;AAAA,EAC/B,CAAC;AAGD,MAAI,IAAI,oBAAoB,CAAC,KAAK,QAAQ;AACxC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,WAAW;AAAA,EACzB,CAAC;AAGD,MAAI,KAAK,8BAA8B,CAAC,KAAK,QAAQ;AACnD,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,cAAc,IAAI,IAAI;AAC9B,QAAI,CAAC,MAAM,QAAQ,aAAa,GAAG;AACjC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kDAAkD,CAAC;AAAA,IAC1F;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG,MAAM,KAAK,CAAC,MAAY,EAAE,OAAO,EAAE;AACzD,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,wBAAwB,CAAC;AAAA,IAChE;AAGA,OAAG,kBAAkB,GAAG,gBAAgB,OAAO,CAAC,OAAuB,GAAG,WAAW,EAAE;AACvF,kBAAc,QAAQ,CAAC,QAAgB;AACrC,SAAG,gBAAgB,KAAK,EAAE,QAAQ,IAAI,cAAc,OAAO,GAAG,EAAE,CAAC;AAAA,IACnE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,0CAA0C,CAAC;AAAA,EACjE,CAAC;AAKD,MAAI,KAAK,sBAAsB,CAAC,KAAK,QAAQ;AAC3C,UAAM,EAAE,UAAU,OAAO,UAAU,OAAO,MAAM,SAAS,IAAI,IAAI;AACjE,QAAI,CAAC,YAAY,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM;AACvD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAAA,IACnE;AAEA,UAAM,KAAK,OAAO;AAClB,QAAI,GAAG,MAAM,KAAK,CAAC,MAAY,EAAE,aAAa,YAAY,EAAE,UAAU,KAAK,GAAG;AAC5E,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAAA,IAC/E;AAGA,UAAM,eAAe,SAAS,UAAU,MAAM;AAE9C,UAAM,UAAwC;AAAA,MAC5C,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,UAAU,YAAY;AAAA,IACxB;AAEA,OAAG,MAAM,KAAK,OAAO;AACrB,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,wBAAwB,MAAM,gBAAgB,SAAS,EAAE,EAAE,CAAC;AAAA,EAC9F,CAAC;AAED,MAAI,KAAK,mBAAmB,CAAC,KAAK,QAAQ;AACxC,UAAM,EAAE,UAAU,SAAS,IAAI,IAAI;AACnC,QAAI,CAAC,YAAY,CAAC,UAAU;AAC1B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qCAAqC,CAAC;AAAA,IAC7E;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAY,EAAE,aAAa,QAAQ;AAE/D,QAAI,CAAC,MAAM;AACT,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAGA,UAAM,eAAe,KAAK,YAAY;AACtC,QAAI,iBAAiB,UAAU;AAC7B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IACjE;AAEA,QAAI,KAAK,EAAE,SAAS,mBAAmB,MAAM,gBAAgB,MAAM,EAAE,EAAE,CAAC;AAAA,EAC1E,CAAC;AAGD,MAAI,IAAI,2BAA2B,CAAC,KAAK,QAAQ;AAC/C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,aAAa,YAAY,IAAI,IAAI;AAEzC,QAAI,CAAC,aAAa;AAChB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,6BAA6B,CAAC;AAAA,IACrE;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,YAAY,GAAG,MAAM,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAC5D,QAAI,cAAc,IAAI;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,OAAO,GAAG,MAAM,SAAS;AAC/B,UAAM,kBAAkB,KAAK,YAAY;AAEzC,QAAI,oBAAoB,aAAa;AACnC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,IACtE;AAEA,OAAG,MAAM,SAAS,EAAE,WAAW;AAC/B,WAAO,EAAE;AAET,QAAI,KAAK,EAAE,SAAS,iCAAiC,MAAM,gBAAgB,GAAG,MAAM,SAAS,GAAG,EAAE,EAAE,CAAC;AAAA,EACvG,CAAC;AAKD,MAAI,IAAI,mBAAmB,CAAC,KAAK,QAAQ;AACvC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,UAAU;AAAA,EACxB,CAAC;AAED,MAAI,KAAK,mBAAmB,CAAC,KAAK,QAAQ;AACxC,UAAM,EAAE,SAAS,WAAW,MAAM,MAAM,SAAS,aAAa,UAAU,YAAY,UAAU,UAAU,cAAc,cAAc,YAAY,IAAI,IAAI;AACxJ,QAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,aAAa;AAC1D,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gCAAgC,CAAC;AAAA,IACxE;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,cAAwB;AAAA,MAC5B,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB;AAAA,MACA,WAAW,aAAa;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,MACxC,YAAY,aAAa,OAAO,UAAU,IAAI;AAAA,MAC9C,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,MACxC,QAAQ;AAAA,MACR,UAAU,YAAY;AAAA,MACtB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,cAAc,gBAAgB;AAAA,MAC9B,cAAc,gBAAgB;AAAA,MAC9B,aAAa,eAAe,kCAAkC,mBAAmB,OAAO,CAAC;AAAA,IAC3F;AAEA,OAAG,WAAW,KAAK,WAAW;AAC9B,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,kCAAkC,UAAU,YAAY,CAAC;AAAA,EAC3F,CAAC;AAED,MAAI,OAAO,uBAAuB,CAAC,KAAK,QAAQ;AAC9C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,gBAAgB,GAAG,WAAW;AACpC,OAAG,aAAa,GAAG,WAAW,OAAO,CAAC,MAAgB,EAAE,OAAO,EAAE;AAEjE,QAAI,GAAG,WAAW,WAAW,eAAe;AAC1C,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAGA,QAAI,GAAG,OAAO;AACZ,SAAG,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAW,EAAE,eAAe,EAAE;AAAA,IAC5D;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,6BAA6B,CAAC;AAAA,EACpD,CAAC;AAED,MAAI,IAAI,uBAAuB,CAAC,KAAK,QAAQ;AAC3C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,MAAM,MAAM,SAAS,aAAa,UAAU,YAAY,UAAU,UAAU,cAAc,cAAc,aAAa,OAAO,IAAI,IAAI;AAE5I,QAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,aAAa;AAC9C,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gCAAgC,CAAC;AAAA,IACxE;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,gBAAgB,GAAG,WAAW,UAAU,CAAC,MAAgB,EAAE,OAAO,EAAE;AAC1E,QAAI,kBAAkB,IAAI;AACxB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,kBAAkB;AAAA,MACtB,GAAG,GAAG,WAAW,aAAa;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,MACxC,YAAY,aAAa,OAAO,UAAU,IAAI;AAAA,MAC9C,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,MACxC,UAAU,YAAY,GAAG,WAAW,aAAa,EAAE;AAAA,MACnD,cAAc,gBAAgB,GAAG,WAAW,aAAa,EAAE;AAAA,MAC3D,cAAc,gBAAgB,GAAG,WAAW,aAAa,EAAE;AAAA,MAC3D,aAAa,eAAe,GAAG,WAAW,aAAa,EAAE;AAAA,MACzD,QAAQ,UAAU,GAAG,WAAW,aAAa,EAAE;AAAA,IACjD;AAEA,OAAG,WAAW,aAAa,IAAI;AAC/B,WAAO,EAAE;AAET,QAAI,KAAK,EAAE,SAAS,iCAAiC,UAAU,gBAAgB,CAAC;AAAA,EAClF,CAAC;AAKD,MAAI,IAAI,cAAc,CAAC,KAAK,QAAQ;AAClC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,SAAS,CAAC,CAAC;AAAA,EACzB,CAAC;AAED,MAAI,IAAI,qCAAqC,CAAC,KAAK,QAAQ;AACzD,UAAM,EAAE,WAAW,IAAI,IAAI;AAC3B,UAAM,KAAK,OAAO;AAClB,UAAM,SAAS,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,MAAW,EAAE,eAAe,UAAU;AAC7E,QAAI,KAAK,KAAK;AAAA,EAChB,CAAC;AAED,MAAI,KAAK,cAAc,CAAC,KAAK,QAAQ;AACnC,UAAM,EAAE,YAAY,YAAY,MAAM,UAAU,QAAQ,UAAU,YAAY,QAAQ,MAAM,SAAS,IAAI,IAAI;AAC7G,QAAI,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM;AACvC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAAA,IAC/E;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,UAAU;AAAA,MACd,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,OAAO,YAAY,CAAC;AAAA,MAC9B,QAAQ,UAAU;AAAA,MAClB,UAAU,YAAY;AAAA,MACtB,YAAY,cAAc,CAAC;AAAA,MAC3B,QAAQ,UAAU;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,UAAU,YAAY;AAAA,MACtB,aAAa,CAAC;AAAA,IAChB;AAEA,OAAG,QAAQ,GAAG,SAAS,CAAC;AACxB,OAAG,MAAM,KAAK,OAAO;AACrB,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,8CAA8C,MAAM,QAAQ,CAAC;AAAA,EAC/F,CAAC;AAED,MAAI,IAAI,yBAAyB,CAAC,KAAK,QAAQ;AAC7C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,IAAI;AACR,UAAM,KAAK,OAAO;AAClB,UAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC1D,QAAI,CAAC,MAAM;AACR,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IAClE;AAEA,UAAM,aAAa,KAAK;AACxB,UAAM,qBAAqB,KAAK;AAEhC,QAAI,WAAW,OAAW,MAAK,SAAS;AACxC,QAAI,gBAAgB,OAAW,MAAK,cAAc;AAClD,QAAI,cAAc,OAAW,MAAK,YAAY;AAC9C,QAAI,iBAAiB,OAAW,MAAK,eAAe;AACpD,QAAI,mBAAmB,OAAW,MAAK,iBAAiB;AACxD,QAAI,oBAAoB,OAAW,MAAK,kBAAkB;AAC1D,QAAI,kBAAkB,OAAW,MAAK,gBAAgB;AACtD,QAAI,kBAAkB,OAAW,MAAK,gBAAgB;AACtD,QAAI,sBAAsB,OAAW,MAAK,oBAAoB;AAC9D,QAAI,qBAAqB,OAAW,MAAK,mBAAmB;AAE5D,WAAO,EAAE;AAGT,UAAM,iBAAiB;AAAA,MACrB,IAAI,KAAK;AAAA,MACT,YAAY,KAAK;AAAA,MACjB,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,gBAAgB,KAAK;AAAA,MACrB,eAAe,KAAK,iBAAiB;AAAA,MACrC,mBAAmB,KAAK,qBAAqB;AAAA,MAC7C,kBAAkB,KAAK,oBAAoB;AAAA,MAC3C,WAAW,KAAK,aAAa;AAAA,MAC7B,cAAc,KAAK,gBAAgB;AAAA,IACrC;AAGA,QAAI,eAAe,eAAe,KAAK,WAAW,YAAY;AAC5D,sBAAgB,YAAY,cAAc;AAAA,IAC5C,WAAW,eAAe,cAAc,KAAK,WAAW,eAAe,KAAK,mBAAmB,SAAS;AACtG,sBAAgB,aAAa,cAAc;AAAA,IAC7C,WAAW,uBAAuB,cAAc,KAAK,mBAAmB,YAAY;AAClF,sBAAgB,oBAAoB,cAAc;AAAA,IACpD,WAAW,uBAAuB,cAAc,KAAK,mBAAmB,SAAS;AAC/E,sBAAgB,sBAAsB,cAAc;AAAA,IACtD,WAAW,eAAe,iBAAiB,KAAK,WAAW,eAAe;AACxE,sBAAgB,uBAAuB,cAAc;AAAA,IACvD,WAAW,eAAe,iBAAiB,KAAK,WAAW,aAAa;AACtE,sBAAgB,yBAAyB,cAAc;AAAA,IACzD;AAEA,QAAI,KAAK,EAAE,SAAS,qCAAqC,KAAK,CAAC;AAAA,EACjE,CAAC;AAED,MAAI,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,YAAY,MAAM,UAAU,QAAQ,UAAU,YAAY,QAAQ,MAAM,UAAU,YAAY,IAAI,IAAI;AAE9G,QAAI,CAAC,cAAc,CAAC,MAAM;AACxB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAAA,IAC/E;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG,SAAS,CAAC,GAAG,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AACpE,QAAI,cAAc,IAAI;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IACjE;AAEA,UAAM,cAAc;AAAA,MAClB,GAAG,GAAG,MAAM,SAAS;AAAA,MACrB;AAAA,MACA;AAAA,MACA,UAAU,OAAO,YAAY,CAAC;AAAA,MAC9B,QAAQ,UAAU,GAAG,MAAM,SAAS,EAAE;AAAA,MACtC,UAAU,aAAa,SAAY,WAAW,GAAG,MAAM,SAAS,EAAE;AAAA,MAClE,YAAY,cAAc,GAAG,MAAM,SAAS,EAAE;AAAA,MAC9C,QAAQ,WAAW,SAAY,SAAS,GAAG,MAAM,SAAS,EAAE;AAAA,MAC5D,MAAM,SAAS,SAAY,OAAO,GAAG,MAAM,SAAS,EAAE;AAAA,MACtD,UAAU,YAAY,GAAG,MAAM,SAAS,EAAE;AAAA,MAC1C,aAAa,eAAe,GAAG,MAAM,SAAS,EAAE;AAAA,IAClD;AAEA,OAAG,MAAM,SAAS,IAAI;AACtB,WAAO,EAAE;AAET,QAAI,KAAK,EAAE,SAAS,wCAAwC,MAAM,YAAY,CAAC;AAAA,EACjF,CAAC;AAED,MAAI,OAAO,kBAAkB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,iBAAiB,GAAG,SAAS,CAAC,GAAG;AAEvC,OAAG,SAAS,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,MAAW,EAAE,OAAO,EAAE;AAE1D,QAAI,GAAG,MAAM,WAAW,eAAe;AACrC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAAA,IACjE;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,oCAAoC,CAAC;AAAA,EAC3D,CAAC;AAKD,MAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AACzC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,YAAY;AAAA,EAC1B,CAAC;AAED,MAAI,KAAK,qBAAqB,CAAC,KAAK,QAAQ;AAC1C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,IAAI;AAER,QAAI,CAAC,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,YAAY;AACnD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gCAAgC,CAAC;AAAA,IACxE;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW,GAAG,WAAW,KAAK,CAAC,MAAgB,EAAE,OAAO,UAAU;AACxE,QAAI,CAAC,UAAU;AACb,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAGA,QAAI,aAAa,OAAO,UAAU;AAClC,QAAI,kBAAkB;AACtB,QAAI,YAAY;AACd,SAAG,SAAS,GAAG,UAAU,CAAC;AAC1B,YAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,MAAW,EAAE,KAAK,YAAY,MAAM,WAAW,KAAK,EAAE,YAAY,CAAC;AACjG,UAAI,OAAO;AACT,YAAI,MAAM,OAAO,MAAM,QAAQ;AAC7B,4BAAkB,OAAO,MAAM,QAAQ;AACvC,uBAAa,KAAK,IAAI,GAAG,aAAa,eAAe;AACrD,gBAAM,QAAQ;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,SAAS,OAAO;AAClB,eAAS,SAAS;AAAA,IACpB,WAAW,SAAS,QAAQ;AAC1B,eAAS,SAAS;AAAA,IACpB,WAAW,SAAS,QAAQ;AAC1B,eAAS,SAAS;AAAA,IACpB;AAGA,QAAI,QAAQ;AACV,SAAG,QAAQ,GAAG,SAAS,CAAC;AACxB,YAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,MAAM;AACtD,UAAI,MAAM;AACR,aAAK,SAAS;AACd,aAAK,cAAc,KAAK,eAAe,CAAC;AACxC,cAAM,QAAQ,cAAa,oBAAI,KAAK,GAAE,YAAY,EAAE,UAAU,GAAG,EAAE;AACnE,cAAM,MAAM,WAAW;AACvB,aAAK,YAAY,KAAK,GAAG,KAAK,QAAQ,GAAG,EAAE;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,KAAK,IAAI,CAAC;AAC9B,UAAM,iBAA8B;AAAA,MAClC,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,SAAS;AAAA,MACvB,cAAc,SAAS;AAAA,MACvB;AAAA,MACA,WAAW,cAAa,oBAAI,KAAK,GAAE,YAAY,EAAE,UAAU,GAAG,EAAE;AAAA,MAChE,SAAS,WAAW;AAAA,MACpB,YAAY;AAAA,MACZ,QAAQ;AAAA;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,QAAQ,UAAU;AAAA,MAClB,YAAY,cAAc;AAAA,IAC5B;AAEA,OAAG,aAAa,KAAK,cAAc;AAGnC,OAAG,WAAW,GAAG,YAAY,CAAC;AAC9B,UAAM,OAAO,iBAAiB;AAC9B,UAAM,aAAa,OAAO,KAAK,IAAI,YAAY,OAAO,cAAc,GAAM,CAAC,IAAI;AAE/E,UAAM,aAAa;AAAA,MACjB,IAAI,SAAS,KAAK,IAAI;AAAA,MACtB,eAAe;AAAA,MACf,cAAc,SAAS;AAAA,MACvB,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,eAAe,iBAAiB;AAAA,MAChC,MAAM,gBAAgB;AAAA;AAAA,MACtB,QAAQ,cAAc,aAAa,SAAS;AAAA,MAC5C,SAAS,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,OAAO,GAAI,EAAE,YAAY,EAAE,UAAU,GAAG,EAAE;AAAA,MAC7F,OAAO,qBAAqB,aAAa,IAAI,yBAAyB,cAAc,WAAW;AAAA,IACjG;AACA,OAAG,SAAS,KAAK,UAAU;AAG3B,OAAG,cAAc,GAAG,eAAe,CAAC;AACpC,UAAM,WAAW;AAAA,MACf,IAAI,QAAQ,KAAK,IAAI;AAAA,MACrB,WAAW;AAAA,MACX,cAAc,SAAS;AAAA,MACvB,YAAY,eAAe,SAAS,SAAS,WAAW,SAAS,SAAS,SAAS,SAAS,SAAS,cACjG,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG,IAAI,GAAG,IAC5C;AAAA,MACJ,QAAQ;AAAA;AAAA,MACR,aAAa,mBAAmB,aAAa;AAAA,MAC7C,cAAc;AAAA,IAChB;AACA,OAAG,YAAY,KAAK,QAAQ;AAG5B,OAAG,OAAO,GAAG,QAAQ,CAAC;AAGtB,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,SAAS,KAAK,IAAI,IAAI;AAAA,MAC1B,MAAM;AAAA,MACN,SAAS,QAAQ,SAAS,yBAAyB,IAAI,qBAAqB,SAAS,IAAI,gBAAgB,WAAW,eAAe,OAAO,CAAC,aAAa,iBAAiB,SAAS;AAAA,MAClL,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAGD,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,SAAS,KAAK,IAAI,IAAI;AAAA,MAC1B,MAAM;AAAA,MACN,SAAS,0CAA0C,IAAI,oBAAoB,SAAS,IAAI,kCAAkC,WAAW,eAAe,OAAO,CAAC;AAAA,MAC5J,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAGD,QAAI;AAEF;AAAA,QACE;AAAA,QACA;AAAA,QACA,WAAW,SAAS,QAAQ,cAAc,WAAW;AAAA,QACrD,uBAAuB,SAAS,IAAI,gBAAgB,WAAW,eAAe,OAAO,CAAC;AAAA,QACtF;AAAA,MACF;AAGA,UAAI,SAAS,SAAS;AACpB;AAAA,UACE;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA,GAAG,SAAS,mBAAmB,SAAS,IAAI,MAAM,SAAS,QAAQ,SAAS,MAAM,gBAAgB,WAAW,eAAe,OAAO,CAAC;AAAA,UACpI;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,cAAQ,MAAM,6CAA6C,CAAC;AAAA,IAC9D;AAEA,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MACnB,SAAS;AAAA,MACT,aAAa;AAAA,MACb;AAAA,MACA,SAAS;AAAA,MACT,YAAY;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AAKD,MAAI,IAAI,cAAc,CAAC,KAAK,QAAQ;AAClC,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa,GAAG;AACtB,UAAM,eAAe,GAAG,aAAa,OAAO,CAAC,MAAmB,EAAE,WAAW,MAAM;AAEnF,QAAI,UAAU;AACd,QAAI,cAAc;AAClB,QAAI,gBAAgB;AACpB,QAAI,YAAY;AAEhB,iBAAa,QAAQ,CAAC,MAAmB;AACvC,iBAAW,EAAE;AACb,UAAI,EAAE,SAAS,OAAQ;AACvB,UAAI,EAAE,SAAS,OAAQ;AACvB,UAAI,EAAE,SAAS,MAAO;AAAA,IACxB,CAAC;AAED,QAAI,KAAK;AAAA,MACP,iBAAiB,WAAW;AAAA,MAC5B,mBAAmB,GAAG,aAAa;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAKD,MAAI,KAAK,gCAAgC,OAAO,KAAK,QAAQ;AAC3D,UAAM,EAAE,MAAM,KAAK,IAAI,IAAI;AAC3B,QAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2CAA2C,CAAC;AAAA,IACnF;AAEA,UAAM,SAAS,QAAQ,IAAI;AAC3B,UAAM,+BAA+B,CAAC,UAAU,WAAW,uBAAuB,OAAO,KAAK,MAAM;AAEpG,QAAI,8BAA8B;AAEhC,UAAI,QAAQ;AACZ,UAAI,uBAAuB;AAC3B,UAAI,kBAAkB;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,YAAY;AAClC,UAAI,aAAa,UAAU,aAAa,WAAW,aAAa,WAAW,aAAa,SAAS;AAC/F,cAAM,OAAO,KAAK,SAAS,aAAa,UAAU,UAAU;AAC5D,YAAI,SAAS,WAAW,aAAa,SAAS;AAC5C,kBAAQ;AACR,iCAAuB;AACvB,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,WAAW,aAAa,SAAS;AAC/B,kBAAQ;AACR,iCAAuB;AACvB,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,OAAO;AACL,kBAAQ;AACR,iCAAuB;AACvB,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,WAAW,aAAa,YAAY;AAClC,cAAM,YAAY,KAAK,YAAY,KAAK,cAAc,KAAK,YAAY;AACvE,YAAI,YAAY,KAAS;AACvB,kBAAQ;AACR,iCAAuB;AACvB,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,OAAO;AACL,kBAAQ;AACR,iCAAuB;AACvB,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL,gBAAQ;AACR,+BAAuB;AACvB,0BAAkB;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,oBAAoB,qCAA8B,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,gDAKnB,KAAK;AAAA;AAAA;AAAA,uBAG9B,oBAAoB;AAAA;AAAA;AAAA;AAAA,EAIzC,gBAAgB,IAAI,OAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAKjE,aAAO,IAAI,KAAK,EAAE,UAAU,kBAAkB,CAAC;AAAA,IACjD;AAEA,QAAI;AACF,YAAM,SAAS;AAAA,eACN,IAAI;AAAA;AAAA,EAEjB,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,YAAM,WAAW,MAAM,YAAY,EAAE,OAAO,gBAAgB;AAAA,QAC1D,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,KAAK,EAAE,UAAU,SAAS,KAAK,CAAC;AAAA,IACtC,SAAS,OAAY;AACnB,cAAQ,MAAM,qBAAqB,KAAK;AACxC,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gDAAgD,MAAM,QAAQ,CAAC;AAAA,IAC/F;AAAA,EACF,CAAC;AAKD,MAAI,KAAK,uBAAuB,OAAO,KAAK,QAAQ;AAClD,UAAM,EAAE,MAAM,OAAO,IAAI,IAAI;AAC7B,QAAI,CAAC,QAAQ,CAAC,QAAQ;AACpB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,iDAAiD,CAAC;AAAA,IACzF;AAEA,UAAM,SAAS,QAAQ,IAAI;AAC3B,UAAM,+BAA+B,CAAC,UAAU,WAAW,uBAAuB,OAAO,KAAK,MAAM;AAEpG,QAAI,8BAA8B;AAEhC,UAAI,WAAW;AACf,UAAI,SAAS,oBAAoB;AAC/B,cAAM,EAAE,cAAc,MAAM,UAAU,WAAW,UAAU,YAAY,CAAC,EAAE,IAAI;AAC9E,cAAM,kBACJ,iBAAiB,UAAU,OAC3B,iBAAiB,cAAc,OAC/B,iBAAiB,UAAU,OAC3B,iBAAiB,QAAQ,OAAU;AAErC,YAAI,aAAa;AACjB,YAAI,UAAU,YAAY,EAAE,SAAS,SAAS,KAAK,UAAU,YAAY,EAAE,SAAS,UAAU,KAAK,UAAU,YAAY,EAAE,SAAS,QAAQ,EAAG,cAAa;AAAA,iBACnJ,UAAU,YAAY,EAAE,SAAS,MAAM,KAAK,UAAU,YAAY,EAAE,SAAS,MAAM,EAAG,cAAa;AAAA,iBACnG,UAAU,YAAY,EAAE,SAAS,SAAS,EAAG,cAAa;AAEnE,cAAM,sBAAsB,OAAO,QAAQ,EAAE,IAAI,kBAAkB,aAAc,OAAO,YAAY,CAAC,IAAI,MAAa,OAAO,aAAa,CAAC,IAAI,MAAa,UAAU,SAAS;AAE/K,YAAI,iBAAiB;AACrB,YAAI,qBAAqB;AACzB,YAAI,iBAAiB,WAAW,iBAAiB,SAAS;AACxD,gBAAM,gBAAgB,KAAK,MAAM,sBAAsB,GAAI;AAC3D,2BAAiB,MAAM,cAAc,eAAe,OAAO,CAAC;AAC5D,+BAAqB,0DAA0D,gBAAgB,KAAK,eAAe,OAAO,CAAC,mBAAmB,gBAAgB,MAAM,eAAe,OAAO,CAAC;AAAA,QAC7L,WAAW,iBAAiB,OAAO;AACjC,gBAAM,gBAAgB,KAAK,MAAM,sBAAsB,GAAK;AAC5D,2BAAiB,MAAM,cAAc,eAAe,OAAO,CAAC;AAC5D,+BAAqB,qCAAqC,cAAc,eAAe,OAAO,CAAC;AAAA,QACjG,OAAO;AACL,2BAAiB,MAAM,oBAAoB,eAAe,OAAO,CAAC;AAClE,+BAAqB,6CAA6C,sBAAsB,MAAM,eAAe,OAAO,CAAC,qEAAqE,sBAAsB,KAAK,eAAe,OAAO,CAAC;AAAA,QAC9O;AAEA,mBAAW;AAAA;AAAA;AAAA;AAAA;AAAA,mCAKgB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,yDAKQ,YAAY,WAAW,YAAY,aAAa,kBAAkB,QAAQ,EAAE;AAAA;AAAA;AAAA,IAGjI,kBAAkB;AAAA;AAAA;AAAA,MAGhB,WAES,SAAS,sBAAsB;AACtC,cAAM,EAAE,YAAY,aAAa,IAAI;AACrC,mBAAW;AAAA;AAAA;AAAA;AAAA,+CAIqB,gBAAgB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBrE,WAES,SAAS,eAAe;AAC/B,cAAM,EAAE,UAAU,WAAW,cAAc,OAAO,YAAY,IAAI;AAClE,cAAM,YAAY,OAAO,SAAS,IAAI,KAAK,OAAO,KAAK;AACvD,cAAM,cAAc,OAAO,QAAQ;AACnC,cAAM,qBAAqB,IAAM,OAAO,gBAAgB,CAAC,IAAI,MAAO,OAAO,KAAK;AAChF,cAAM,wBAAwB,cAAc;AAC5C,cAAM,eAAe,wBAAyB,OAAO,eAAe,GAAM,IAAI,KAAK,OAAO,KAAK;AAC/F,cAAM,8BAA8B,cAAc,KAAK,IAAI,MAAM,OAAO,KAAK,CAAC;AAC9E,cAAM,YAAY,8BAA8B;AAEhD,cAAM,WAAW,YAAY,CAAC,YAAY,YAAY;AACtD,cAAM,aAAa,KAAK,IAAI,YAAY,SAAS;AAEjD,mBAAW;AAAA;AAAA;AAAA;AAAA,mDAIyB,KAAK;AAAA,oDACG,QAAQ;AAAA,yCACnB,KAAK,MAAM,UAAU,EAAE,eAAe,OAAO,CAAC;AAAA,sCACjD,KAAK,MAAM,SAAS,EAAE,eAAe,OAAO,CAAC;AAAA,6DACtB,KAAK,MAAM,2BAA2B,EAAE,eAAe,OAAO,CAAC;AAAA;AAAA;AAAA,8FAG9B,KAAK,MAAM,SAAS,EAAE,eAAe,OAAO,CAAC;AAAA,6IACE,KAAK,MAAM,2BAA2B,EAAE,eAAe,OAAO,CAAC,YAAY,KAAK;AAAA;AAAA;AAAA,yCAGpL,KAAK,oCAAoC,QAAQ;AAAA;AAAA,MAEpF,WAES,SAAS,0BAA0B;AAC1C,cAAM,EAAE,SAAS,WAAW,KAAK,YAAY,aAAa,IAAI;AAC9D,cAAM,WAAY,OAAO,OAAO,CAAC,IAAI,OAAS,OAAO,gBAAgB,GAAI,IAAI,QAAY,eAAe,SAAS,MAAM,eAAe,WAAW,OAAO;AACxJ,cAAM,YAAY,KAAK,IAAI,KAAK,KAAK,MAAM,WAAW,GAAG,CAAC;AAE1D,YAAI,YAAY;AAChB,YAAI,YAAY;AAChB,YAAI,kBAAkB;AAEtB,YAAI,YAAY,IAAI;AAClB,sBAAY;AACZ,sBAAY;AACZ,4BAAkB;AAAA,QACpB,WAAW,YAAY,IAAI;AACzB,sBAAY;AACZ,sBAAY;AACZ,4BAAkB;AAAA,QACpB;AAEA,cAAM,gBAAgB,KAAK,MAAM,YAAY,GAAK;AAElD,mBAAW;AAAA;AAAA;AAAA;AAAA,qCAIW,aAAa,eAAe;AAAA,+CACX,SAAS,KAAK,SAAS,KAAK,SAAS;AAAA,gDACpC,eAAe;AAAA,sCACzB,IAAI,KAAK,KAAK,IAAI,IAAI,kBAAkB,KAAK,OAAO,GAAI,EAAE,mBAAmB,SAAS,EAAE,MAAM,WAAW,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC;AAAA,yDACtH,cAAc,eAAe,OAAO,CAAC;AAAA;AAAA;AAAA,yEAGrB,gBAAgB,GAAI,uCAAuC,cAAc,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,8EAK5E,gBAAgB,MAAM,eAAe,OAAO,CAAC;AAAA,MACrH;AAEA,aAAO,IAAI,KAAK,EAAE,SAAS,CAAC;AAAA,IAC9B;AAEA,QAAI;AACF,UAAI,SAAS;AACb,UAAI,SAAS,oBAAoB;AAC/B,iBAAS;AAAA;AAAA,EAEf,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAS3B,WAAW,SAAS,sBAAsB;AACxC,iBAAS;AAAA;AAAA,EAEf,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ3B,WAAW,SAAS,eAAe;AACjC,iBAAS;AAAA;AAAA,EAEf,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ3B,WAAW,SAAS,0BAA0B;AAC5C,iBAAS;AAAA;AAAA,EAEf,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAS3B;AAEA,YAAM,WAAW,MAAM,YAAY,EAAE,OAAO,gBAAgB;AAAA,QAC1D,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,KAAK,EAAE,UAAU,SAAS,KAAK,CAAC;AAAA,IACtC,SAAS,OAAY;AACnB,cAAQ,MAAM,uCAAuC,KAAK;AAC1D,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gDAAgD,MAAM,QAAQ,CAAC;AAAA,IAC/F;AAAA,EACF,CAAC;AAQD,MAAI,IAAI,8BAA8B,CAAC,KAAK,QAAQ;AAClD,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,OAAO,IAAI,IAAI;AACvB,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC3D,QAAI,CAAC,UAAU;AACb,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAAA,IACnE;AACA,UAAM,YAAY,SAAS;AAC3B,aAAS,SAAS;AAGlB,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,oBAAoB,SAAS,IAAI,iBAAiB,SAAS,YAAY,MAAM;AAAA,MACtF,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,wCAAwC,SAAS,CAAC;AAAA,EACxE,CAAC;AAGD,MAAI,IAAI,yBAAyB,CAAC,KAAK,QAAQ;AAC7C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,YAAY,WAAW,SAAS,YAAY,KAAK,IAAI,IAAI;AACjE,UAAM,KAAK,OAAO;AAClB,UAAM,cAAc,GAAG,aAAa,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAChE,QAAI,CAAC,aAAa;AAChB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AAEA,UAAM,gBAAgB,YAAY;AAClC,UAAM,kBAAkB,YAAY;AAEpC,QAAI,cAAc,eAAe,eAAe;AAC9C,YAAM,cAAc,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,UAAU;AACtE,UAAI,CAAC,aAAa;AAChB,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,gCAAgC,CAAC;AAAA,MACxE;AAGA,YAAM,cAAc,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,aAAa;AACzE,UAAI,aAAa;AACf,oBAAY,SAAS;AAAA,MACvB;AAGA,UAAI,YAAY,SAAS,SAAS,SAAS,OAAO;AAChD,oBAAY,SAAS;AAAA,MACvB,WAAW,YAAY,SAAS,UAAU,SAAS,QAAQ;AACzD,oBAAY,SAAS;AAAA,MACvB,OAAO;AACL,oBAAY,SAAS;AAAA,MACvB;AAEA,kBAAY,aAAa;AACzB,kBAAY,eAAe,YAAY;AACvC,kBAAY,eAAe,YAAY;AAAA,IACzC;AAEA,QAAI,UAAW,aAAY,YAAY;AACvC,QAAI,QAAS,aAAY,UAAU;AACnC,QAAI,WAAY,aAAY,aAAa,OAAO,UAAU;AAC1D,QAAI,KAAM,aAAY,OAAO;AAG7B,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,8BAA8B,EAAE,sBAAsB,eAAe,SAAS,YAAY,YAAY;AAAA,MAC/G,MAAM,YAAY,aAAa;AAAA,MAC/B,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,4CAA4C,YAAY,CAAC;AAAA,EAC/E,CAAC;AAGD,MAAI,IAAI,eAAe,CAAC,KAAK,QAAQ;AACnC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,UAAU,CAAC,CAAC;AAAA,EAC1B,CAAC;AAED,MAAI,KAAK,eAAe,CAAC,KAAK,QAAQ;AACpC,UAAM,EAAE,MAAM,UAAU,MAAM,QAAQ,YAAY,IAAI,IAAI;AAC1D,QAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM;AAC/B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sCAAsC,CAAC;AAAA,IAC9E;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW;AAAA,MACf,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB,MAAM,KAAK,YAAY;AAAA,MACvB,UAAU,OAAO,QAAQ;AAAA,MACzB;AAAA;AAAA,MACA,QAAQ,SAAS,OAAO,MAAM,IAAI;AAAA,MAClC,MAAM;AAAA,MACN,aAAa,eAAe;AAAA,IAC9B;AACA,OAAG,SAAS,GAAG,UAAU,CAAC;AAC1B,OAAG,OAAO,KAAK,QAAQ;AACvB,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,QAAQ;AAAA,EAC/B,CAAC;AAGD,MAAI,IAAI,uBAAuB,CAAC,KAAK,QAAQ;AAC3C,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,kBAAkB,CAAC,CAAC;AAAA,EAClC,CAAC;AAED,MAAI,KAAK,uBAAuB,CAAC,KAAK,QAAQ;AAC5C,UAAM,EAAE,OAAO,UAAU,MAAM,QAAQ,IAAI,IAAI;AAC/C,QAAI,CAAC,SAAS,CAAC,UAAU;AACvB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mCAAmC,CAAC;AAAA,IAC3E;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,QAAQ;AAAA,MACZ,IAAI,QAAQ,KAAK,IAAI;AAAA,MACrB;AAAA,MACA;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,SAAS,WAAW;AAAA,MACpB,QAAQ;AAAA,IACV;AACA,OAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAC1C,OAAG,eAAe,KAAK,KAAK;AAC5B,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,KAAK;AAAA,EAC5B,CAAC;AAGD,MAAI,IAAI,kBAAkB,CAAC,KAAK,QAAQ;AACtC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,aAAa,CAAC,CAAC;AAAA,EAC7B,CAAC;AAED,MAAI,KAAK,kBAAkB,CAAC,KAAK,QAAQ;AACvC,UAAM,EAAE,MAAM,QAAQ,SAAS,UAAU,IAAI,IAAI;AACjD,QAAI,CAAC,QAAQ,CAAC,SAAS;AACrB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qCAAqC,CAAC;AAAA,IAC7E;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,cAAc;AAAA,MAClB,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA,QAAQ,SAAS,OAAO,MAAM,IAAI;AAAA,MAClC;AAAA,MACA,WAAW,YAAY,OAAO,SAAS,IAAI;AAAA,IAC7C;AACA,OAAG,YAAY,GAAG,aAAa,CAAC;AAChC,OAAG,UAAU,KAAK,WAAW;AAC7B,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,WAAW;AAAA,EAClC,CAAC;AAED,MAAI,IAAI,mBAAmB,CAAC,KAAK,QAAQ;AACvC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,cAAc,CAAC,CAAC;AAAA,EAC9B,CAAC;AAED,MAAI,KAAK,mBAAmB,CAAC,KAAK,QAAQ;AACxC,UAAM,EAAE,MAAM,MAAM,QAAQ,SAAS,IAAI,IAAI;AAC7C,QAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,sCAAsC,CAAC;AAAA,IAC9E;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,cAAc;AAAA,MAClB,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA,QAAQ,UAAU;AAAA,MAClB,UAAU,YAAY;AAAA,IACxB;AACA,OAAG,aAAa,GAAG,cAAc,CAAC;AAClC,OAAG,WAAW,KAAK,WAAW;AAC9B,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,WAAW;AAAA,EAClC,CAAC;AAED,MAAI,IAAI,uBAAuB,CAAC,KAAK,QAAQ;AAC3C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,QAAQ,UAAU,KAAK,IAAI,IAAI;AACvC,UAAM,KAAK,OAAO;AAClB,UAAM,MAAM,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACtD,QAAI,CAAC,KAAK;AACR,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAA,IACpE;AACA,QAAI,OAAQ,KAAI,SAAS;AACzB,QAAI,SAAU,KAAI,WAAW;AAC7B,QAAI,KAAM,KAAI,OAAO;AACrB,WAAO,EAAE;AACT,QAAI,KAAK,GAAG;AAAA,EACd,CAAC;AAGD,MAAI,IAAI,iBAAiB,CAAC,KAAK,QAAQ;AACrC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,YAAY,CAAC,CAAC;AAAA,EAC5B,CAAC;AAED,MAAI,KAAK,iBAAiB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,eAAe,cAAc,aAAa,YAAY,eAAe,MAAM,SAAS,MAAM,IAAI,IAAI;AAC1G,QAAI,CAAC,gBAAgB,CAAC,aAAa;AACjC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qDAAqD,CAAC;AAAA,IAC7F;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,aAAa;AAAA,MACjB,IAAI,SAAS,KAAK,IAAI;AAAA,MACtB,eAAe,iBAAiB;AAAA,MAChC;AAAA,MACA,aAAa,OAAO,WAAW;AAAA,MAC/B,YAAY,OAAO,cAAc,CAAC;AAAA,MAClC,eAAe,iBAAiB;AAAA,MAChC,MAAM,QAAQ;AAAA;AAAA,MACd,QAAQ,OAAO,UAAU,KAAK,OAAO,WAAW,IAAI,SAAS;AAAA,MAC7D,SAAS,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,KAAK,OAAO,GAAI,EAAE,YAAY,EAAE,UAAU,GAAG,EAAE;AAAA,MAC7F,OAAO,SAAS;AAAA,IAClB;AACA,OAAG,WAAW,GAAG,YAAY,CAAC;AAC9B,OAAG,SAAS,KAAK,UAAU;AAC3B,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,UAAU;AAAA,EACjC,CAAC;AAED,MAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,YAAY,eAAe,QAAQ,MAAM,IAAI,IAAI;AACzD,UAAM,KAAK,OAAO;AAClB,UAAM,UAAU,GAAG,SAAS,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACxD,QAAI,CAAC,SAAS;AACZ,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAAA,IAClE;AACA,QAAI,eAAe,QAAW;AAC5B,cAAQ,aAAa,OAAO,UAAU;AACtC,cAAQ,SAAS,QAAQ,cAAc,QAAQ,cAAc,SAAS;AAAA,IACxE;AACA,QAAI,cAAe,SAAQ,gBAAgB;AAC3C,QAAI,OAAQ,SAAQ,SAAS;AAC7B,QAAI,MAAO,SAAQ,QAAQ;AAG3B,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,mCAAmC,EAAE,KAAK,QAAQ,YAAY,8BAA8B,QAAQ,WAAW,eAAe,OAAO,CAAC;AAAA,MAC/I,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,OAAO;AAAA,EAClB,CAAC;AAGD,MAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AACzC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,eAAe,CAAC,CAAC;AAAA,EAC/B,CAAC;AAED,MAAI,KAAK,qBAAqB,CAAC,KAAK,QAAQ;AAC1C,UAAM,EAAE,WAAW,cAAc,YAAY,QAAQ,YAAY,IAAI,IAAI;AACzE,QAAI,CAAC,aAAa,CAAC,cAAc;AAC/B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,0CAA0C,CAAC;AAAA,IAClF;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW;AAAA,MACf,IAAI,QAAQ,KAAK,IAAI;AAAA,MACrB;AAAA,MACA;AAAA,MACA,YAAY,cAAc;AAAA,MAC1B,QAAQ,UAAU;AAAA;AAAA,MAClB,aAAa,eAAe;AAAA,MAC5B,cAAc;AAAA,IAChB;AACA,OAAG,cAAc,GAAG,eAAe,CAAC;AACpC,OAAG,YAAY,KAAK,QAAQ;AAC5B,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,QAAQ;AAAA,EAC/B,CAAC;AAED,MAAI,IAAI,yBAAyB,CAAC,KAAK,QAAQ;AAC7C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,QAAQ,WAAW,IAAI,IAAI;AACnC,UAAM,KAAK,OAAO;AAClB,UAAM,QAAQ,GAAG,YAAY,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACzD,QAAI,CAAC,OAAO;AACV,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,IACtE;AACA,UAAM,YAAY,MAAM;AACxB,QAAI,QAAQ;AACV,YAAM,SAAS;AACf,UAAI,WAAW,cAAc;AAC3B,cAAM,eAAc,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MAChF,WAAW,WAAW,eAAe;AACnC,cAAM,gBAAe,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MACjF;AAAA,IACF;AACA,QAAI,WAAY,OAAM,aAAa;AAGnC,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,sBAAsB,MAAM,SAAS,kBAAkB,MAAM,YAAY,kBAAkB,SAAS,cAAc,MAAM,MAAM;AAAA,MACvI,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,KAAK;AAAA,EAChB,CAAC;AAGD,MAAI,IAAI,mBAAmB,CAAC,KAAK,QAAQ;AACvC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,cAAc,CAAC,CAAC;AAAA,EAC9B,CAAC;AAED,MAAI,KAAK,mBAAmB,CAAC,KAAK,QAAQ;AACxC,UAAM,EAAE,WAAW,cAAc,OAAO,aAAa,UAAU,SAAS,IAAI,IAAI;AAChF,QAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,SAAS,CAAC,aAAa;AACzD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2CAA2C,CAAC;AAAA,IACnF;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,eAAe;AAAA,MACnB,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,YAAY;AAAA,MACtB,UAAU,YAAY;AAAA,MACtB,QAAQ;AAAA;AAAA,MACR,YAAY;AAAA,MACZ,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE;AACA,OAAG,aAAa,GAAG,cAAc,CAAC;AAClC,OAAG,WAAW,KAAK,YAAY;AAG/B,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,wBAAwB,SAAS,oBAAoB,KAAK,qBAAqB,YAAY;AAAA,MACpG,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,YAAY;AAAA,EACnC,CAAC;AAED,MAAI,IAAI,uBAAuB,CAAC,KAAK,QAAQ;AAC3C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,QAAQ,WAAW,IAAI,IAAI;AACnC,UAAM,KAAK,OAAO;AAClB,UAAM,OAAO,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACvD,QAAI,CAAC,MAAM;AACT,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAAA,IACnE;AACA,QAAI,OAAQ,MAAK,SAAS;AAC1B,QAAI,eAAe,OAAW,MAAK,aAAa;AAGhD,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,oBAAoB,EAAE,wBAAwB,MAAM,cAAc,cAAc,sBAAsB;AAAA,MAC/G,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AAGD,iBAAe,gBAAgB,OAAe,SAAc;AAC1D,QAAI;AACF,YAAM,KAAK,OAAO;AAClB,YAAM,kBAAkB,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,MAAW,EAAE,WAAW,YAAY,EAAE,OAAO,SAAS,KAAK,CAAC;AAC/G,UAAI,eAAe,WAAW,EAAG;AAEjC,iBAAW,MAAM,gBAAgB;AAE/B,cAAM,GAAG,KAAK;AAAA,UACZ,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,mBAAmB;AAAA,YACnB,oBAAoB,GAAG,UAAU;AAAA,UACnC;AAAA,UACA,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC;AAAA,UACF,CAAC;AAAA,QACH,CAAC,EAAE,KAAK,OAAO,aAAa;AAC1B,gBAAM,QAAQ,OAAO;AACrB,uBAAa,OAAO,UAAU,8BAA8B,KAAK,wBAAwB,GAAG,IAAI,mBAAmB,SAAS,MAAM,EAAE;AACpI,iBAAO,KAAK;AAAA,QACd,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,gBAAM,QAAQ,OAAO;AACrB,uBAAa,OAAO,UAAU,0CAA0C,KAAK,SAAS,GAAG,IAAI,MAAM,IAAI,OAAO,EAAE;AAChH,iBAAO,KAAK;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAU;AACjB,cAAQ,MAAM,2BAA2B,IAAI,OAAO;AAAA,IACtD;AAAA,EACF;AAGA,MAAI,IAAI,aAAa,CAAC,KAAK,QAAQ;AACjC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,QAAQ,CAAC,CAAC;AAAA,EACxB,CAAC;AAED,MAAI,KAAK,aAAa,CAAC,KAAK,QAAQ;AAClC,UAAM,EAAE,MAAM,SAAS,KAAK,IAAI,IAAI;AACpC,QAAI,CAAC,QAAS,QAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,wBAAwB,CAAC;AAC5E,UAAM,KAAK,OAAO;AAGlB,iBAAa,IAAI,QAAQ,OAAO,SAAS,QAAQ,UAAU,GAAG;AAC9D,WAAO,EAAE;AAET,UAAM,YAAY,GAAG,KAAK,GAAG,KAAK,SAAS,CAAC;AAC5C,QAAI,OAAO,GAAG,EAAE,KAAK,SAAS;AAAA,EAChC,CAAC;AAED,MAAI,OAAO,aAAa,CAAC,KAAK,QAAQ;AACpC,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW;AAAA,MACf,IAAI,eAAe,KAAK,IAAI;AAAA,MAC5B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MACrE,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ;AACA,OAAG,OAAO,CAAC,QAAQ;AACnB,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,4BAA4B,CAAC;AAAA,EACnD,CAAC;AAGD,MAAI,IAAI,iBAAiB,CAAC,KAAK,QAAQ;AACrC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,WAAW,CAAC,CAAC;AAAA,EAC3B,CAAC;AAED,MAAI,KAAK,iBAAiB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,MAAM,YAAY,IAAI,IAAI;AAClC,QAAI,CAAC,KAAM,QAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qCAAqC,CAAC;AACtF,UAAM,KAAK,OAAO;AAClB,OAAG,UAAU,GAAG,WAAW,CAAC;AAE5B,UAAM,YAAY,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AAC5D,UAAM,MAAM,WAAW,gBAAgB,cAAc,OAAO,IAAI,IAAI,SAAS;AAC7E,UAAM,SAAS;AAAA,MACb,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA,aAAa,eAAe;AAAA,MAC5B,QAAQ;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE;AACA,OAAG,QAAQ,KAAK,MAAM;AACtB,iBAAa,IAAI,UAAU,+CAA+C,IAAI,MAAM,WAAW,KAAK,iBAAiB,GAAG;AACxH,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,MAAM;AAAA,EAC7B,CAAC;AAED,MAAI,OAAO,qBAAqB,CAAC,KAAK,QAAQ;AAC5C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,OAAG,UAAU,GAAG,WAAW,CAAC;AAC5B,UAAM,QAAQ,GAAG,QAAQ,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAC1D,QAAI,UAAU,IAAI;AAChB,YAAM,UAAU,GAAG,QAAQ,OAAO,OAAO,CAAC,EAAE,CAAC;AAC7C,mBAAa,IAAI,UAAU,yCAAyC,QAAQ,IAAI,KAAK,iBAAiB,GAAG;AACzG,aAAO,EAAE;AACT,aAAO,IAAI,KAAK,EAAE,SAAS,8BAA8B,CAAC;AAAA,IAC5D;AACA,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,6BAA6B,CAAC;AAAA,EAC9D,CAAC;AAGD,MAAI,IAAI,iBAAiB,CAAC,KAAK,QAAQ;AACrC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,YAAY,CAAC,CAAC;AAAA,EAC5B,CAAC;AAED,MAAI,KAAK,iBAAiB,CAAC,KAAK,QAAQ;AACtC,UAAM,EAAE,MAAM,KAAK,OAAO,IAAI,IAAI;AAClC,QAAI,CAAC,QAAQ,CAAC,IAAK,QAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,mCAAmC,CAAC;AAC5F,UAAM,KAAK,OAAO;AAClB,OAAG,WAAW,GAAG,YAAY,CAAC;AAE9B,UAAM,SAAS,WAAW,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AAClH,UAAM,QAAQ;AAAA,MACZ,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,UAAU,OAAO,SAAS,SAAS,CAAC,YAAY,WAAW;AAAA,MACnE,QAAQ;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE;AACA,OAAG,SAAS,KAAK,KAAK;AACtB,iBAAa,IAAI,UAAU,gDAAgD,IAAI,oBAAoB,GAAG,IAAI,iBAAiB,GAAG;AAC9H,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,KAAK;AAAA,EAC5B,CAAC;AAED,MAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AACzC,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,MAAM,KAAK,QAAQ,OAAO,IAAI,IAAI;AAC1C,UAAM,KAAK,OAAO;AAClB,OAAG,WAAW,GAAG,YAAY,CAAC;AAC9B,UAAM,KAAK,GAAG,SAAS,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AACnD,QAAI,CAAC,GAAI,QAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAE1E,QAAI,SAAS,OAAW,IAAG,OAAO;AAClC,QAAI,QAAQ,OAAW,IAAG,MAAM;AAChC,QAAI,WAAW,OAAW,IAAG,SAAS;AACtC,QAAI,WAAW,OAAW,IAAG,SAAS;AAEtC,iBAAa,IAAI,UAAU,8BAA8B,GAAG,IAAI,kCAAkC,iBAAiB,GAAG;AACtH,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,gCAAgC,SAAS,GAAG,CAAC;AAAA,EACnE,CAAC;AAED,MAAI,OAAO,qBAAqB,CAAC,KAAK,QAAQ;AAC5C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,OAAG,WAAW,GAAG,YAAY,CAAC;AAC9B,UAAM,QAAQ,GAAG,SAAS,UAAU,CAAC,MAAW,EAAE,OAAO,EAAE;AAC3D,QAAI,UAAU,IAAI;AAChB,YAAM,UAAU,GAAG,SAAS,OAAO,OAAO,CAAC,EAAE,CAAC;AAC9C,mBAAa,IAAI,UAAU,uCAAuC,QAAQ,IAAI,KAAK,iBAAiB,GAAG;AACvG,aAAO,EAAE;AACT,aAAO,IAAI,KAAK,EAAE,SAAS,4BAA4B,CAAC;AAAA,IAC1D;AACA,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAAA,EAC5D,CAAC;AAED,MAAI,KAAK,0BAA0B,OAAO,KAAK,QAAQ;AACrD,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,MAAM,GAAG,YAAY,CAAC,GAAG,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC3D,QAAI,CAAC,GAAI,QAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAE1E,UAAM,UAAU;AAAA,MACd,OAAO;AAAA,MACP,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,MAClD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,GAAI;AAE3D,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK;AAAA,QACnC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,mBAAmB;AAAA,UACnB,oBAAoB,GAAG,UAAU;AAAA,QACnC;AAAA,QACA,MAAM,KAAK,UAAU,OAAO;AAAA,QAC5B,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,mBAAa,SAAS;AAEtB,mBAAa,IAAI,UAAU,mDAAmD,GAAG,IAAI,qBAAqB,SAAS,MAAM,IAAI,iBAAiB,GAAG;AACjJ,aAAO,EAAE;AACT,UAAI,KAAK,EAAE,SAAS,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,IACrD,SAAS,KAAU;AACjB,mBAAa,IAAI,UAAU,gDAAgD,GAAG,IAAI,MAAM,IAAI,OAAO,IAAI,iBAAiB,GAAG;AAC3H,aAAO,EAAE;AACT,UAAI,KAAK,EAAE,SAAS,OAAO,OAAO,IAAI,QAAQ,CAAC;AAAA,IACjD;AAAA,EACF,CAAC;AAGD,MAAI,IAAI,qBAAqB,CAAC,KAAK,QAAQ;AACzC,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,GAAG,gBAAgB,CAAC,CAAC;AAAA,EAChC,CAAC;AAED,MAAI,KAAK,qBAAqB,CAAC,KAAK,QAAQ;AAC1C,UAAM,EAAE,YAAY,cAAc,WAAW,OAAO,MAAM,KAAK,IAAI,IAAI;AACvE,QAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM;AAClD,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,kEAAkE,CAAC;AAAA,IAC1G;AACA,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW;AAAA,MACf,IAAI,OAAO,KAAK,IAAI;AAAA,MACpB,YAAY,cAAc;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MACA,QAAQ;AAAA;AAAA,MACR,MAAM,OAAO,OAAO,IAAI,IAAI;AAAA,MAC5B,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE;AACA,OAAG,eAAe,GAAG,gBAAgB,CAAC;AACtC,OAAG,aAAa,KAAK,QAAQ;AAG7B,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,sBAAsB,IAAI,YAAY,SAAS,SAAS,YAAY;AAAA,MAC7E,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAGD,QAAI;AACF,YAAM,aAAa,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,cAAc,EAAE,SAAS,YAAY;AAChG,YAAM,eAAe,aAAa,WAAW,UAAU;AACvD;AAAA,QACE;AAAA,QACA;AAAA,QACA,4BAA4B,IAAI;AAAA,QAChC,oDAAoD,SAAS,kBAAkB,YAAY;AAAA,QAC3F;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,cAAQ,MAAM,4CAA4C,CAAC;AAAA,IAC7D;AAEA,WAAO,EAAE;AACT,QAAI,OAAO,GAAG,EAAE,KAAK,QAAQ;AAAA,EAC/B,CAAC;AAED,MAAI,IAAI,yBAAyB,CAAC,KAAK,QAAQ;AAC7C,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,EAAE,QAAQ,KAAK,IAAI,IAAI;AAC7B,UAAM,KAAK,OAAO;AAClB,UAAM,QAAQ,GAAG,aAAa,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC1D,QAAI,CAAC,OAAO;AACV,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,+BAA+B,CAAC;AAAA,IACvE;AACA,QAAI,OAAQ,OAAM,SAAS;AAC3B,QAAI,SAAS,OAAW,OAAM,OAAO,OAAO,IAAI;AAGhD,OAAG,KAAK,KAAK;AAAA,MACX,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,MACrB,MAAM;AAAA,MACN,SAAS,wBAAwB,EAAE,oBAAoB,MAAM,gBAAgB,OAAO,MAAM,IAAI,EAAE,eAAe,OAAO,CAAC;AAAA,MACvH,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,IACvE,CAAC;AAGD,QAAI;AACF,YAAM,aAAa,GAAG,WAAW,KAAK,CAAC,MAAW,EAAE,OAAO,MAAM,cAAc,EAAE,SAAS,MAAM,YAAY;AAC5G,YAAM,eAAe,aAAa,WAAW,UAAU;AACvD;AAAA,QACE;AAAA,QACA;AAAA,QACA,wBAAwB,OAAO,YAAY,CAAC;AAAA,QAC5C,yCAAyC,MAAM,SAAS,kBAAkB,MAAM,YAAY,qBAAqB,MAAM,yBAAyB,OAAO,MAAM,IAAI,EAAE,eAAe,OAAO,CAAC;AAAA,QAC1L;AAAA,MACC;AAAA,IACL,SAAS,GAAG;AACV,cAAQ,MAAM,mDAAmD,CAAC;AAAA,IACpE;AAEA,WAAO,EAAE;AACT,QAAI,KAAK,KAAK;AAAA,EAChB,CAAC;AAOD,MAAI,IAAI,sBAAsB,CAAC,KAAK,QAAQ;AAC1C,UAAM,EAAE,OAAO,IAAI,IAAI;AACvB,UAAM,KAAK,OAAO;AAClB,OAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAExC,QAAI,CAAC,QAAQ;AACX,aAAO,IAAI,KAAK,GAAG,aAAa;AAAA,IAClC;AAEA,UAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAW,EAAE,OAAO,OAAO,MAAM,CAAC;AAC9D,QAAI,QAAQ,KAAK,WAAW,KAAK;AAC/B,aAAO,IAAI,KAAK,GAAG,aAAa;AAAA,IAClC;AAEA,UAAM,WAAW,GAAG,cAAc,OAAO,CAAC,MAAW,OAAO,EAAE,MAAM,MAAM,OAAO,MAAM,CAAC;AACxF,QAAI,KAAK,QAAQ;AAAA,EACnB,CAAC;AAGD,MAAI,KAAK,+BAA+B,CAAC,KAAK,QAAQ;AACpD,UAAM,EAAE,GAAG,IAAI,IAAI;AACnB,UAAM,KAAK,OAAO;AAClB,OAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAExC,UAAM,QAAQ,GAAG,cAAc,KAAK,CAAC,MAAW,EAAE,OAAO,EAAE;AAC3D,QAAI,OAAO;AACT,YAAM,OAAO;AACb,aAAO,EAAE;AACT,aAAO,IAAI,KAAK,EAAE,SAAS,MAAM,cAAc,MAAM,CAAC;AAAA,IACxD;AACA,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,EAC/D,CAAC;AAGD,MAAI,KAAK,+BAA+B,CAAC,KAAK,QAAQ;AACpD,UAAM,EAAE,OAAO,IAAI,IAAI;AACvB,QAAI,CAAC,QAAQ;AACX,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAAA,IAC7D;AACA,UAAM,KAAK,OAAO;AAClB,OAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAExC,OAAG,cAAc,QAAQ,CAAC,MAAW;AACnC,UAAI,OAAO,EAAE,MAAM,MAAM,OAAO,MAAM,GAAG;AACvC,UAAE,OAAO;AAAA,MACX;AAAA,IACF,CAAC;AAED,WAAO,EAAE;AACT,QAAI,KAAK,EAAE,SAAS,MAAM,SAAS,0CAA0C,CAAC;AAAA,EAChF,CAAC;AAGD,MAAI,KAAK,+BAA+B,CAAC,KAAK,QAAQ;AACpD,UAAM,EAAE,QAAQ,OAAO,SAAS,KAAK,IAAI,IAAI;AAC7C,QAAI,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS;AACjC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yCAAyC,CAAC;AAAA,IACjF;AAEA,UAAM,KAAK,OAAO;AAClB,UAAM,WAAW,8BAA8B,IAAI,QAAQ,OAAO,SAAS,QAAQ,QAAQ;AAC3F,WAAO,EAAE;AAET,QAAI,OAAO,GAAG,EAAE,KAAK;AAAA,MACnB,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AAGD,MAAI,IAAI,sBAAsB,CAAC,KAAK,QAAQ;AAC1C,UAAM,YAAY,YAAAF,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe,SAAS;AACnE,QAAI,CAAC,UAAAC,QAAG,WAAW,SAAS,GAAG;AAC7B,gBAAAA,QAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC7C;AAEA,QAAI;AACF,YAAM,QAAQ,UAAAA,QAAG,YAAY,SAAS;AACtC,YAAM,UAAU,MACb,OAAO,OAAK,EAAE,SAAS,MAAM,CAAC,EAC9B,IAAI,OAAK;AACR,cAAM,WAAW,YAAAD,QAAK,KAAK,WAAW,CAAC;AACvC,cAAM,OAAO,UAAAC,QAAG,SAAS,QAAQ;AACjC,eAAO;AAAA,UACL,UAAU;AAAA,UACV,MAAM,KAAK;AAAA,UACX,WAAW,KAAK;AAAA,UAChB,MAAM,8BAA8B,CAAC;AAAA,QACvC;AAAA,MACF,CAAC;AACH,UAAI,KAAK,OAAO;AAAA,IAClB,SAAS,OAAY;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,qCAAqC,MAAM,QAAQ,CAAC;AAAA,IACpF;AAAA,EACF,CAAC;AAED,MAAI,KAAK,8BAA8B,CAAC,KAAK,QAAQ;AACnD,QAAI;AA0CF,UAAS,aAAT,SAAoB,KAAqB;AACvC,YAAI,QAAQ;AACZ,cAAM,QAAQ,UAAAA,QAAG,YAAY,GAAG;AAChC,cAAM,QAAQ,OAAK;AACjB,gBAAM,IAAI,YAAAD,QAAK,KAAK,KAAK,CAAC;AAC1B,cAAI,UAAAC,QAAG,SAAS,CAAC,EAAE,YAAY,GAAG;AAChC,qBAAS,WAAW,CAAC;AAAA,UACvB,OAAO;AACL;AAAA,UACF;AAAA,QACF,CAAC;AACD,eAAO;AAAA,MACT;AArDA,YAAM,YAAY,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,aAAa;AACxD,YAAM,UAAU,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe,SAAS;AAEjE,UAAI,CAAC,UAAAC,QAAG,WAAW,SAAS,GAAG;AAC7B,eAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAAA,MAC/E;AAEA,UAAI,CAAC,UAAAA,QAAG,WAAW,OAAO,GAAG;AAC3B,kBAAAA,QAAG,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,MAC3C;AAEA,YAAM,cAAc,wBAAwB,KAAK,IAAI,CAAC;AACtD,YAAM,cAAc,YAAAD,QAAK,KAAK,SAAS,WAAW;AAElD,YAAM,MAAM,IAAI,eAAAG,QAAO;AAIvB,YAAM,QAAQ,UAAAF,QAAG,YAAY,SAAS;AACtC,UAAI,YAAY;AAEhB,YAAM,QAAQ,UAAQ;AACpB,YAAI,SAAS,UAAW;AAExB,cAAM,WAAW,YAAAD,QAAK,KAAK,WAAW,IAAI;AAC1C,cAAM,OAAO,UAAAC,QAAG,SAAS,QAAQ;AAEjC,YAAI,KAAK,YAAY,GAAG;AACtB,cAAI,eAAe,UAAU,IAAI;AACjC,uBAAa,WAAW,QAAQ;AAAA,QAClC,OAAO;AACL,cAAI,aAAa,QAAQ;AACzB;AAAA,QACF;AAAA,MACF,CAAC;AAED,UAAI,SAAS,WAAW;AAExB,YAAM,YAAY,UAAAA,QAAG,SAAS,WAAW;AAiBzC,UAAI,KAAK;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,QACV,MAAM,UAAU;AAAA,QAChB;AAAA,QACA,WAAW,UAAU;AAAA,MACvB,CAAC;AAAA,IACH,SAAS,GAAQ;AACf,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,wCAAwC,EAAE,QAAQ,CAAC;AAAA,IACnF;AAAA,EACF,CAAC;AAGD,MAAI,IAAI,wCAAwC,CAAC,KAAK,QAAQ;AAC5D,UAAM,EAAE,SAAS,IAAI,IAAI;AACzB,UAAM,WAAW,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe,WAAW,QAAQ;AAC5E,QAAI,UAAAC,QAAG,WAAW,QAAQ,GAAG;AAC3B,UAAI,SAAS,QAAQ;AAAA,IACvB,OAAO;AACL,UAAI,OAAO,GAAG,EAAE,KAAK,uBAAuB;AAAA,IAC9C;AAAA,EACF,CAAC;AAGD,MAAI,KAAK,qBAAqB,CAAC,KAAK,QAAQ;AAC1C,UAAM,EAAE,UAAU,UAAU,OAAO,IAAI,IAAI;AAC3C,QAAI,CAAC,UAAU;AACb,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAAA,IAC/D;AAEA,UAAM,WAAW,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe,WAAW,QAAQ;AAC5E,QAAI,CAAC,UAAAC,QAAG,WAAW,QAAQ,GAAG;AAC5B,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,yCAAyC,CAAC;AAAA,IACjF;AAGA,UAAM,OAAO,UAAAA,QAAG,SAAS,QAAQ,EAAE;AAEnC,QAAI,KAAK;AAAA,MACP,SAAS;AAAA,MACT,SAAS,uBAAuB,QAAQ,OAAO,QAAQ;AAAA,MACvD,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,UAAU;AAAA,QACV,aAAa,cAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,CAAC;AAAA,QACtE,YAAY,oBAAI,KAAK;AAAA,QACrB,aAAa,IAAI,QAAQ,OAAO,OAAO,QAAQ,CAAC,CAAC;AAAA,QACjD,WAAW,8CAA8C,QAAQ,IAAI,KAAK,IAAI,CAAC;AAAA,MACjF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAKD,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAM,OAAO,UAAM,YAAAG,cAAiB;AAAA,MAClC,QAAQ;AAAA,QACN,gBAAgB;AAAA,QAChB,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,QAAI,IAAI,KAAK,WAAW;AAAA,EAC1B,OAAO;AACL,UAAM,WAAW,YAAAJ,QAAK,KAAK,QAAQ,IAAI,GAAG,MAAM;AAChD,QAAI,IAAI,eAAAE,QAAQ,OAAO,QAAQ,CAAC;AAChC,QAAI,IAAI,KAAK,CAAC,KAAK,QAAQ;AACzB,UAAI,SAAS,YAAAF,QAAK,KAAK,UAAU,YAAY,CAAC;AAAA,IAChD,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,MAAM,WAAW,MAAM;AAChC,YAAQ,IAAI,yCAAyC,IAAI,EAAE;AAAA,EAC7D,CAAC;AACH;AAEA,YAAY;",
  "names": ["path", "fs", "express", "AdmZip", "createViteServer"]
}
