diff --git a/.env.example b/.env.example index 8caa795..d3e130a 100644 --- a/.env.example +++ b/.env.example @@ -12,7 +12,18 @@ JWT_ACCESS_TTL=15m JWT_REFRESH_TTL=30d DELIVERY_MAX_DEVICES=2 -# ---- Safaricom Daraja ---- +# ---- Platform operator ---- +# Comma-separated emails with cross-tenant access to /platform. Create these +# accounts with `npm run seed`; public signup refuses these addresses. +PLATFORM_ADMIN_EMAILS= + +# ---- M-Pesa (optional, off for the pilot) ---- +# M-Pesa STK Push is out of scope for the pilot. While this is false every +# /api/mpesa route returns 404 and the Daraja variables below are ignored. +# If you turn it on in production, DARAJA_CALLBACK_IP_ALLOWLIST is required. +FEATURE_MPESA=false + +# ---- Safaricom Daraja (only read when FEATURE_MPESA=true) ---- DARAJA_ENV=sandbox DARAJA_CONSUMER_KEY=xxxxxxxxxxxxxxxx DARAJA_CONSUMER_SECRET=xxxxxxxxxxxxxxxx diff --git a/package-lock.json b/package-lock.json index 62bd3ca..8f8c6bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,10 +27,12 @@ "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.19", "dotenv": "^16.4.5", + "mongodb-memory-server": "^10.1.4", "postcss": "^8.4.39", "tailwindcss": "^3.4.4", "tsx": "^4.19.0", - "typescript": "^5.5.3" + "typescript": "^5.5.3", + "vitest": "^2.1.9" } }, "node_modules/@alloc/quick-lru": { @@ -536,6 +538,26 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, "node_modules/@next/env": { "version": "14.2.35", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz", @@ -724,6 +746,395 @@ "node": ">= 8" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.64.5.tgz", + "integrity": "sha512-MrfgRQSpD5hkkRg6XI16B6EDLb+6+xp8xje6bpdSwkYw+qxrBKbUVrRAQu9h82UT+QumSIVQ8HXsXjPd2dlhqw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.64.5.tgz", + "integrity": "sha512-+uu2p/R9Tzn8GpoQyX1pAo5dmKT1DhXevfaCzqzmPFhnLjHLWw7uWkaVGlxmhwYoRiYYhsGfRcD5cTBpL7rgSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.64.5.tgz", + "integrity": "sha512-17dys+YEmzwzzFVHQAVDONg5FALXY9kd99HFEpfk4gJVHYxoh5bGea3D4t1fXXnwkTcOe25wPyd6nWS0I8IdLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.64.5.tgz", + "integrity": "sha512-wg0zQEKkEvFZf1UaaX1UELOoPs//OSKUG7D+yITuqOsAvza7LvHTv5Wu4nmMfzNG7EYI2jp2PJC7Id6OETmsYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.64.5.tgz", + "integrity": "sha512-CoJmWcpEMuwin+TZ/ev/H9uDyF/uxUKQSWXdmIPn/UBx/uGV9+4ebMp0FwnlhWR9PE1AdzYsKf3bZevhif38+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.64.5.tgz", + "integrity": "sha512-PxZnLAaTUAL5xG0W2BXLeYPKrK2b3LIASV2/e/Kf7PZvSLI1iAQIm9B9aJD+YyFIT7hc6qaMV3+OOO35R28LfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.64.5.tgz", + "integrity": "sha512-uPo3IvnONjhbFXwWgroBeFwOicuhT7ZwQrnzkzmOtBJzeQbkUJUE1SJDfDI31ijQ5+ZUIA6sPrdUMxTSnxUWAg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.64.5.tgz", + "integrity": "sha512-ywI8Jyuc4LyHYTjC0mw4yA1ulvZBkHusdpWnoiEBsmBuHvSnt90btTBGCZ+s/2y+YNNfVAEKy33nPo5UI9zTmg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.64.5.tgz", + "integrity": "sha512-tmuXJoQ/3ovSr637aykZMdQteU/CB2APAz2CrvsbibuoHZi1BS1Db13cVViBdEARGwXCLn1DSJ8wsjoThLJPGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.64.5.tgz", + "integrity": "sha512-5FMjSYNcUOHx7oW8Qu9KB6jGPpvF/8sG7+BDHwU/Ihh1/6FMJ9ySmsFG4tJ1qbNRuP8OLzCBDso4sF0mQaLuFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.64.5.tgz", + "integrity": "sha512-K8ZJ+neLDbUkIrL8dqF/5LtuVCrKwo27kREgOlxjBEjlOXwHvDnHLU8Z/UKv/B49qi7e8hsSDOyoJwhwqhvX4w==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.64.5.tgz", + "integrity": "sha512-NlVxsq7PFPv0DBKGuNWRDKixQYQCjM53zl04mxEcKMBmJbCBIUm1JdPfIWDRHyOOFzzYPmLQzfeEwh4716ayQg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.64.5.tgz", + "integrity": "sha512-ARhRHJYs5eCFet5azfrHD97vOkD8OzNW2RSMlvo5CcBqXaTOLfp0OHDtUQh7/K5AL5fUYoFp2fgC9KDg4vVYMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.64.5.tgz", + "integrity": "sha512-atSgreM5C7jpxd9aEXN+6vJ5wTd05iYw+S3FiQpw7VsoEl8B90llbq35ARON+GOHj5QlVQEq2vOKWCHTob/BSQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.64.5.tgz", + "integrity": "sha512-vmlmwBFGnjVWxSRoVabNkyYuscSmg52Pd0fM8jEbNT3Jmka4A6HcB84x4uAmuumznWfBVaxKOqU6jbEgomWKCA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.64.5.tgz", + "integrity": "sha512-hhJrP6S9WkbsbcHgUkvCBS5Cn8IdsG8XjlLZyxjnv9+NdoYfbbZE4TWJYr8apdaj1M5t5Y1id2StnEslxpNFyA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.64.5.tgz", + "integrity": "sha512-NNVCyN9pGrwFmQa4bf+Cnf5aVH3g6ZpnlOg1Cs/H9swIHT9bRixijfzUqyEIWm1WtiAuR1LJ+rJH6zpBm8kgQA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.64.5.tgz", + "integrity": "sha512-dR9nd6OKnvSS60Ifz/L7Mj5zzYyoqyRn2NwTuaOONKaa3xsVGXyp8YusMbvFyEOR94DxnwgcbgsFqkHd29ZSzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.64.5.tgz", + "integrity": "sha512-1tzsMjaqhsh3bAO6SJiJqh8hIr9sSPRd+i2vPPxJHod8/XYnf9TEnK0z/u3r1z1AkI347X0KbRSg9dWcxeGahw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.64.5.tgz", + "integrity": "sha512-01mWMQblKoXXsmk28KXtpbA96w7g/aOWUoV3AC16fdHdqkykGalqyyM+5u8M7uP5/MEMiiPv69Hv7iv/hEH/dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.64.5.tgz", + "integrity": "sha512-trdnMPb/DNm4V/CgsaoGgr90HfQQ071wfK0KoIs4YpLvjBgVQGXhGabg2Z6nK4EcYNilrb9ZZPcsP6+zpJIdxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.64.5.tgz", + "integrity": "sha512-x2LxZlfdfsw99T6/qb9EqE/Qi84JWzibjyOJyhJsgFJy6CafaTiqIXCCnslCGrV5XWNh7fwrS3FbRENcuKnooA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.64.5.tgz", + "integrity": "sha512-/Qd/9aDQIo0+jmItgBmPIs8195YVbDxRRApn47GyufgbutCDOh7eP5vSKKlI4QNFeaI+wKQAkSMsPnF3EuMpaA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.64.5.tgz", + "integrity": "sha512-ngUJ/XvOWrqbd2IMsfXfh2xXFLTP3sY7sCKvxbGvYdBZ1KmXFd3ewDZ9n3/GNzAUgzRuhLT/UvJRivbNoAQRBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.64.5.tgz", + "integrity": "sha512-IhV6ew/DuzUWwHaYmlh7MrPCV3lKFUq/amTEwysi4r/mwNPAEfAMh5dYWeTSPTeMy2pFHGMEWYtPkHzfX3tG5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -747,6 +1158,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/jsonwebtoken": { "version": "9.0.10", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", @@ -818,6 +1236,119 @@ "@types/webidl-conversions": "*" } }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -858,6 +1389,26 @@ "dev": true, "license": "MIT" }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -913,6 +1464,106 @@ "proxy-from-env": "^2.1.0" } }, + "node_modules/b4a": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz", + "integrity": "sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bare-events": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", + "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.8.4.tgz", + "integrity": "sha512-MPC2eyrpbk3A873sK4y6rk+Iv4o2enxTjHZ8zH3HO0mjrpm5XjnguY2XmfidIsDV6vnjpbMBKUAJpV0ISD2SsQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.28.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-path": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.2.tgz", + "integrity": "sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bare-stream": { + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.4.tgz", + "integrity": "sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.8.1", + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.5.4.tgz", + "integrity": "sha512-Gxa7UVWBr0/edU1b+TJhn/AZvMQUj9OGspvYsaTYQrAbZA4BOTZGL3LiZxvD+CeMlDH4juwD84+eTAp/bLYW5g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/baseline-browser-mapping": { "version": "2.11.26", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.26.tgz", @@ -1018,6 +1669,16 @@ "node": ">=10.16.0" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1031,6 +1692,19 @@ "node": ">= 0.4" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1061,6 +1735,33 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1127,6 +1828,13 @@ "node": ">= 6" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1174,6 +1882,16 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1258,6 +1976,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -1337,6 +2062,43 @@ "node": ">=6" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -1390,6 +2152,38 @@ "node": ">=8" } }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", @@ -1740,6 +2534,19 @@ "dev": true, "license": "MIT" }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -1794,6 +2601,49 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1910,6 +2760,69 @@ "whatwg-url": "^14.1.0 || ^13.0.0" } }, + "node_modules/mongodb-memory-server": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-10.1.4.tgz", + "integrity": "sha512-+oKQ/kc3CX+816oPFRtaF0CN4vNcGKNjpOQe4bHo/21A3pMD+lC7Xz1EX5HP7siCX4iCpVchDMmCOFXVQSGkUg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "mongodb-memory-server-core": "10.1.4", + "tslib": "^2.7.0" + }, + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/mongodb-memory-server-core": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-10.1.4.tgz", + "integrity": "sha512-o8fgY7ZalEd8pGps43fFPr/hkQu1L8i6HFEGbsTfA2zDOW0TopgpswaBCqDr0qD7ptibyPfB5DmC+UlIxbThzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-mutex": "^0.5.0", + "camelcase": "^6.3.0", + "debug": "^4.3.7", + "find-cache-dir": "^3.3.2", + "follow-redirects": "^1.15.9", + "https-proxy-agent": "^7.0.5", + "mongodb": "^6.9.0", + "new-find-package-json": "^2.0.0", + "semver": "^7.6.3", + "tar-stream": "^3.1.7", + "tslib": "^2.7.0", + "yauzl": "^3.1.3" + }, + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/mongoose": { "version": "8.24.4", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.24.4.tgz", @@ -1989,6 +2902,19 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/new-find-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-2.0.0.tgz", + "integrity": "sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">=12.22.0" + } + }, "node_modules/next": { "version": "14.2.35", "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz", @@ -2107,6 +3033,55 @@ "node": ">= 6" } }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2114,6 +3089,30 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2143,6 +3142,19 @@ "node": ">= 6" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/postcss": { "version": "8.5.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", @@ -2423,6 +3435,52 @@ "node": ">=0.10.0" } }, + "node_modules/rollup": { + "version": "4.64.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.64.5.tgz", + "integrity": "sha512-EAP5ZHcz2ijbgCWwPkpI7zh6bfsri2Ez5FtCy2dCp1k62duXzfG7DLGGh7RU2QQXWwavT+u4qpvDF/TWOiiGTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.64.5", + "@rollup/rollup-android-arm64": "4.64.5", + "@rollup/rollup-darwin-arm64": "4.64.5", + "@rollup/rollup-darwin-x64": "4.64.5", + "@rollup/rollup-freebsd-arm64": "4.64.5", + "@rollup/rollup-freebsd-x64": "4.64.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.64.5", + "@rollup/rollup-linux-arm-musleabihf": "4.64.5", + "@rollup/rollup-linux-arm64-gnu": "4.64.5", + "@rollup/rollup-linux-arm64-musl": "4.64.5", + "@rollup/rollup-linux-loong64-gnu": "4.64.5", + "@rollup/rollup-linux-loong64-musl": "4.64.5", + "@rollup/rollup-linux-ppc64-gnu": "4.64.5", + "@rollup/rollup-linux-ppc64-musl": "4.64.5", + "@rollup/rollup-linux-riscv64-gnu": "4.64.5", + "@rollup/rollup-linux-riscv64-musl": "4.64.5", + "@rollup/rollup-linux-s390x-gnu": "4.64.5", + "@rollup/rollup-linux-x64-gnu": "4.64.5", + "@rollup/rollup-linux-x64-musl": "4.64.5", + "@rollup/rollup-openbsd-x64": "4.64.5", + "@rollup/rollup-openharmony-arm64": "4.64.5", + "@rollup/rollup-win32-arm64-msvc": "4.64.5", + "@rollup/rollup-win32-ia32-msvc": "4.64.5", + "@rollup/rollup-win32-x64-gnu": "4.64.5", + "@rollup/rollup-win32-x64-msvc": "4.64.5", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2494,6 +3552,13 @@ "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", "license": "MIT" }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", @@ -2512,6 +3577,20 @@ "memory-pager": "^1.0.2" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -2520,6 +3599,18 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", + "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/styled-jsx": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", @@ -2617,6 +3708,39 @@ "node": ">=14.0.0" } }, + "node_modules/tar-stream": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.2.tgz", + "integrity": "sha512-+8NeqHRjQWH9nYlwo2gamAMImZCVzI4UoEgDpWorBt9OEfppiZn+uSkskzQKPWIZyji/C8fpWO7u69G0DX0tbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.9.0", + "bare-fs": "^4.8.2", + "fast-fifo": "^1.3.2", + "streamx": "^2.28.1" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2640,6 +3764,20 @@ "node": ">=0.8" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -2688,6 +3826,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2804,6 +3972,585 @@ "dev": true, "license": "MIT" }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -2826,6 +4573,36 @@ "node": ">=18" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/package.json b/package.json index bac9b8b..bf58592 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "start": "next start", "lint": "next lint", "seed": "tsx scripts/seed.ts", - "migrate:multitenant": "tsx scripts/migrate-multitenant.ts" + "migrate:multitenant": "tsx scripts/migrate-multitenant.ts", + "test": "vitest run", + "typecheck": "tsc --noEmit" }, "dependencies": { "axios": "^1.7.7", @@ -29,10 +31,12 @@ "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.19", + "dotenv": "^16.4.5", + "mongodb-memory-server": "^10.1.4", "postcss": "^8.4.39", "tailwindcss": "^3.4.4", "tsx": "^4.19.0", "typescript": "^5.5.3", - "dotenv": "^16.4.5" + "vitest": "^2.1.9" } } diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index a9ff1cb..bc57232 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -9,6 +9,7 @@ import { signAccessToken, generateRefreshToken, hashRefreshToken, refreshTtlMs } import { ACCESS_COOKIE, REFRESH_COOKIE, accessCookieOptions, refreshCookieOptions } from "@/lib/server/auth"; import { isPlatformAdminEmail } from "@/lib/server/platform"; import { getEnv } from "@/lib/server/env"; +import { tenantAccessError } from "@/lib/server/subscription"; export const runtime = "nodejs"; @@ -70,6 +71,11 @@ export async function POST(req: NextRequest) { user.lockedUntil = null; await user.save(); + const tenantError = await tenantAccessError(user.businessId); + if (tenantError) { + return NextResponse.json({ error: tenantError }, { status: 403 }); + } + if (user.role === "DELIVERY") { const binding = await enforceDeviceBinding(user._id.toString(), deviceId); if (!binding.allowed) { diff --git a/src/app/api/auth/me/route.ts b/src/app/api/auth/me/route.ts index 09ce640..26ccf4d 100644 --- a/src/app/api/auth/me/route.ts +++ b/src/app/api/auth/me/route.ts @@ -5,6 +5,7 @@ import { Branch } from "@/lib/server/models/Branch"; import { Business } from "@/lib/server/models/Business"; import { getAuth } from "@/lib/server/auth"; import { isPlatformAdminEmail } from "@/lib/server/platform"; +import { isMpesaEnabled } from "@/lib/server/env"; import { TIERS, type TierId, type SubscriptionStatus } from "@/lib/tiers"; export const runtime = "nodejs"; @@ -49,5 +50,6 @@ export async function GET(req: NextRequest) { maxBranches: tierDef.maxBranches, maxUsers: tierDef.maxUsers, }, + features: { mpesa: isMpesaEnabled() }, }); } \ No newline at end of file diff --git a/src/app/api/auth/refresh/route.ts b/src/app/api/auth/refresh/route.ts index 5e78149..56c2d15 100644 --- a/src/app/api/auth/refresh/route.ts +++ b/src/app/api/auth/refresh/route.ts @@ -3,6 +3,7 @@ import { connectDb } from "@/lib/server/db"; import { User } from "@/lib/server/models/User"; import { UserSession } from "@/lib/server/models/UserSession"; import { signAccessToken, generateRefreshToken, hashRefreshToken, refreshTtlMs } from "@/lib/server/jwt"; +import { tenantAccessError } from "@/lib/server/subscription"; import { ACCESS_COOKIE, REFRESH_COOKIE, accessCookieOptions, refreshCookieOptions } from "@/lib/server/auth"; export const runtime = "nodejs"; @@ -29,6 +30,11 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: "Account no longer active" }, { status: 401 }); } + const tenantError = await tenantAccessError(user.businessId); + if (tenantError) { + return NextResponse.json({ error: tenantError }, { status: 403 }); + } + const newRefreshToken = generateRefreshToken(); session.refreshTokenHash = hashRefreshToken(newRefreshToken); session.lastUsedAt = new Date(); diff --git a/src/app/api/auth/signup/route.ts b/src/app/api/auth/signup/route.ts index df9f2b2..bbdc1e6 100644 --- a/src/app/api/auth/signup/route.ts +++ b/src/app/api/auth/signup/route.ts @@ -11,6 +11,7 @@ import { signAccessToken, generateRefreshToken, hashRefreshToken, refreshTtlMs } import { ACCESS_COOKIE, REFRESH_COOKIE, accessCookieOptions, refreshCookieOptions } from "@/lib/server/auth"; import { normalizeKenyanPhone } from "@/lib/server/phone"; import { DEFAULT_TIER, TRIAL_DAYS } from "@/lib/tiers"; +import { isPlatformAdminEmail } from "@/lib/server/platform"; export const runtime = "nodejs"; @@ -52,6 +53,14 @@ export async function POST(req: NextRequest) { const lowerEmail = email.toLowerCase(); + // Platform-operator rights are granted by email (PLATFORM_ADMIN_EMAILS) + // and signup does not verify email ownership, so an operator address + // must never be claimable through public signup. Operator accounts are + // created with `npm run seed` instead. + if (isPlatformAdminEmail(lowerEmail)) { + return NextResponse.json({ error: "This email cannot be used to sign up." }, { status: 403 }); + } + const emailTaken = await User.findOne({ email: lowerEmail }).lean(); if (emailTaken) { return NextResponse.json({ error: "An account with this email already exists." }, { status: 409 }); diff --git a/src/app/api/branches/[id]/route.ts b/src/app/api/branches/[id]/route.ts new file mode 100644 index 0000000..1730732 --- /dev/null +++ b/src/app/api/branches/[id]/route.ts @@ -0,0 +1,37 @@ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { isValidObjectId } from "mongoose"; +import { connectDb } from "@/lib/server/db"; +import { Branch } from "@/lib/server/models/Branch"; +import { authorize } from "@/lib/server/auth"; + +export const runtime = "nodejs"; + +const updateSchema = z + .object({ + branchName: z.string().trim().min(1).max(120).optional(), + locationCity: z.string().trim().min(1).max(120).optional(), + }) + .refine((v) => Object.keys(v).length > 0, { message: "No fields to update" }); + +// PATCH /api/branches/:id — owner renames a branch or changes its city. +export async function PATCH(req: NextRequest, { params }: { params: { id: string } }) { + await connectDb(); + const gate = authorize(req, ["SUPER_ADMIN"]); + if (!gate.ok) return gate.response; + const auth = gate.auth; + + if (!isValidObjectId(params.id)) return NextResponse.json({ error: "Branch not found" }, { status: 404 }); + + const json = await req.json().catch(() => null); + const parsed = updateSchema.safeParse(json); + if (!parsed.success) { + return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); + } + + const branch = await Branch.findOneAndUpdate({ _id: params.id, businessId: auth.businessId }, parsed.data, { + new: true, + }).lean(); + if (!branch) return NextResponse.json({ error: "Branch not found" }, { status: 404 }); + return NextResponse.json({ branch }); +} diff --git a/src/app/api/branches/route.ts b/src/app/api/branches/route.ts index 6d2fc07..a439696 100644 --- a/src/app/api/branches/route.ts +++ b/src/app/api/branches/route.ts @@ -4,7 +4,7 @@ import bcrypt from "bcryptjs"; import { connectDb } from "@/lib/server/db"; import { Branch } from "@/lib/server/models/Branch"; import { User } from "@/lib/server/models/User"; -import { getAuth, requireRole } from "@/lib/server/auth"; +import { authorize, getAuth } from "@/lib/server/auth"; import { normalizeKenyanPhone } from "@/lib/server/phone"; import { branchLimitError, userLimitError, loadTier } from "@/lib/server/subscription"; @@ -40,10 +40,9 @@ const createSchema = z.object({ export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, ["SUPER_ADMIN"]); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = createSchema.safeParse(json); @@ -51,7 +50,7 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); } const { branchName, locationCity, manager } = parsed.data; - const businessId = auth!.businessId; + const businessId = auth.businessId; const tier = await loadTier(businessId); const branchErr = await branchLimitError(businessId, tier); diff --git a/src/app/api/dashboard/reconciliation/route.ts b/src/app/api/dashboard/reconciliation/route.ts index a676824..fb9e487 100644 --- a/src/app/api/dashboard/reconciliation/route.ts +++ b/src/app/api/dashboard/reconciliation/route.ts @@ -3,27 +3,48 @@ import mongoose from "mongoose"; import { connectDb } from "@/lib/server/db"; import { Transaction } from "@/lib/server/models/Transaction"; import { DailyInventory } from "@/lib/server/models/DailyInventory"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { authorize, badRequest, branchParam } from "@/lib/server/auth"; +import { dayRangeNairobi, isBusinessDate, todayNairobi } from "@/lib/server/businessDay"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req); + if (!gate.ok) return gate.response; + const auth = gate.auth; - const branchId = resolveBranchScope(auth, req.nextUrl.searchParams.get("branchId")); - const date = req.nextUrl.searchParams.get("date") || new Date().toISOString().slice(0, 10); + const scope = branchParam(auth, req.nextUrl.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const branchId = scope.branchId; + const date = req.nextUrl.searchParams.get("date") || todayNairobi(); + if (!isBusinessDate(date)) return badRequest("date must be YYYY-MM-DD"); const invMatch: Record = { date, businessId: new mongoose.Types.ObjectId(auth.businessId) }; if (branchId) invMatch.branchId = new mongoose.Types.ObjectId(branchId); const inventoryRows = await DailyInventory.aggregate([ { $match: invMatch }, - { $lookup: { from: "products", localField: "productId", foreignField: "_id", as: "product" } }, + // Lookups are tenant-scoped too, so a row can never surface another + // tenant's product or branch even if one were referenced by mistake. + { + $lookup: { + from: "products", + let: { pid: "$productId", biz: "$businessId" }, + pipeline: [{ $match: { $expr: { $and: [{ $eq: ["$_id", "$$pid"] }, { $eq: ["$businessId", "$$biz"] }] } } }], + as: "product", + }, + }, { $unwind: "$product" }, - { $lookup: { from: "branches", localField: "branchId", foreignField: "_id", as: "branch" } }, + { + $lookup: { + from: "branches", + let: { bid: "$branchId", biz: "$businessId" }, + pipeline: [{ $match: { $expr: { $and: [{ $eq: ["$_id", "$$bid"] }, { $eq: ["$businessId", "$$biz"] }] } } }], + as: "branch", + }, + }, { $unwind: "$branch" }, { $project: { @@ -39,9 +60,7 @@ export async function GET(req: NextRequest) { }, ]); - const dayStart = new Date(date + "T00:00:00.000Z"); - const dayEnd = new Date(dayStart); - dayEnd.setUTCDate(dayEnd.getUTCDate() + 1); + const { start: dayStart, end: dayEnd } = dayRangeNairobi(date); const soldMatch: Record = { businessId: new mongoose.Types.ObjectId(auth.businessId), diff --git a/src/app/api/dashboard/summary/route.ts b/src/app/api/dashboard/summary/route.ts index 4e6fb46..8052fc4 100644 --- a/src/app/api/dashboard/summary/route.ts +++ b/src/app/api/dashboard/summary/route.ts @@ -2,26 +2,22 @@ import { NextRequest, NextResponse } from "next/server"; import mongoose from "mongoose"; import { connectDb } from "@/lib/server/db"; import { Transaction } from "@/lib/server/models/Transaction"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { authorize, branchParam } from "@/lib/server/auth"; +import { dayRangeNairobi, todayNairobi } from "@/lib/server/businessDay"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; -function todayRange() { - const start = new Date(); - start.setHours(0, 0, 0, 0); - const end = new Date(start); - end.setDate(end.getDate() + 1); - return { start, end }; -} - export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req); + if (!gate.ok) return gate.response; + const auth = gate.auth; - const branchId = resolveBranchScope(auth, req.nextUrl.searchParams.get("branchId")); - const { start, end } = todayRange(); + const scope = branchParam(auth, req.nextUrl.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const branchId = scope.branchId; + const { start, end } = dayRangeNairobi(todayNairobi()); const matchStage: Record = { businessId: new mongoose.Types.ObjectId(auth.businessId), diff --git a/src/app/api/expenses/route.ts b/src/app/api/expenses/route.ts index 17cdc08..dffbefb 100644 --- a/src/app/api/expenses/route.ts +++ b/src/app/api/expenses/route.ts @@ -3,21 +3,25 @@ import { z } from "zod"; import { connectDb } from "@/lib/server/db"; import { Expense, EXPENSE_CATEGORIES } from "@/lib/server/models/Expense"; import { Branch } from "@/lib/server/models/Branch"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { objectId } from "@/lib/server/validation"; +import { authorize, branchParam, MANAGERS } from "@/lib/server/auth"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; // GET /api/expenses?branchId=&from=&to= -// SUPER_ADMIN sees all (optionally filtered by branch); everyone else is -// hard-scoped to their own branch regardless of query params. +// Managers and owners only. SUPER_ADMIN sees all (optionally filtered by +// branch); a BRANCH_MANAGER is hard-scoped to their own branch. export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const url = new URL(req.url); - const scopeBranch = resolveBranchScope(auth, url.searchParams.get("branchId")); + const scope = branchParam(auth, url.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const scopeBranch = scope.branchId; const filter: Record = { businessId: auth.businessId }; if (scopeBranch) filter.branchId = scopeBranch; @@ -42,7 +46,7 @@ export async function GET(req: NextRequest) { } const createSchema = z.object({ - branchId: z.string().trim().min(1).optional(), + branchId: objectId.optional(), category: z.enum(EXPENSE_CATEGORIES), amount: z.number().positive().max(100_000_000), description: z.string().trim().min(1).max(300), @@ -50,12 +54,13 @@ const createSchema = z.object({ notes: z.string().trim().max(500).optional(), }); -// POST /api/expenses — any authenticated staff can record an expense, but -// only against a branch they are allowed to touch. +// POST /api/expenses — managers and owners only, and only against a branch +// they are allowed to touch. export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = createSchema.safeParse(json); diff --git a/src/app/api/inventory/dispatch/route.ts b/src/app/api/inventory/dispatch/route.ts index 1f22f9b..843b0c0 100644 --- a/src/app/api/inventory/dispatch/route.ts +++ b/src/app/api/inventory/dispatch/route.ts @@ -3,27 +3,25 @@ import { z } from "zod"; import { connectDb } from "@/lib/server/db"; import { DailyInventory } from "@/lib/server/models/DailyInventory"; import { Branch } from "@/lib/server/models/Branch"; -import { getAuth, requireRole, resolveBranchScope } from "@/lib/server/auth"; +import { Product } from "@/lib/server/models/Product"; +import { authorize, MANAGERS, resolveBranchScope } from "@/lib/server/auth"; +import { isBusinessDate, todayNairobi } from "@/lib/server/businessDay"; +import { objectId } from "@/lib/server/validation"; export const runtime = "nodejs"; -function todayLocal(): string { - return new Date().toISOString().slice(0, 10); -} - const dispatchSchema = z.object({ - productId: z.string().min(1), + productId: objectId, morningDispatched: z.number().int().min(0), - date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(), - branchId: z.string().optional(), + date: z.string().refine(isBusinessDate, { message: "date must be YYYY-MM-DD" }).optional(), + branchId: objectId.optional(), }); export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = dispatchSchema.safeParse(json); @@ -31,18 +29,22 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); } - const branchId = resolveBranchScope(auth!, parsed.data.branchId); + const branchId = resolveBranchScope(auth, parsed.data.branchId); if (!branchId) return NextResponse.json({ error: "branchId is required" }, { status: 400 }); // The branch MUST belong to this tenant — blocks a crafted branchId from // writing inventory into another business. - const branch = await Branch.findOne({ _id: branchId, businessId: auth!.businessId }).lean(); + const branch = await Branch.findOne({ _id: branchId, businessId: auth.businessId }).lean(); if (!branch) return NextResponse.json({ error: "Branch not found in your business" }, { status: 404 }); - const date = parsed.data.date ?? todayLocal(); + // The product must belong to this tenant too. + const product = await Product.exists({ _id: parsed.data.productId, businessId: auth.businessId }); + if (!product) return NextResponse.json({ error: "Product not found in your business" }, { status: 404 }); + + const date = parsed.data.date ?? todayNairobi(); const row = await DailyInventory.findOneAndUpdate( { branchId, productId: parsed.data.productId, date }, - { morningDispatched: parsed.data.morningDispatched, recordedBy: auth!.sub, businessId: auth!.businessId }, + { morningDispatched: parsed.data.morningDispatched, recordedBy: auth.sub, businessId: auth.businessId }, { upsert: true, new: true, setDefaultsOnInsert: true } ); return NextResponse.json({ inventory: row }); diff --git a/src/app/api/inventory/evening-count/route.ts b/src/app/api/inventory/evening-count/route.ts index bc9de05..7c80057 100644 --- a/src/app/api/inventory/evening-count/route.ts +++ b/src/app/api/inventory/evening-count/route.ts @@ -3,27 +3,25 @@ import { z } from "zod"; import { connectDb } from "@/lib/server/db"; import { DailyInventory } from "@/lib/server/models/DailyInventory"; import { Branch } from "@/lib/server/models/Branch"; -import { getAuth, requireRole, resolveBranchScope } from "@/lib/server/auth"; +import { Product } from "@/lib/server/models/Product"; +import { authorize, MANAGERS, resolveBranchScope } from "@/lib/server/auth"; +import { isBusinessDate, todayNairobi } from "@/lib/server/businessDay"; +import { objectId } from "@/lib/server/validation"; export const runtime = "nodejs"; -function todayLocal(): string { - return new Date().toISOString().slice(0, 10); -} - const countSchema = z.object({ - productId: z.string().min(1), + productId: objectId, eveningPhysicalCount: z.number().int().min(0), - date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(), - branchId: z.string().optional(), + date: z.string().refine(isBusinessDate, { message: "date must be YYYY-MM-DD" }).optional(), + branchId: objectId.optional(), }); export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = countSchema.safeParse(json); @@ -31,17 +29,21 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); } - const branchId = resolveBranchScope(auth!, parsed.data.branchId); + const branchId = resolveBranchScope(auth, parsed.data.branchId); if (!branchId) return NextResponse.json({ error: "branchId is required" }, { status: 400 }); // The branch MUST belong to this tenant. - const branch = await Branch.findOne({ _id: branchId, businessId: auth!.businessId }).lean(); + const branch = await Branch.findOne({ _id: branchId, businessId: auth.businessId }).lean(); if (!branch) return NextResponse.json({ error: "Branch not found in your business" }, { status: 404 }); - const date = parsed.data.date ?? todayLocal(); + // The product must belong to this tenant too. + const product = await Product.exists({ _id: parsed.data.productId, businessId: auth.businessId }); + if (!product) return NextResponse.json({ error: "Product not found in your business" }, { status: 404 }); + + const date = parsed.data.date ?? todayNairobi(); const row = await DailyInventory.findOneAndUpdate( { branchId, productId: parsed.data.productId, date }, - { eveningPhysicalCount: parsed.data.eveningPhysicalCount, recordedBy: auth!.sub, businessId: auth!.businessId }, + { eveningPhysicalCount: parsed.data.eveningPhysicalCount, recordedBy: auth.sub, businessId: auth.businessId }, { upsert: true, new: true, setDefaultsOnInsert: true } ); return NextResponse.json({ inventory: row }); diff --git a/src/app/api/mpesa/callback/route.ts b/src/app/api/mpesa/callback/route.ts index 4b20887..653bbc6 100644 --- a/src/app/api/mpesa/callback/route.ts +++ b/src/app/api/mpesa/callback/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import { connectDb } from "@/lib/server/db"; +import { isMpesaEnabled } from "@/lib/server/env"; import { Transaction } from "@/lib/server/models/Transaction"; import { MpesaCallbackLog } from "@/lib/server/models/MpesaCallbackLog"; @@ -18,6 +19,7 @@ function isIpAllowed(ip: string): boolean { } export async function POST(req: NextRequest) { + if (!isMpesaEnabled()) return NextResponse.json({ error: "Not found" }, { status: 404 }); await connectDb(); const ack = () => NextResponse.json({ ResultCode: 0, ResultDesc: "Accepted" }); const sourceIp = getSourceIp(req); diff --git a/src/app/api/mpesa/status/[transactionId]/route.ts b/src/app/api/mpesa/status/[transactionId]/route.ts index 48faefc..3e2d8d9 100644 --- a/src/app/api/mpesa/status/[transactionId]/route.ts +++ b/src/app/api/mpesa/status/[transactionId]/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import { connectDb } from "@/lib/server/db"; +import { isMpesaEnabled } from "@/lib/server/env"; import { Transaction } from "@/lib/server/models/Transaction"; import { getAuth } from "@/lib/server/auth"; import { queryStkStatus } from "@/lib/server/mpesa"; @@ -8,6 +9,7 @@ export const runtime = "nodejs"; export const dynamic = "force-dynamic"; export async function GET(req: NextRequest, { params }: { params: { transactionId: string } }) { + if (!isMpesaEnabled()) return NextResponse.json({ error: "Not found" }, { status: 404 }); await connectDb(); const auth = getAuth(req); if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); diff --git a/src/app/api/mpesa/stkpush/route.ts b/src/app/api/mpesa/stkpush/route.ts index 4b8808a..aa4a8a0 100644 --- a/src/app/api/mpesa/stkpush/route.ts +++ b/src/app/api/mpesa/stkpush/route.ts @@ -1,6 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { connectDb } from "@/lib/server/db"; +import { isMpesaEnabled } from "@/lib/server/env"; import { Transaction } from "@/lib/server/models/Transaction"; import { Product, BranchPricing } from "@/lib/server/models/Product"; import { Branch } from "@/lib/server/models/Branch"; @@ -31,6 +32,7 @@ function rateLimited(key: string): boolean { } export async function POST(req: NextRequest) { + if (!isMpesaEnabled()) return NextResponse.json({ error: "Not found" }, { status: 404 }); await connectDb(); const auth = getAuth(req); if (!requireRole(auth, "DELIVERY", "BRANCH_MANAGER")) { diff --git a/src/app/api/products/[id]/route.ts b/src/app/api/products/[id]/route.ts index a2fc57d..1b5a095 100644 --- a/src/app/api/products/[id]/route.ts +++ b/src/app/api/products/[id]/route.ts @@ -2,7 +2,8 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { connectDb } from "@/lib/server/db"; import { Product } from "@/lib/server/models/Product"; -import { getAuth, requireRole } from "@/lib/server/auth"; +import { authorize } from "@/lib/server/auth"; +import { isValidObjectId } from "mongoose"; export const runtime = "nodejs"; @@ -12,14 +13,16 @@ const updateSchema = z.object({ unitPrice: z.number().nonnegative().optional(), sortOrder: z.number().int().optional(), isActive: z.boolean().optional(), + lowStockThreshold: z.number().int().min(0).max(1_000_000).optional(), }); export async function PATCH(req: NextRequest, { params }: { params: { id: string } }) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + // Owner only — product prices apply to every branch. + const gate = authorize(req, ["SUPER_ADMIN"]); + if (!gate.ok) return gate.response; + const auth = gate.auth; + if (!isValidObjectId(params.id)) return NextResponse.json({ error: "Product not found" }, { status: 404 }); const json = await req.json().catch(() => null); const parsed = updateSchema.safeParse(json); @@ -31,7 +34,7 @@ export async function PATCH(req: NextRequest, { params }: { params: { id: string } const product = await Product.findOneAndUpdate( - { _id: params.id, businessId: auth!.businessId }, + { _id: params.id, businessId: auth.businessId }, parsed.data, { new: true } ); diff --git a/src/app/api/products/route.ts b/src/app/api/products/route.ts index 4faf49d..7ad7635 100644 --- a/src/app/api/products/route.ts +++ b/src/app/api/products/route.ts @@ -1,18 +1,30 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { connectDb } from "@/lib/server/db"; -import { Product } from "@/lib/server/models/Product"; -import { getAuth, requireRole } from "@/lib/server/auth"; +import { Product, BranchPricing } from "@/lib/server/models/Product"; +import { authorize } from "@/lib/server/auth"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; +// GET /api/products — the tenant's active catalogue. For branch-scoped +// staff the price returned is the price THEIR branch charges (the branch +// override when one exists), so the terminal shows exactly what the +// server will record. export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req); + if (!gate.ok) return gate.response; + const auth = gate.auth; const products = await Product.find({ businessId: auth.businessId, isActive: true }).sort({ sortOrder: 1 }).lean(); + if (auth.branchId) { + const overrides = await BranchPricing.find({ businessId: auth.businessId, branchId: auth.branchId }).lean(); + const priceByProduct = new Map(overrides.map((o) => [o.productId.toString(), o.unitPrice])); + for (const p of products) { + p.unitPrice = priceByProduct.get(p._id.toString()) ?? p.unitPrice; + } + } return NextResponse.json({ products }); } @@ -23,20 +35,22 @@ const createSchema = z.object({ category: z.string().trim().min(1).max(40).optional(), unitPrice: z.number().nonnegative(), sortOrder: z.number().int().optional(), + lowStockThreshold: z.number().int().min(0).max(1_000_000).optional(), }); +// POST /api/products — owner only: the catalogue and its prices apply to +// every branch, so a branch manager must not be able to change them. export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, ["SUPER_ADMIN"]); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = createSchema.safeParse(json); if (!parsed.success) { return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); } - const product = await Product.create({ ...parsed.data, businessId: auth!.businessId }); + const product = await Product.create({ ...parsed.data, businessId: auth.businessId }); return NextResponse.json({ product }, { status: 201 }); } diff --git a/src/app/api/purchases/route.ts b/src/app/api/purchases/route.ts index 3b5d35f..00f6fc1 100644 --- a/src/app/api/purchases/route.ts +++ b/src/app/api/purchases/route.ts @@ -4,7 +4,8 @@ import { connectDb } from "@/lib/server/db"; import { Purchase } from "@/lib/server/models/Purchase"; import { Product } from "@/lib/server/models/Product"; import { Branch } from "@/lib/server/models/Branch"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { objectId } from "@/lib/server/validation"; +import { authorize, branchParam, MANAGERS } from "@/lib/server/auth"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; @@ -12,11 +13,14 @@ export const dynamic = "force-dynamic"; // GET /api/purchases?branchId=&from=&to= export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const url = new URL(req.url); - const scopeBranch = resolveBranchScope(auth, url.searchParams.get("branchId")); + const scope = branchParam(auth, url.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const scopeBranch = scope.branchId; const filter: Record = { businessId: auth.businessId }; if (scopeBranch) filter.branchId = scopeBranch; @@ -41,9 +45,9 @@ export async function GET(req: NextRequest) { } const createSchema = z.object({ - branchId: z.string().trim().min(1).optional(), + branchId: objectId.optional(), supplierName: z.string().trim().min(1).max(120), - productId: z.string().trim().min(1).optional(), + productId: objectId.optional(), productLabel: z.string().trim().min(1).max(120).optional(), quantity: z.number().int().positive().max(1_000_000), unitCost: z.number().nonnegative().max(100_000_000), @@ -57,8 +61,9 @@ const createSchema = z.object({ // branch stock. export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = createSchema.safeParse(json); diff --git a/src/app/api/reports/profit/route.ts b/src/app/api/reports/profit/route.ts index 89133d0..706fbf0 100644 --- a/src/app/api/reports/profit/route.ts +++ b/src/app/api/reports/profit/route.ts @@ -4,7 +4,8 @@ import { connectDb } from "@/lib/server/db"; import { Transaction } from "@/lib/server/models/Transaction"; import { Purchase } from "@/lib/server/models/Purchase"; import { Expense } from "@/lib/server/models/Expense"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { authorize, badRequest, branchParam, MANAGERS } from "@/lib/server/auth"; +import { startOfMonthNairobi } from "@/lib/server/businessDay"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; @@ -17,17 +18,21 @@ export const dynamic = "force-dynamic"; // Net Profit = Gross Profit - Expenses export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + // Revenue, costs and profit are owner/manager information, never a cashier's. + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const url = new URL(req.url); - const branchId = resolveBranchScope(auth, url.searchParams.get("branchId")); + const scope = branchParam(auth, url.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const branchId = scope.branchId; - // Default range: start of the current month -> now. + // Default range: start of the current business month (EAT) -> now. const now = new Date(); - const defaultFrom = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0); - const from = url.searchParams.get("from") ? new Date(url.searchParams.get("from")!) : defaultFrom; + const from = url.searchParams.get("from") ? new Date(url.searchParams.get("from")!) : startOfMonthNairobi(now); const to = url.searchParams.get("to") ? new Date(url.searchParams.get("to")!) : now; + if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime())) return badRequest("Invalid from/to date"); const branchObjId = branchId ? new mongoose.Types.ObjectId(branchId) : null; const businessObjId = new mongoose.Types.ObjectId(auth.businessId); diff --git a/src/app/api/transactions/route.ts b/src/app/api/transactions/route.ts index 3de7b63..7b8348f 100644 --- a/src/app/api/transactions/route.ts +++ b/src/app/api/transactions/route.ts @@ -1,25 +1,27 @@ import { NextRequest, NextResponse } from "next/server"; import { connectDb } from "@/lib/server/db"; import { Transaction } from "@/lib/server/models/Transaction"; -import { getAuth, resolveBranchScope } from "@/lib/server/auth"; +import { authorize, branchParam } from "@/lib/server/auth"; +import { startOfTodayNairobi } from "@/lib/server/businessDay"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!auth) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + const gate = authorize(req); + if (!gate.ok) return gate.response; + const auth = gate.auth; - const branchId = resolveBranchScope(auth, req.nextUrl.searchParams.get("branchId")); + const scope = branchParam(auth, req.nextUrl.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const branchId = scope.branchId; const limit = Math.min(Number(req.nextUrl.searchParams.get("limit")) || 50, 200); const filter: Record = { businessId: auth.businessId }; if (branchId) filter.branchId = branchId; - const startOfDay = new Date(); - startOfDay.setHours(0, 0, 0, 0); - filter.createdAt = { $gte: startOfDay }; + filter.createdAt = { $gte: startOfTodayNairobi() }; const transactions = await Transaction.find(filter) .sort({ createdAt: -1 }) diff --git a/src/app/api/users/[id]/route.ts b/src/app/api/users/[id]/route.ts new file mode 100644 index 0000000..0572791 --- /dev/null +++ b/src/app/api/users/[id]/route.ts @@ -0,0 +1,86 @@ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { isValidObjectId } from "mongoose"; +import { connectDb } from "@/lib/server/db"; +import { User } from "@/lib/server/models/User"; +import { Branch } from "@/lib/server/models/Branch"; +import { Business } from "@/lib/server/models/Business"; +import { UserSession } from "@/lib/server/models/UserSession"; +import { authorize, MANAGERS } from "@/lib/server/auth"; +import { objectId } from "@/lib/server/validation"; + +export const runtime = "nodejs"; + +const updateSchema = z + .object({ + isActive: z.boolean().optional(), + branchId: objectId.optional(), // owner only: move staff to another branch + }) + .refine((v) => v.isActive !== undefined || v.branchId !== undefined, { message: "No fields to update" }); + +/** + * PATCH /api/users/:id — deactivate/reactivate a staff account, or (owner + * only) move it to another branch. This is how an owner "removes" a user: + * the account and its sales history stay, but it can no longer sign in. + * + * SUPER_ADMIN any user in the business except themselves and the owner of record + * BRANCH_MANAGER only DELIVERY staff in their own branch, and only isActive + */ +export async function PATCH(req: NextRequest, { params }: { params: { id: string } }) { + await connectDb(); + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; + + if (!isValidObjectId(params.id)) return NextResponse.json({ error: "User not found" }, { status: 404 }); + + const json = await req.json().catch(() => null); + const parsed = updateSchema.safeParse(json); + if (!parsed.success) { + return NextResponse.json({ error: parsed.error.issues[0]?.message ?? "Invalid request" }, { status: 400 }); + } + const { isActive, branchId } = parsed.data; + + const target = await User.findOne({ _id: params.id, businessId: auth.businessId }); + if (!target) return NextResponse.json({ error: "User not found" }, { status: 404 }); + + if (target._id.toString() === auth.sub) { + return NextResponse.json({ error: "You cannot change your own account here" }, { status: 403 }); + } + + if (auth.role === "BRANCH_MANAGER") { + const ownStaff = target.role === "DELIVERY" && target.branchId?.toString() === auth.branchId; + if (!ownStaff) { + return NextResponse.json({ error: "Branch managers may only manage delivery staff in their own branch" }, { status: 403 }); + } + if (branchId !== undefined) { + return NextResponse.json({ error: "Only the owner can move staff between branches" }, { status: 403 }); + } + } + + const business = await Business.findById(auth.businessId).select("ownerId").lean(); + if (business && business.ownerId.toString() === target._id.toString()) { + return NextResponse.json({ error: "The business owner's account cannot be changed" }, { status: 403 }); + } + + if (branchId !== undefined) { + if (target.role === "SUPER_ADMIN") { + return NextResponse.json({ error: "Owner accounts are not tied to a branch" }, { status: 400 }); + } + const branch = await Branch.findOne({ _id: branchId, businessId: auth.businessId }).lean(); + if (!branch) return NextResponse.json({ error: "Branch not found in your business" }, { status: 404 }); + target.branchId = branch._id; + } + if (isActive !== undefined) target.isActive = isActive; + await target.save(); + + // Revoke every device session so a deactivated (or moved) user cannot + // mint new access tokens; any current access token expires within 15m. + if (isActive === false || branchId !== undefined) { + await UserSession.deleteMany({ userId: target._id }); + } + + const obj = target.toObject() as unknown as Record; + delete obj.passwordHash; + return NextResponse.json({ user: obj }); +} diff --git a/src/app/api/users/route.ts b/src/app/api/users/route.ts index 596a816..c821cbd 100644 --- a/src/app/api/users/route.ts +++ b/src/app/api/users/route.ts @@ -4,7 +4,8 @@ import { z } from "zod"; import { connectDb } from "@/lib/server/db"; import { User } from "@/lib/server/models/User"; import { Branch } from "@/lib/server/models/Branch"; -import { getAuth, requireRole, resolveBranchScope } from "@/lib/server/auth"; +import { authorize, branchParam, MANAGERS } from "@/lib/server/auth"; +import { objectId } from "@/lib/server/validation"; import { normalizeKenyanPhone } from "@/lib/server/phone"; import { userLimitError, loadTier } from "@/lib/server/subscription"; @@ -13,14 +14,14 @@ export const dynamic = "force-dynamic"; export async function GET(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; - const branchId = resolveBranchScope(auth!, req.nextUrl.searchParams.get("branchId")); - const filter: Record = { businessId: auth!.businessId }; - if (branchId) filter.branchId = branchId; + const scope = branchParam(auth, req.nextUrl.searchParams.get("branchId")); + if (!scope.ok) return scope.response; + const filter: Record = { businessId: auth.businessId }; + if (scope.branchId) filter.branchId = scope.branchId; const users = await User.find(filter).select("-passwordHash").sort({ name: 1 }).lean(); return NextResponse.json({ users }); } @@ -28,7 +29,7 @@ export async function GET(req: NextRequest) { const createSchema = z.object({ name: z.string().trim().min(1).max(120), role: z.enum(["DELIVERY", "BRANCH_MANAGER", "SUPER_ADMIN"]), - branchId: z.string().min(1).optional(), + branchId: objectId.optional(), phoneNumber: z.string().min(9).max(15), email: z.string().email(), password: z.string().min(8), @@ -36,10 +37,9 @@ const createSchema = z.object({ export async function POST(req: NextRequest) { await connectDb(); - const auth = getAuth(req); - if (!requireRole(auth, "BRANCH_MANAGER", "SUPER_ADMIN")) { - return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - } + const gate = authorize(req, MANAGERS); + if (!gate.ok) return gate.response; + const auth = gate.auth; const json = await req.json().catch(() => null); const parsed = createSchema.safeParse(json); @@ -48,22 +48,22 @@ export async function POST(req: NextRequest) { } const data = parsed.data; - if (auth!.role === "BRANCH_MANAGER") { + if (auth.role === "BRANCH_MANAGER") { if (data.role !== "DELIVERY") { return NextResponse.json({ error: "Branch managers may only create delivery staff accounts" }, { status: 403 }); } - if (data.branchId && data.branchId !== auth!.branchId) { + if (data.branchId && data.branchId !== auth.branchId) { return NextResponse.json({ error: "Branch managers may only add staff to their own branch" }, { status: 403 }); } } - const branchId = data.role === "SUPER_ADMIN" ? null : data.branchId ?? auth!.branchId ?? undefined; + const branchId = data.role === "SUPER_ADMIN" ? null : data.branchId ?? auth.branchId ?? undefined; if (data.role !== "SUPER_ADMIN" && !branchId) { return NextResponse.json({ error: "branchId is required for this role" }, { status: 400 }); } if (branchId) { - const branch = await Branch.findOne({ _id: branchId, businessId: auth!.businessId }).lean(); + const branch = await Branch.findOne({ _id: branchId, businessId: auth.businessId }).lean(); if (!branch) { return NextResponse.json({ error: "Branch not found in your business" }, { status: 404 }); } @@ -77,15 +77,15 @@ export async function POST(req: NextRequest) { } // Enforce the plan's user cap (counts owner + managers + staff). - const tier = await loadTier(auth!.businessId); - const userErr = await userLimitError(auth!.businessId, tier); + const tier = await loadTier(auth.businessId); + const userErr = await userLimitError(auth.businessId, tier); if (userErr) return NextResponse.json({ error: userErr }, { status: 403 }); const passwordHash = await bcrypt.hash(data.password, 12); try { const user = await User.create({ - businessId: auth!.businessId, + businessId: auth.businessId, name: data.name, role: data.role, branchId: branchId ?? null, @@ -96,7 +96,7 @@ export async function POST(req: NextRequest) { if (data.role === "BRANCH_MANAGER" && branchId) { await Branch.findOneAndUpdate( - { _id: branchId, businessId: auth!.businessId }, + { _id: branchId, businessId: auth.businessId }, { managerId: user._id } ); } diff --git a/src/lib/server/auth.ts b/src/lib/server/auth.ts index 66bfe82..0ce35dc 100644 --- a/src/lib/server/auth.ts +++ b/src/lib/server/auth.ts @@ -1,4 +1,5 @@ -import { NextRequest } from "next/server"; +import { NextRequest, NextResponse } from "next/server"; +import { isValidObjectId } from "mongoose"; import { verifyAccessToken, AccessTokenPayload } from "@/lib/server/jwt"; import { UserRole } from "@/lib/server/models/User"; @@ -27,6 +28,49 @@ export function resolveBranchScope(auth: AccessTokenPayload, requestedBranchId?: return auth.branchId; } +export const MANAGERS: UserRole[] = ["BRANCH_MANAGER", "SUPER_ADMIN"]; + +type Gate = { ok: true; auth: AccessTokenPayload } | { ok: false; response: NextResponse }; + +/** + * Authenticate the request and, when `roles` is given, authorize it. + * 401 = not signed in; 403 = signed in with the wrong role. Every route + * that limits roles must use this rather than relying on the admin pages + * redirecting — the PRD requires enforcement on the backend too. + */ +export function authorize(req: NextRequest, roles?: UserRole[]): Gate { + const auth = getAuth(req); + if (!auth) { + return { ok: false, response: NextResponse.json({ error: "Not authenticated" }, { status: 401 }) }; + } + if (roles && !roles.includes(auth.role)) { + return { + ok: false, + response: NextResponse.json({ error: "You do not have permission to do this" }, { status: 403 }), + }; + } + return { ok: true, auth }; +} + +type BranchParam = { ok: true; branchId: string | null } | { ok: false; response: NextResponse }; + +/** + * Resolve the `branchId` query parameter for a read route: owners may pick + * a branch or ALL, everyone else is pinned to their own branch. Rejects a + * malformed id with 400 instead of letting ObjectId() throw a 500. + */ +export function branchParam(auth: AccessTokenPayload, raw: string | null | undefined): BranchParam { + const branchId = resolveBranchScope(auth, raw); + if (branchId && !isValidObjectId(branchId)) { + return { ok: false, response: NextResponse.json({ error: "Invalid branchId" }, { status: 400 }) }; + } + return { ok: true, branchId }; +} + +export function badRequest(message: string): NextResponse { + return NextResponse.json({ error: message }, { status: 400 }); +} + export function isProd(): boolean { return process.env.NODE_ENV === "production"; } diff --git a/src/lib/server/businessDay.ts b/src/lib/server/businessDay.ts new file mode 100644 index 0000000..035b5e8 --- /dev/null +++ b/src/lib/server/businessDay.ts @@ -0,0 +1,40 @@ +// The business day for every tenant is the Kenyan calendar day +// (Africa/Nairobi, EAT). EAT is a fixed UTC+3 with no daylight saving, so a +// constant offset is exact — no timezone database needed. +// +// Never use `new Date().setHours(0)` or `toISOString().slice(0, 10)` for +// "today" on the server: on Vercel the server clock is UTC, which would +// start the business day at 03:00 EAT and push early-morning sales onto +// the previous day. + +const EAT_OFFSET_MS = 3 * 60 * 60 * 1000; +const DAY_MS = 24 * 60 * 60 * 1000; +const DATE_RE = /^\d{4}-\d{2}-\d{2}$/; + +/** Today's business day as YYYY-MM-DD. */ +export function todayNairobi(now: Date = new Date()): string { + return new Date(now.getTime() + EAT_OFFSET_MS).toISOString().slice(0, 10); +} + +export function isBusinessDate(value: string): boolean { + if (!DATE_RE.test(value)) return false; + const d = new Date(value + "T00:00:00.000Z"); + return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === value; +} + +/** The UTC instants [start, end) covering one business day. */ +export function dayRangeNairobi(date: string): { start: Date; end: Date } { + if (!isBusinessDate(date)) throw new Error(`Invalid business date: ${date}`); + const start = new Date(new Date(date + "T00:00:00.000Z").getTime() - EAT_OFFSET_MS); + return { start, end: new Date(start.getTime() + DAY_MS) }; +} + +/** Start of the business day containing `now`. */ +export function startOfTodayNairobi(now: Date = new Date()): Date { + return dayRangeNairobi(todayNairobi(now)).start; +} + +/** Start of the current business month (1st, 00:00 EAT). */ +export function startOfMonthNairobi(now: Date = new Date()): Date { + return dayRangeNairobi(todayNairobi(now).slice(0, 8) + "01").start; +} diff --git a/src/lib/server/env.ts b/src/lib/server/env.ts index 85cb7b9..393222a 100644 --- a/src/lib/server/env.ts +++ b/src/lib/server/env.ts @@ -1,26 +1,60 @@ import { z } from "zod"; -const schema = z.object({ - NODE_ENV: z.enum(["development", "production", "test"]).default("development"), - MONGODB_URI: z.string().min(1), +const booleanFlag = z + .enum(["true", "false", "1", "0", ""]) + .optional() + .transform((v) => v === "true" || v === "1"); - JWT_ACCESS_SECRET: z.string().min(16), - JWT_REFRESH_SECRET: z.string().min(16), - JWT_ACCESS_TTL: z.string().default("15m"), - JWT_REFRESH_TTL: z.string().default("30d"), - DELIVERY_MAX_DEVICES: z.coerce.number().default(2), +const schema = z + .object({ + NODE_ENV: z.enum(["development", "production", "test"]).default("development"), + MONGODB_URI: z.string().min(1), - DARAJA_ENV: z.enum(["sandbox", "production"]).default("sandbox"), - DARAJA_CONSUMER_KEY: z.string().min(1), - DARAJA_CONSUMER_SECRET: z.string().min(1), - DARAJA_SHORTCODE: z.string().min(1), - DARAJA_PASSKEY: z.string().min(1), - DARAJA_TRANSACTION_TYPE: z - .enum(["CustomerPayBillOnline", "CustomerBuyGoodsOnline"]) - .default("CustomerPayBillOnline"), - DARAJA_CALLBACK_URL: z.string().url(), - DARAJA_CALLBACK_IP_ALLOWLIST: z.string().optional(), -}); + JWT_ACCESS_SECRET: z.string().min(16), + JWT_REFRESH_SECRET: z.string().min(16), + JWT_ACCESS_TTL: z.string().default("15m"), + JWT_REFRESH_TTL: z.string().default("30d"), + DELIVERY_MAX_DEVICES: z.coerce.number().default(2), + + // M-Pesa STK Push is out of scope for the pilot (PRD section 4), so it + // is OFF unless explicitly enabled. When off, the Daraja variables are + // not required and every /api/mpesa route answers 404. + FEATURE_MPESA: booleanFlag, + + DARAJA_ENV: z.enum(["sandbox", "production"]).default("sandbox"), + DARAJA_CONSUMER_KEY: z.string().optional(), + DARAJA_CONSUMER_SECRET: z.string().optional(), + DARAJA_SHORTCODE: z.string().optional(), + DARAJA_PASSKEY: z.string().optional(), + DARAJA_TRANSACTION_TYPE: z + .enum(["CustomerPayBillOnline", "CustomerBuyGoodsOnline"]) + .default("CustomerPayBillOnline"), + DARAJA_CALLBACK_URL: z.string().url().optional(), + DARAJA_CALLBACK_IP_ALLOWLIST: z.string().optional(), + }) + .superRefine((env, ctx) => { + if (!env.FEATURE_MPESA) return; + const required = [ + "DARAJA_CONSUMER_KEY", + "DARAJA_CONSUMER_SECRET", + "DARAJA_SHORTCODE", + "DARAJA_PASSKEY", + "DARAJA_CALLBACK_URL", + ] as const; + for (const key of required) { + if (!env[key]) { + ctx.addIssue({ code: z.ZodIssueCode.custom, path: [key], message: "required when FEATURE_MPESA=true" }); + } + } + // An open callback endpoint lets anyone mark a pending sale as paid. + if (env.NODE_ENV === "production" && !env.DARAJA_CALLBACK_IP_ALLOWLIST) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["DARAJA_CALLBACK_IP_ALLOWLIST"], + message: "required in production when FEATURE_MPESA=true", + }); + } + }); type ServerEnv = z.infer; let cached: ServerEnv | null = null; @@ -35,3 +69,22 @@ export function getEnv(): ServerEnv { cached = parsed.data; return cached; } + +export function isMpesaEnabled(): boolean { + return getEnv().FEATURE_MPESA; +} + +/** Daraja settings, only valid when FEATURE_MPESA is on (validated above). */ +export function getDarajaEnv() { + const env = getEnv(); + if (!env.FEATURE_MPESA) throw new Error("M-Pesa is disabled (FEATURE_MPESA is not true)"); + return { + DARAJA_ENV: env.DARAJA_ENV, + DARAJA_CONSUMER_KEY: env.DARAJA_CONSUMER_KEY!, + DARAJA_CONSUMER_SECRET: env.DARAJA_CONSUMER_SECRET!, + DARAJA_SHORTCODE: env.DARAJA_SHORTCODE!, + DARAJA_PASSKEY: env.DARAJA_PASSKEY!, + DARAJA_TRANSACTION_TYPE: env.DARAJA_TRANSACTION_TYPE, + DARAJA_CALLBACK_URL: env.DARAJA_CALLBACK_URL!, + }; +} diff --git a/src/lib/server/models/Product.ts b/src/lib/server/models/Product.ts index fb656fe..b14f4bc 100644 --- a/src/lib/server/models/Product.ts +++ b/src/lib/server/models/Product.ts @@ -10,6 +10,7 @@ export interface IProduct extends Document { unitPrice: number; sortOrder: number; isActive: boolean; + lowStockThreshold: number; // a branch at or below this many units shows a low-stock warning createdAt: Date; updatedAt: Date; } @@ -24,6 +25,7 @@ const productSchema = new Schema( unitPrice: { type: Number, required: true, min: 0 }, sortOrder: { type: Number, default: 0 }, isActive: { type: Boolean, default: true, index: true }, + lowStockThreshold: { type: Number, default: 10, min: 0 }, }, { timestamps: true } ); diff --git a/src/lib/server/mpesa.ts b/src/lib/server/mpesa.ts index 1948f78..b0d9ba0 100644 --- a/src/lib/server/mpesa.ts +++ b/src/lib/server/mpesa.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { getEnv } from "@/lib/server/env"; +import { getDarajaEnv as getEnv } from "@/lib/server/env"; function baseUrl(): string { return getEnv().DARAJA_ENV === "production" diff --git a/src/lib/server/subscription.ts b/src/lib/server/subscription.ts index befbc76..002ba24 100644 --- a/src/lib/server/subscription.ts +++ b/src/lib/server/subscription.ts @@ -8,7 +8,7 @@ import { Types } from "mongoose"; import { Branch } from "@/lib/server/models/Branch"; import { User } from "@/lib/server/models/User"; import { Business, IBusiness } from "@/lib/server/models/Business"; -import { TIERS, type TierId } from "@/lib/tiers"; +import { TIERS, isUsable, type TierId, type SubscriptionStatus } from "@/lib/tiers"; export function tierOf(business: Pick): TierId { return (business.tier as TierId) ?? "STARTER"; @@ -52,4 +52,19 @@ export async function userLimitError( export async function loadTier(businessId: Types.ObjectId | string): Promise { const biz = await Business.findById(businessId).select("tier").lean(); return tierOf({ tier: (biz?.tier as TierId) ?? "STARTER" } as IBusiness); -} \ No newline at end of file +} + +/** + * Returns a user-facing reason this tenant may not use the app right now, + * or null when access is allowed. Checked at login and on every token + * refresh, so a suspension takes effect within one access-token lifetime + * (15 minutes) even for devices that are already signed in. + */ +export async function tenantAccessError(businessId: Types.ObjectId | string): Promise { + const biz = await Business.findById(businessId).select("isActive subscriptionStatus").lean(); + if (!biz || !biz.isActive) return "This business account has been deactivated."; + if (!isUsable((biz.subscriptionStatus as SubscriptionStatus) ?? "TRIALING")) { + return "This business account is suspended. Contact support to restore access."; + } + return null; +} diff --git a/src/lib/server/validation.ts b/src/lib/server/validation.ts new file mode 100644 index 0000000..401bf49 --- /dev/null +++ b/src/lib/server/validation.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; +import { isValidObjectId } from "mongoose"; + +/** A MongoDB ObjectId string. Validating up front turns a would-be CastError 500 into a 400. */ +export const objectId = z + .string() + .trim() + .refine((v) => isValidObjectId(v) && /^[0-9a-f]{24}$/i.test(v), { message: "Invalid id" }); diff --git a/tests/access.test.ts b/tests/access.test.ts new file mode 100644 index 0000000..a1e7f82 --- /dev/null +++ b/tests/access.test.ts @@ -0,0 +1,166 @@ +import { describe, expect, it } from "vitest"; +import bcrypt from "bcryptjs"; +import { Business } from "@/lib/server/models/Business"; +import { User } from "@/lib/server/models/User"; +import { UserSession } from "@/lib/server/models/UserSession"; +import * as profit from "@/app/api/reports/profit/route"; +import * as expenses from "@/app/api/expenses/route"; +import * as purchases from "@/app/api/purchases/route"; +import * as products from "@/app/api/products/route"; +import * as productById from "@/app/api/products/[id]/route"; +import * as userById from "@/app/api/users/[id]/route"; +import * as branchById from "@/app/api/branches/[id]/route"; +import * as summary from "@/app/api/dashboard/summary/route"; +import * as login from "@/app/api/auth/login/route"; +import * as signup from "@/app/api/auth/signup/route"; +import * as stkpush from "@/app/api/mpesa/stkpush/route"; +import * as callback from "@/app/api/mpesa/callback/route"; +import { json, makeTenant, params, req, uuid } from "./helpers"; + +describe("role-based access on the backend", () => { + it("blocks cashiers from owner-level money endpoints with 403", async () => { + const t = await makeTenant(); + const as = t.cashierA; + const responses = await Promise.all([ + profit.GET(req("GET", "/api/reports/profit", { as })), + expenses.GET(req("GET", "/api/expenses", { as })), + purchases.GET(req("GET", "/api/purchases", { as })), + expenses.POST(req("POST", "/api/expenses", { as, body: { category: "Rent", amount: 10, description: "x" } })), + purchases.POST( + req("POST", "/api/purchases", { as, body: { supplierName: "s", productLabel: "x", quantity: 1, unitCost: 1 } }) + ), + ]); + expect(responses.map((r) => r.status)).toEqual([403, 403, 403, 403, 403]); + }); + + it("still lets a branch manager use them for their own branch", async () => { + const t = await makeTenant(); + const res = await expenses.POST( + req("POST", "/api/expenses", { as: t.managerA, body: { category: "Rent", amount: 10, description: "rent" } }) + ); + expect(res.status).toBe(201); + expect((await profit.GET(req("GET", "/api/reports/profit", { as: t.managerA }))).status).toBe(200); + }); + + it("returns 401, not 403, when signed out", async () => { + expect((await profit.GET(req("GET", "/api/reports/profit"))).status).toBe(401); + }); + + it("only lets the owner create or reprice products", async () => { + const t = await makeTenant(); + const body = { label: "1L", sizeLiters: 1, unitPrice: 20 }; + expect((await products.POST(req("POST", "/api/products", { as: t.managerA, body }))).status).toBe(403); + expect( + (await productById.PATCH(req("PATCH", "/x", { as: t.managerA, body: { unitPrice: 1 } }), params({ id: t.water20 }))) + .status + ).toBe(403); + expect((await products.POST(req("POST", "/api/products", { as: t.owner, body }))).status).toBe(201); + }); + + it("rejects a malformed branchId with 400 instead of crashing", async () => { + const t = await makeTenant(); + const res = await summary.GET(req("GET", "/api/dashboard/summary?branchId=abc", { as: t.owner })); + expect(res.status).toBe(400); + }); +}); + +describe("user deactivation", () => { + it("lets a manager deactivate their own cashier and revokes that cashier's sessions", async () => { + const t = await makeTenant(); + await UserSession.create({ + userId: t.cashierA.id, + deviceId: uuid(), + refreshTokenHash: "h", + expiresAt: new Date(Date.now() + 86_400_000), + }); + const res = await userById.PATCH( + req("PATCH", "/x", { as: t.managerA, body: { isActive: false } }), + params({ id: t.cashierA.id }) + ); + expect(res.status).toBe(200); + expect((await User.findById(t.cashierA.id))!.isActive).toBe(false); + expect(await UserSession.countDocuments({ userId: t.cashierA.id })).toBe(0); + }); + + it("does not let a manager touch another branch's staff", async () => { + const t = await makeTenant(); + const res = await userById.PATCH( + req("PATCH", "/x", { as: t.managerA, body: { isActive: false } }), + params({ id: t.cashierB.id }) + ); + expect(res.status).toBe(403); + }); + + it("does not let the owner deactivate themselves", async () => { + const t = await makeTenant(); + const res = await userById.PATCH( + req("PATCH", "/x", { as: t.owner, body: { isActive: false } }), + params({ id: t.owner.id }) + ); + expect(res.status).toBe(403); + }); +}); + +describe("tenant status", () => { + it("refuses login for a suspended business", async () => { + const t = await makeTenant(); + const passwordHash = await bcrypt.hash("correct-horse", 4); + await User.updateOne({ _id: t.cashierA.id }, { passwordHash }); + await Business.updateOne({ _id: t.businessId }, { subscriptionStatus: "SUSPENDED" }); + + const res = await login.POST( + req("POST", "/api/auth/login", { + body: { email: t.cashierA.email, password: "correct-horse", deviceId: uuid() }, + }) + ); + expect(res.status).toBe(403); + }); + + it("still allows login for an active business", async () => { + const t = await makeTenant(); + const passwordHash = await bcrypt.hash("correct-horse", 4); + await User.updateOne({ _id: t.managerA.id }, { passwordHash }); + const res = await login.POST( + req("POST", "/api/auth/login", { + body: { email: t.managerA.email, password: "correct-horse", deviceId: uuid() }, + }) + ); + expect(res.status).toBe(200); + }); +}); + +describe("platform and M-Pesa hardening", () => { + it("refuses public signup with a platform-operator email", async () => { + const res = await signup.POST( + req("POST", "/api/auth/signup", { + body: { + businessName: "Takeover Ltd", + ownerName: "Mallory", + email: "operator@aquaflow.test", + phoneNumber: "0712345678", + password: "password123", + deviceId: uuid(), + }, + }) + ); + expect(res.status).toBe(403); + }); + + it("hides every M-Pesa route when FEATURE_MPESA is off", async () => { + const t = await makeTenant(); + const push = await stkpush.POST( + req("POST", "/api/mpesa/stkpush", { as: t.cashierA, body: { customerPhone: "0712345678", productId: t.water20, quantity: 1 } }) + ); + const cb = await callback.POST(req("POST", "/api/mpesa/callback", { body: { Body: {} } })); + expect([push.status, cb.status]).toEqual([404, 404]); + }); + + it("lets only the owner rename a branch", async () => { + const t = await makeTenant(); + const body = { branchName: "Renamed" }; + expect((await branchById.PATCH(req("PATCH", "/x", { as: t.managerA, body }), params({ id: t.branchA }))).status).toBe(403); + const ok = await json(await branchById.PATCH(req("PATCH", "/x", { as: t.owner, body }), params({ id: t.branchA }))); + expect(ok.status).toBe(200); + expect(ok.body.branch.branchName).toBe("Renamed"); + }); +}); diff --git a/tests/businessDay.test.ts b/tests/businessDay.test.ts new file mode 100644 index 0000000..f208b89 --- /dev/null +++ b/tests/businessDay.test.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from "vitest"; +import { dayRangeNairobi, isBusinessDate, startOfMonthNairobi, todayNairobi } from "@/lib/server/businessDay"; + +describe("Nairobi business day", () => { + it("rolls over at midnight EAT, not midnight UTC", () => { + // 00:30 EAT on 12 Oct = 21:30 UTC on 11 Oct. + expect(todayNairobi(new Date("2026-10-11T21:30:00Z"))).toBe("2026-10-12"); + // 23:30 EAT on 11 Oct = 20:30 UTC on 11 Oct. + expect(todayNairobi(new Date("2026-10-11T20:30:00Z"))).toBe("2026-10-11"); + }); + + it("maps a business date to the UTC range 21:00 -> 21:00", () => { + const { start, end } = dayRangeNairobi("2026-10-12"); + expect(start.toISOString()).toBe("2026-10-11T21:00:00.000Z"); + expect(end.toISOString()).toBe("2026-10-12T21:00:00.000Z"); + }); + + it("starts the month on the 1st at 00:00 EAT", () => { + expect(startOfMonthNairobi(new Date("2026-10-31T22:00:00Z")).toISOString()).toBe("2026-10-31T21:00:00.000Z"); + expect(startOfMonthNairobi(new Date("2026-10-15T10:00:00Z")).toISOString()).toBe("2026-09-30T21:00:00.000Z"); + }); + + it("rejects malformed dates", () => { + expect(isBusinessDate("2026-02-30")).toBe(false); + expect(isBusinessDate("2026-2-3")).toBe(false); + expect(isBusinessDate("2026-02-28")).toBe(true); + expect(() => dayRangeNairobi("nope")).toThrow(); + }); +}); diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts new file mode 100644 index 0000000..7716e8e --- /dev/null +++ b/tests/globalSetup.ts @@ -0,0 +1,12 @@ +import { MongoMemoryServer } from "mongodb-memory-server"; + +let server: MongoMemoryServer | null = null; + +export async function setup({ provide }: { provide: (key: string, value: string) => void }) { + server = await MongoMemoryServer.create(); + provide("mongoUri", server.getUri("aquaflow-test")); +} + +export async function teardown() { + await server?.stop(); +} diff --git a/tests/helpers.ts b/tests/helpers.ts new file mode 100644 index 0000000..b52c9cf --- /dev/null +++ b/tests/helpers.ts @@ -0,0 +1,133 @@ +import { randomUUID } from "crypto"; +import mongoose from "mongoose"; +import { NextRequest } from "next/server"; +import { Business } from "@/lib/server/models/Business"; +import { Branch } from "@/lib/server/models/Branch"; +import { User, UserRole } from "@/lib/server/models/User"; +import { Product } from "@/lib/server/models/Product"; +import { signAccessToken } from "@/lib/server/jwt"; +import { ACCESS_COOKIE } from "@/lib/server/auth"; + +let phoneSeq = 0; +function nextPhone(): string { + phoneSeq += 1; + return "2547" + String(10_000_000 + phoneSeq).slice(-8); +} + +export interface Actor { + id: string; + businessId: string; + role: UserRole; + branchId: string | null; + email: string; +} + +export interface Tenant { + businessId: string; + owner: Actor; + branchA: string; + branchB: string; + managerA: Actor; + cashierA: Actor; + cashierB: Actor; + water20: string; + water5: string; +} + +async function makeUser( + businessId: string, + role: UserRole, + branchId: string | null, + label: string +): Promise { + const email = `${label}-${randomUUID().slice(0, 8)}@aquaflow.test`; + const user = await User.create({ + businessId, + name: label, + role, + branchId, + phoneNumber: nextPhone(), + email, + passwordHash: "$2a$12$abcdefghijklmnopqrstuuJ0dBz7m6Y8yCjvC7vQ7hZqXbY8yCjvC", // never used to log in + }); + return { id: user._id.toString(), businessId, role, branchId, email }; +} + +/** A complete tenant: owner, two branches, a manager, a cashier per branch, two products. */ +export async function makeTenant(name = "Tenant"): Promise { + const business = await Business.create({ + name, + ownerId: new mongoose.Types.ObjectId(), + tier: "ENTERPRISE", + subscriptionStatus: "ACTIVE", + }); + const businessId = business._id.toString(); + const owner = await makeUser(businessId, "SUPER_ADMIN", null, name + "-owner"); + business.ownerId = new mongoose.Types.ObjectId(owner.id); + await business.save(); + + const a = await Branch.create({ businessId, branchName: name + " A", locationCity: "Nairobi" }); + const b = await Branch.create({ businessId, branchName: name + " B", locationCity: "Thika" }); + const managerA = await makeUser(businessId, "BRANCH_MANAGER", a._id.toString(), name + "-mgrA"); + const cashierA = await makeUser(businessId, "DELIVERY", a._id.toString(), name + "-cashA"); + const cashierB = await makeUser(businessId, "DELIVERY", b._id.toString(), name + "-cashB"); + + const [p20, p5] = await Product.insertMany([ + { businessId, label: "20L Jerrycan", sizeLiters: 20, unitPrice: 200, sortOrder: 1 }, + { businessId, label: "5L Jerrycan", sizeLiters: 5, unitPrice: 60, sortOrder: 2 }, + ]); + + return { + businessId, + owner, + branchA: a._id.toString(), + branchB: b._id.toString(), + managerA, + cashierA, + cashierB, + water20: p20._id.toString(), + water5: p5._id.toString(), + }; +} + +export function tokenFor(actor: Actor, deviceId = "00000000-0000-4000-8000-000000000001"): string { + return signAccessToken({ + sub: actor.id, + businessId: actor.businessId, + role: actor.role, + branchId: actor.branchId, + deviceId, + }); +} + +export function req( + method: string, + path: string, + opts: { as?: Actor; body?: unknown; cookies?: Record } = {} +): NextRequest { + const cookies: Record = { ...(opts.cookies ?? {}) }; + if (opts.as) cookies[ACCESS_COOKIE] = tokenFor(opts.as); + const cookieHeader = Object.entries(cookies) + .map(([k, v]) => `${k}=${v}`) + .join("; "); + return new NextRequest(new URL(path, "http://localhost"), { + method, + headers: { + "content-type": "application/json", + ...(cookieHeader ? { cookie: cookieHeader } : {}), + }, + body: opts.body === undefined ? undefined : JSON.stringify(opts.body), + }); +} + +export function params>(p: T) { + return { params: p }; +} + +export async function json(res: Response): Promise<{ status: number; body: T }> { + return { status: res.status, body: (await res.json()) as T }; +} + +export function uuid(): string { + return randomUUID(); +} diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..6caf82b --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,26 @@ +import { afterAll, beforeEach, inject } from "vitest"; +import mongoose from "mongoose"; +import { connectDb } from "@/lib/server/db"; + +declare module "vitest" { + export interface ProvidedContext { + mongoUri: string; + } +} + +process.env.MONGODB_URI = inject("mongoUri"); +process.env.JWT_ACCESS_SECRET = "test-access-secret-0123456789"; +process.env.JWT_REFRESH_SECRET = "test-refresh-secret-0123456789"; +process.env.PLATFORM_ADMIN_EMAILS = "operator@aquaflow.test"; + +beforeEach(async () => { + await connectDb(); + const collections = await mongoose.connection.db!.collections(); + await Promise.all(collections.map((c) => c.deleteMany({}))); + await Promise.all(Object.values(mongoose.models).map((m) => m.syncIndexes())); +}); + +afterAll(async () => { + await mongoose.disconnect(); + global.__mongooseCache = { conn: null, promise: null }; +}); diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo deleted file mode 100644 index d66aeb6..0000000 --- a/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/prop-types/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/future/route-kind.d.ts","./node_modules/next/dist/server/future/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/future/route-matches/route-match.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/server/lib/revalidate.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/future/helpers/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/font-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/future/route-modules/route-module.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/server/future/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/future/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/client/components/static-generation-async-storage-instance.d.ts","./node_modules/next/dist/client/components/static-generation-async-storage.external.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/client/components/request-async-storage-instance.d.ts","./node_modules/next/dist/client/components/request-async-storage.external.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/module.compiled.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/router-reducer/create-initial-router-state.d.ts","./node_modules/next/dist/client/components/app-router.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/client/components/action-async-storage-instance.d.ts","./node_modules/next/dist/client/components/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/search-params.d.ts","./node_modules/next/dist/client/components/not-found-boundary.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/lib/builtin-request-context.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/future/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/future/route-modules/pages/module.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/future/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/future/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/future/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/future/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/future/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/future/normalizers/normalizer.d.ts","./node_modules/next/dist/server/future/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/future/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/future/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/future/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/future/normalizers/request/prefix.d.ts","./node_modules/next/dist/server/future/normalizers/request/postponed.d.ts","./node_modules/next/dist/server/future/normalizers/request/action.d.ts","./node_modules/next/dist/server/future/normalizers/request/prefetch-rsc.d.ts","./node_modules/next/dist/server/future/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/webpack/plugins/define-env-plugin.d.ts","./node_modules/next/dist/build/swc/index.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/types/index.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/client/components/draft-mode.d.ts","./node_modules/next/dist/client/components/headers.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./next-env.d.ts","./node_modules/source-map-js/source-map.d.ts","./node_modules/postcss/lib/previous-map.d.ts","./node_modules/postcss/lib/input.d.ts","./node_modules/postcss/lib/css-syntax-error.d.ts","./node_modules/postcss/lib/declaration.d.ts","./node_modules/postcss/lib/root.d.ts","./node_modules/postcss/lib/warning.d.ts","./node_modules/postcss/lib/lazy-result.d.ts","./node_modules/postcss/lib/no-work-result.d.ts","./node_modules/postcss/lib/processor.d.ts","./node_modules/postcss/lib/result.d.ts","./node_modules/postcss/lib/document.d.ts","./node_modules/postcss/lib/rule.d.ts","./node_modules/postcss/lib/node.d.ts","./node_modules/postcss/lib/comment.d.ts","./node_modules/postcss/lib/container.d.ts","./node_modules/postcss/lib/at-rule.d.ts","./node_modules/postcss/lib/list.d.ts","./node_modules/postcss/lib/postcss.d.ts","./node_modules/postcss/lib/postcss.d.mts","./node_modules/tailwindcss/types/generated/corepluginlist.d.ts","./node_modules/tailwindcss/types/generated/colors.d.ts","./node_modules/tailwindcss/types/config.d.ts","./node_modules/tailwindcss/types/index.d.ts","./tailwind.config.ts","./node_modules/dotenv/lib/main.d.ts","./node_modules/bson/bson.d.ts","./node_modules/mongodb/mongodb.d.ts","./node_modules/mongoose/types/aggregate.d.ts","./node_modules/mongoose/types/callback.d.ts","./node_modules/mongoose/types/collection.d.ts","./node_modules/mongoose/types/connection.d.ts","./node_modules/mongoose/types/cursor.d.ts","./node_modules/mongoose/types/document.d.ts","./node_modules/mongoose/types/error.d.ts","./node_modules/mongoose/types/expressions.d.ts","./node_modules/mongoose/types/helpers.d.ts","./node_modules/kareem/index.d.ts","./node_modules/mongoose/types/middlewares.d.ts","./node_modules/mongoose/types/indexes.d.ts","./node_modules/mongoose/types/models.d.ts","./node_modules/mongoose/types/mongooseoptions.d.ts","./node_modules/mongoose/types/pipelinestage.d.ts","./node_modules/mongoose/types/populate.d.ts","./node_modules/mongoose/types/query.d.ts","./node_modules/mongoose/types/schemaoptions.d.ts","./node_modules/mongoose/types/schematypes.d.ts","./node_modules/mongoose/types/session.d.ts","./node_modules/mongoose/types/types.d.ts","./node_modules/mongoose/types/utility.d.ts","./node_modules/mongoose/types/validation.d.ts","./node_modules/mongoose/types/inferschematype.d.ts","./node_modules/mongoose/types/inferrawdoctype.d.ts","./node_modules/mongoose/types/virtuals.d.ts","./node_modules/mongoose/types/augmentations.d.ts","./node_modules/mongoose/types/index.d.ts","./src/lib/server/db.ts","./node_modules/@types/bcryptjs/index.d.ts","./src/lib/server/models/user.ts","./src/lib/server/models/branch.ts","./src/lib/server/models/product.ts","./src/lib/server/models/transaction.ts","./src/lib/server/models/dailyinventory.ts","./src/lib/server/models/expense.ts","./src/lib/server/models/purchase.ts","./src/lib/tiers.ts","./src/lib/server/models/business.ts","./scripts/migrate-multitenant.ts","./scripts/seed.ts","./node_modules/zod/v3/helpers/typealiases.d.cts","./node_modules/zod/v3/helpers/util.d.cts","./node_modules/zod/v3/index.d.cts","./node_modules/zod/v3/zoderror.d.cts","./node_modules/zod/v3/locales/en.d.cts","./node_modules/zod/v3/errors.d.cts","./node_modules/zod/v3/helpers/parseutil.d.cts","./node_modules/zod/v3/helpers/enumutil.d.cts","./node_modules/zod/v3/helpers/errorutil.d.cts","./node_modules/zod/v3/helpers/partialutil.d.cts","./node_modules/zod/v3/standard-schema.d.cts","./node_modules/zod/v3/types.d.cts","./node_modules/zod/v3/external.d.cts","./node_modules/zod/index.d.cts","./src/lib/server/models/usersession.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/jsonwebtoken/index.d.ts","./src/lib/server/env.ts","./src/lib/server/jwt.ts","./src/lib/server/auth.ts","./src/lib/server/platform.ts","./src/app/api/auth/login/route.ts","./src/app/api/auth/logout/route.ts","./src/app/api/auth/me/route.ts","./src/app/api/auth/refresh/route.ts","./src/app/api/auth/sessions/route.ts","./src/app/api/auth/sessions/[deviceid]/route.ts","./src/lib/server/phone.ts","./src/app/api/auth/signup/route.ts","./src/lib/server/subscription.ts","./src/app/api/branches/route.ts","./src/app/api/dashboard/reconciliation/route.ts","./src/app/api/dashboard/summary/route.ts","./src/app/api/expenses/route.ts","./src/app/api/health/route.ts","./src/app/api/inventory/dispatch/route.ts","./src/app/api/inventory/evening-count/route.ts","./src/lib/server/models/mpesacallbacklog.ts","./src/app/api/mpesa/callback/route.ts","./node_modules/axios/index.d.ts","./src/lib/server/mpesa.ts","./src/app/api/mpesa/status/[transactionid]/route.ts","./src/app/api/mpesa/stkpush/route.ts","./src/app/api/platform/businesses/route.ts","./src/app/api/platform/businesses/[id]/route.ts","./src/app/api/products/route.ts","./src/app/api/products/[id]/route.ts","./src/app/api/purchases/route.ts","./src/app/api/reports/profit/route.ts","./src/app/api/transactions/route.ts","./src/app/api/transactions/cash/route.ts","./src/app/api/users/route.ts","./src/lib/deviceid.ts","./src/lib/api.ts","./node_modules/idb/build/wrap-idb-value.d.ts","./node_modules/idb/build/entry.d.ts","./node_modules/idb/build/database-extras.d.ts","./node_modules/idb/build/async-iterators.d.ts","./node_modules/idb/build/index.d.ts","./src/lib/offlinequeue.ts","./src/lib/phone.ts","./src/lib/types.ts","./src/lib/pollingfeed.ts","./src/components/ui/toast.tsx","./src/app/layout.tsx","./src/app/page.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/emptystate.tsx","./src/app/admin/branches/page.tsx","./src/components/admin/globalswitcher.tsx","./src/components/admin/financialoverviewcards.tsx","./src/components/admin/paymentsplitdonut.tsx","./src/components/admin/radialgauge.tsx","./src/components/admin/livestatsrow.tsx","./src/components/admin/branchrankinglist.tsx","./node_modules/date-fns/locale/types.d.ts","./node_modules/date-fns/fp/types.d.ts","./node_modules/date-fns/types.d.ts","./node_modules/date-fns/add.d.ts","./node_modules/date-fns/addbusinessdays.d.ts","./node_modules/date-fns/adddays.d.ts","./node_modules/date-fns/addhours.d.ts","./node_modules/date-fns/addisoweekyears.d.ts","./node_modules/date-fns/addmilliseconds.d.ts","./node_modules/date-fns/addminutes.d.ts","./node_modules/date-fns/addmonths.d.ts","./node_modules/date-fns/addquarters.d.ts","./node_modules/date-fns/addseconds.d.ts","./node_modules/date-fns/addweeks.d.ts","./node_modules/date-fns/addyears.d.ts","./node_modules/date-fns/areintervalsoverlapping.d.ts","./node_modules/date-fns/clamp.d.ts","./node_modules/date-fns/closestindexto.d.ts","./node_modules/date-fns/closestto.d.ts","./node_modules/date-fns/compareasc.d.ts","./node_modules/date-fns/comparedesc.d.ts","./node_modules/date-fns/constructfrom.d.ts","./node_modules/date-fns/constructnow.d.ts","./node_modules/date-fns/daystoweeks.d.ts","./node_modules/date-fns/differenceinbusinessdays.d.ts","./node_modules/date-fns/differenceincalendardays.d.ts","./node_modules/date-fns/differenceincalendarisoweekyears.d.ts","./node_modules/date-fns/differenceincalendarisoweeks.d.ts","./node_modules/date-fns/differenceincalendarmonths.d.ts","./node_modules/date-fns/differenceincalendarquarters.d.ts","./node_modules/date-fns/differenceincalendarweeks.d.ts","./node_modules/date-fns/differenceincalendaryears.d.ts","./node_modules/date-fns/differenceindays.d.ts","./node_modules/date-fns/differenceinhours.d.ts","./node_modules/date-fns/differenceinisoweekyears.d.ts","./node_modules/date-fns/differenceinmilliseconds.d.ts","./node_modules/date-fns/differenceinminutes.d.ts","./node_modules/date-fns/differenceinmonths.d.ts","./node_modules/date-fns/differenceinquarters.d.ts","./node_modules/date-fns/differenceinseconds.d.ts","./node_modules/date-fns/differenceinweeks.d.ts","./node_modules/date-fns/differenceinyears.d.ts","./node_modules/date-fns/eachdayofinterval.d.ts","./node_modules/date-fns/eachhourofinterval.d.ts","./node_modules/date-fns/eachminuteofinterval.d.ts","./node_modules/date-fns/eachmonthofinterval.d.ts","./node_modules/date-fns/eachquarterofinterval.d.ts","./node_modules/date-fns/eachweekofinterval.d.ts","./node_modules/date-fns/eachweekendofinterval.d.ts","./node_modules/date-fns/eachweekendofmonth.d.ts","./node_modules/date-fns/eachweekendofyear.d.ts","./node_modules/date-fns/eachyearofinterval.d.ts","./node_modules/date-fns/endofday.d.ts","./node_modules/date-fns/endofdecade.d.ts","./node_modules/date-fns/endofhour.d.ts","./node_modules/date-fns/endofisoweek.d.ts","./node_modules/date-fns/endofisoweekyear.d.ts","./node_modules/date-fns/endofminute.d.ts","./node_modules/date-fns/endofmonth.d.ts","./node_modules/date-fns/endofquarter.d.ts","./node_modules/date-fns/endofsecond.d.ts","./node_modules/date-fns/endoftoday.d.ts","./node_modules/date-fns/endoftomorrow.d.ts","./node_modules/date-fns/endofweek.d.ts","./node_modules/date-fns/endofyear.d.ts","./node_modules/date-fns/endofyesterday.d.ts","./node_modules/date-fns/_lib/format/formatters.d.ts","./node_modules/date-fns/_lib/format/longformatters.d.ts","./node_modules/date-fns/format.d.ts","./node_modules/date-fns/formatdistance.d.ts","./node_modules/date-fns/formatdistancestrict.d.ts","./node_modules/date-fns/formatdistancetonow.d.ts","./node_modules/date-fns/formatdistancetonowstrict.d.ts","./node_modules/date-fns/formatduration.d.ts","./node_modules/date-fns/formatiso.d.ts","./node_modules/date-fns/formatiso9075.d.ts","./node_modules/date-fns/formatisoduration.d.ts","./node_modules/date-fns/formatrfc3339.d.ts","./node_modules/date-fns/formatrfc7231.d.ts","./node_modules/date-fns/formatrelative.d.ts","./node_modules/date-fns/fromunixtime.d.ts","./node_modules/date-fns/getdate.d.ts","./node_modules/date-fns/getday.d.ts","./node_modules/date-fns/getdayofyear.d.ts","./node_modules/date-fns/getdaysinmonth.d.ts","./node_modules/date-fns/getdaysinyear.d.ts","./node_modules/date-fns/getdecade.d.ts","./node_modules/date-fns/_lib/defaultoptions.d.ts","./node_modules/date-fns/getdefaultoptions.d.ts","./node_modules/date-fns/gethours.d.ts","./node_modules/date-fns/getisoday.d.ts","./node_modules/date-fns/getisoweek.d.ts","./node_modules/date-fns/getisoweekyear.d.ts","./node_modules/date-fns/getisoweeksinyear.d.ts","./node_modules/date-fns/getmilliseconds.d.ts","./node_modules/date-fns/getminutes.d.ts","./node_modules/date-fns/getmonth.d.ts","./node_modules/date-fns/getoverlappingdaysinintervals.d.ts","./node_modules/date-fns/getquarter.d.ts","./node_modules/date-fns/getseconds.d.ts","./node_modules/date-fns/gettime.d.ts","./node_modules/date-fns/getunixtime.d.ts","./node_modules/date-fns/getweek.d.ts","./node_modules/date-fns/getweekofmonth.d.ts","./node_modules/date-fns/getweekyear.d.ts","./node_modules/date-fns/getweeksinmonth.d.ts","./node_modules/date-fns/getyear.d.ts","./node_modules/date-fns/hourstomilliseconds.d.ts","./node_modules/date-fns/hourstominutes.d.ts","./node_modules/date-fns/hourstoseconds.d.ts","./node_modules/date-fns/interval.d.ts","./node_modules/date-fns/intervaltoduration.d.ts","./node_modules/date-fns/intlformat.d.ts","./node_modules/date-fns/intlformatdistance.d.ts","./node_modules/date-fns/isafter.d.ts","./node_modules/date-fns/isbefore.d.ts","./node_modules/date-fns/isdate.d.ts","./node_modules/date-fns/isequal.d.ts","./node_modules/date-fns/isexists.d.ts","./node_modules/date-fns/isfirstdayofmonth.d.ts","./node_modules/date-fns/isfriday.d.ts","./node_modules/date-fns/isfuture.d.ts","./node_modules/date-fns/islastdayofmonth.d.ts","./node_modules/date-fns/isleapyear.d.ts","./node_modules/date-fns/ismatch.d.ts","./node_modules/date-fns/ismonday.d.ts","./node_modules/date-fns/ispast.d.ts","./node_modules/date-fns/issameday.d.ts","./node_modules/date-fns/issamehour.d.ts","./node_modules/date-fns/issameisoweek.d.ts","./node_modules/date-fns/issameisoweekyear.d.ts","./node_modules/date-fns/issameminute.d.ts","./node_modules/date-fns/issamemonth.d.ts","./node_modules/date-fns/issamequarter.d.ts","./node_modules/date-fns/issamesecond.d.ts","./node_modules/date-fns/issameweek.d.ts","./node_modules/date-fns/issameyear.d.ts","./node_modules/date-fns/issaturday.d.ts","./node_modules/date-fns/issunday.d.ts","./node_modules/date-fns/isthishour.d.ts","./node_modules/date-fns/isthisisoweek.d.ts","./node_modules/date-fns/isthisminute.d.ts","./node_modules/date-fns/isthismonth.d.ts","./node_modules/date-fns/isthisquarter.d.ts","./node_modules/date-fns/isthissecond.d.ts","./node_modules/date-fns/isthisweek.d.ts","./node_modules/date-fns/isthisyear.d.ts","./node_modules/date-fns/isthursday.d.ts","./node_modules/date-fns/istoday.d.ts","./node_modules/date-fns/istomorrow.d.ts","./node_modules/date-fns/istuesday.d.ts","./node_modules/date-fns/isvalid.d.ts","./node_modules/date-fns/iswednesday.d.ts","./node_modules/date-fns/isweekend.d.ts","./node_modules/date-fns/iswithininterval.d.ts","./node_modules/date-fns/isyesterday.d.ts","./node_modules/date-fns/lastdayofdecade.d.ts","./node_modules/date-fns/lastdayofisoweek.d.ts","./node_modules/date-fns/lastdayofisoweekyear.d.ts","./node_modules/date-fns/lastdayofmonth.d.ts","./node_modules/date-fns/lastdayofquarter.d.ts","./node_modules/date-fns/lastdayofweek.d.ts","./node_modules/date-fns/lastdayofyear.d.ts","./node_modules/date-fns/_lib/format/lightformatters.d.ts","./node_modules/date-fns/lightformat.d.ts","./node_modules/date-fns/max.d.ts","./node_modules/date-fns/milliseconds.d.ts","./node_modules/date-fns/millisecondstohours.d.ts","./node_modules/date-fns/millisecondstominutes.d.ts","./node_modules/date-fns/millisecondstoseconds.d.ts","./node_modules/date-fns/min.d.ts","./node_modules/date-fns/minutestohours.d.ts","./node_modules/date-fns/minutestomilliseconds.d.ts","./node_modules/date-fns/minutestoseconds.d.ts","./node_modules/date-fns/monthstoquarters.d.ts","./node_modules/date-fns/monthstoyears.d.ts","./node_modules/date-fns/nextday.d.ts","./node_modules/date-fns/nextfriday.d.ts","./node_modules/date-fns/nextmonday.d.ts","./node_modules/date-fns/nextsaturday.d.ts","./node_modules/date-fns/nextsunday.d.ts","./node_modules/date-fns/nextthursday.d.ts","./node_modules/date-fns/nexttuesday.d.ts","./node_modules/date-fns/nextwednesday.d.ts","./node_modules/date-fns/parse/_lib/types.d.ts","./node_modules/date-fns/parse/_lib/setter.d.ts","./node_modules/date-fns/parse/_lib/parser.d.ts","./node_modules/date-fns/parse/_lib/parsers.d.ts","./node_modules/date-fns/parse.d.ts","./node_modules/date-fns/parseiso.d.ts","./node_modules/date-fns/parsejson.d.ts","./node_modules/date-fns/previousday.d.ts","./node_modules/date-fns/previousfriday.d.ts","./node_modules/date-fns/previousmonday.d.ts","./node_modules/date-fns/previoussaturday.d.ts","./node_modules/date-fns/previoussunday.d.ts","./node_modules/date-fns/previousthursday.d.ts","./node_modules/date-fns/previoustuesday.d.ts","./node_modules/date-fns/previouswednesday.d.ts","./node_modules/date-fns/quarterstomonths.d.ts","./node_modules/date-fns/quarterstoyears.d.ts","./node_modules/date-fns/roundtonearesthours.d.ts","./node_modules/date-fns/roundtonearestminutes.d.ts","./node_modules/date-fns/secondstohours.d.ts","./node_modules/date-fns/secondstomilliseconds.d.ts","./node_modules/date-fns/secondstominutes.d.ts","./node_modules/date-fns/set.d.ts","./node_modules/date-fns/setdate.d.ts","./node_modules/date-fns/setday.d.ts","./node_modules/date-fns/setdayofyear.d.ts","./node_modules/date-fns/setdefaultoptions.d.ts","./node_modules/date-fns/sethours.d.ts","./node_modules/date-fns/setisoday.d.ts","./node_modules/date-fns/setisoweek.d.ts","./node_modules/date-fns/setisoweekyear.d.ts","./node_modules/date-fns/setmilliseconds.d.ts","./node_modules/date-fns/setminutes.d.ts","./node_modules/date-fns/setmonth.d.ts","./node_modules/date-fns/setquarter.d.ts","./node_modules/date-fns/setseconds.d.ts","./node_modules/date-fns/setweek.d.ts","./node_modules/date-fns/setweekyear.d.ts","./node_modules/date-fns/setyear.d.ts","./node_modules/date-fns/startofday.d.ts","./node_modules/date-fns/startofdecade.d.ts","./node_modules/date-fns/startofhour.d.ts","./node_modules/date-fns/startofisoweek.d.ts","./node_modules/date-fns/startofisoweekyear.d.ts","./node_modules/date-fns/startofminute.d.ts","./node_modules/date-fns/startofmonth.d.ts","./node_modules/date-fns/startofquarter.d.ts","./node_modules/date-fns/startofsecond.d.ts","./node_modules/date-fns/startoftoday.d.ts","./node_modules/date-fns/startoftomorrow.d.ts","./node_modules/date-fns/startofweek.d.ts","./node_modules/date-fns/startofweekyear.d.ts","./node_modules/date-fns/startofyear.d.ts","./node_modules/date-fns/startofyesterday.d.ts","./node_modules/date-fns/sub.d.ts","./node_modules/date-fns/subbusinessdays.d.ts","./node_modules/date-fns/subdays.d.ts","./node_modules/date-fns/subhours.d.ts","./node_modules/date-fns/subisoweekyears.d.ts","./node_modules/date-fns/submilliseconds.d.ts","./node_modules/date-fns/subminutes.d.ts","./node_modules/date-fns/submonths.d.ts","./node_modules/date-fns/subquarters.d.ts","./node_modules/date-fns/subseconds.d.ts","./node_modules/date-fns/subweeks.d.ts","./node_modules/date-fns/subyears.d.ts","./node_modules/date-fns/todate.d.ts","./node_modules/date-fns/transpose.d.ts","./node_modules/date-fns/weekstodays.d.ts","./node_modules/date-fns/yearstodays.d.ts","./node_modules/date-fns/yearstomonths.d.ts","./node_modules/date-fns/yearstoquarters.d.ts","./node_modules/date-fns/index.d.mts","./src/components/admin/activityfeedmatrix.tsx","./src/components/admin/reconciliationgrid.tsx","./src/app/admin/dashboard/page.tsx","./src/app/admin/expenses/page.tsx","./src/app/admin/login/page.tsx","./src/components/ui/confirmbutton.tsx","./src/app/admin/products/page.tsx","./src/app/admin/purchases/page.tsx","./src/app/admin/reports/page.tsx","./src/app/admin/staff/page.tsx","./src/components/ui/vessellogo.tsx","./src/app/login/page.tsx","./src/app/platform/page.tsx","./src/app/signup/page.tsx","./src/components/terminal/productsizeselector.tsx","./src/components/terminal/quantitycounter.tsx","./src/components/terminal/paymentmethodtoggle.tsx","./src/components/terminal/paymentstatusoverlay.tsx","./src/app/terminal/page.tsx","./.next/types/app/layout.ts","./.next/types/app/admin/dashboard/page.ts","./.next/types/app/api/auth/login/route.ts","./.next/types/app/api/auth/me/route.ts","./.next/types/app/api/auth/refresh/route.ts","./.next/types/app/api/branches/route.ts","./.next/types/app/api/dashboard/reconciliation/route.ts","./.next/types/app/api/dashboard/summary/route.ts","./.next/types/app/api/platform/businesses/route.ts","./.next/types/app/api/transactions/route.ts","./.next/types/app/login/page.ts","./.next/types/app/platform/page.ts","./node_modules/@types/webidl-conversions/index.d.ts","./node_modules/@types/whatwg-url/index.d.ts"],"fileIdsList":[[99,145,360,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,814],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,501],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,503],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,504],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,510],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,511],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,512],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,523],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,529],[99,145,360,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,544],[99,145,360,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,823],[99,145,360,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,824],[99,145,408,409,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,495],[99,142,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,178,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,146,151,156,164,175,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,146,147,156,164,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[94,95,96,99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,148,187,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,149,150,157,165,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,175,183,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,151,153,156,164,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,152,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,153,154,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,155,156,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,156,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,157,158,175,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,157,158,171,175,178,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,153,156,159,164,175,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,157,159,160,164,175,183,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,161,175,183,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[97,98,99,100,101,102,103,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,162,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,163,186,191,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,153,156,164,175,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,165,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,166,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,167,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,169,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,170,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,171,172,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,171,173,187,189,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,175,176,178,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,177,178,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,176,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,178,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,179,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,142,145,175,180,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,181,182,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,181,182,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,164,175,183,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,184,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,164,185,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,170,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,187,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,188,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,163,189,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,190,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,140,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,140,145,156,158,167,175,178,186,189,191,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,192,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,197,198,199,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,197,198,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,91,99,145,196,361,404,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,91,99,145,195,361,404,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[84,85,86,99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,557],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,555,557],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,555],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,557,621,622],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,624],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,625],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,642],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,718],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,557,622,742],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,555,739,740],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,741],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,739],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,555,556],[99,145,186,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,534],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,535,536,537],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,535],[99,145,153,156,164,175,183,437,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466],[99,145,438,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,437,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466],[99,145,439,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,438,439,440,441,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,439,440,441,442,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,444,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,444,445,446,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,156,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466],[99,145,438,439,440,441,442,443,444,445,446,447,449,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,464,466],[99,145,439,440,441,442,443,444,445,446,447,448,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,444,445,446,447,449,450,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,439,440,441,442,443,444,445,446,447,449,450,451,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,455,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,456,457,458,459,460,461,462,463,464,466],[99,145,438,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,457,458,459,460,461,462,463,464,466],[99,145,437,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,458,459,460,461,462,463,464,465,466],[99,145,438,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,459,460,461,462,463,464,466],[99,145,437,438,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,460,461,462,463,464,465,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,466],[92,99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,365,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,367,368,369,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,371,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,212,218,220,361,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,209,211,214,232,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,214,339,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,267,285,300,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,309,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,212,219,253,263,336,337,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,219,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,263,264,265,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,219,253,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,219,220,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,293,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,193,292,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,286,287,288,306,307,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,286,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,276,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,275,277,381,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,286,287,304,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,282,307,393,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,391,392,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,226,390,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,279,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,193,226,242,275,276,277,278,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,304,306,307,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,304,306,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,304,305,307,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,170,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,274,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,193,211,213,270,271,272,273,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,203,384,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,186,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,219,251,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,219,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,249,254,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,250,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,91,99,145,159,193,195,196,361,402,403,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,361,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,201,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,354,355,356,357,358,359,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,356,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,250,286,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,286,362,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,286,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,213,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,210,211,222,240,242,274,279,280,302,304,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,271,274,279,287,289,290,291,293,294,295,296,297,298,299,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,272,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,170,193,211,212,240,242,243,245,270,302,303,307,361,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,213,214,226,227,275,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,212,214,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,175,193,210,213,214,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,170,186,193,210,211,212,213,214,219,222,223,233,234,236,239,240,242,243,244,245,269,270,303,304,312,314,317,319,322,324,325,326,327,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,175,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,203,204,210,211,361,364,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,175,186,193,207,338,340,341,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,170,186,193,207,210,213,230,234,236,237,238,243,270,317,328,330,336,350,351,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,216,270,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,210,212,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,223,318,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,320,321,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,320,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,318,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,320,323,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,206,207,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,206,246,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,206,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,208,223,316,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,315,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,207,208,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,208,313,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,207,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,302,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,210,222,241,261,267,281,284,301,304,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,255,256,257,258,259,260,282,283,307,362,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,311,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,210,222,241,247,308,310,312,361,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,186,193,203,210,212,269,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,266,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,344,349,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,233,242,269,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,332,336,350,353,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,216,336,344,345,353,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,202,212,233,244,347,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,212,219,244,331,332,342,343,346,348,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,194,240,241,242,361,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,170,186,193,208,210,211,213,216,221,222,230,233,234,236,237,238,239,243,245,269,270,314,328,329,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,210,212,216,330,352,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,211,213,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,159,170,193,201,203,210,211,214,222,239,240,242,243,245,311,361,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,170,186,193,205,208,209,213,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,206,268,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,206,211,222,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,212,223,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,226,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,225,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,227,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,224,226,230,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,212,224,226,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,159,193,205,212,213,219,227,228,229,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,304,305,306,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,262,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,203,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,236,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,194,239,242,245,361,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,203,384,385,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,254,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,170,186,193,201,248,250,252,253,364,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,213,219,236,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,235,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,157,159,170,193,201,254,263,361,362,363,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[83,87,88,89,90,99,145,195,196,361,404,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,150,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,333,334,335,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,333,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,373,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,375,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,377,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,379,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,382,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,386,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[91,93,99,145,361,366,370,372,374,376,378,380,383,387,389,395,396,398,405,406,407,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,388,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,394,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,250,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,397,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,144,145,227,228,229,230,399,400,401,404,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,91,99,145,159,161,170,193,195,196,197,199,201,214,353,360,364,404,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,426,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,424,426,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,415,423,424,425,427,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,413,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,416,421,426,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,412,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,416,417,420,421,422,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,416,417,418,420,421,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,413,414,415,416,417,421,422,423,425,426,427,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,411,413,414,415,416,417,418,420,421,422,423,424,425,426,427,428,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,411,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,416,418,419,421,422,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,420,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,421,422,426,429,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,414,424,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,431,432,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,430,433,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,116,145,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,145,175,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,107,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,109,112,145,183,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,164,183,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,107,145,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,109,112,145,164,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,104,105,108,111,145,156,175,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,119,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,104,110,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,133,134,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,108,112,145,178,186,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,133,145,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,106,107,145,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,137,138,139,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,127,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,119,120,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,110,112,120,121,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,111,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,104,107,112,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,112,116,120,121,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,116,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,110,112,115,145,186,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,104,109,112,119,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,175,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,107,112,133,145,191,193,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,492],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,483,484],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,480,481,483,485,486,491],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,481,483],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,491],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,483],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,480,481,483,486,487,488,489,490],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,480,481,482],[99,145,166,436,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,469,470,471,472,473,474,475,476,477],[99,145,166,436,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,468,469,471,477],[87,99,145,389,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541,543,546,547],[87,99,145,389,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541,542,543,546,547,549,550,551,553,554,812,813],[99,145,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[87,99,145,389,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541,543,546,547,817],[87,99,145,389,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541,543,546],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,469,470,477,493,494,497,498,499,500],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,494,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,469,470,476,477,499,500],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,469,494,498,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,468,469,471,476,477,493,494,498,499,507],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,468,469,470,493,499,507,509],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,472,473,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,472,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,470,474,493,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,470,473,493,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,472,517],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,472,499,520],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,470,471,472,493,499,507,520],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,476,477,493,500],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,469,470,476,477,500],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,471,493,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,470,471,475,493,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,472,474,475,499],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,467,471,472,493,499,507],[99,145,408,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,543],[87,99,145,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,532,533,822],[87,99,145,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541],[87,99,145,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541,543,546],[87,99,145,395,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,539,540,541,543,826,827,828,829],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,541,547,811],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,541],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,541,552],[99,145,389,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,532],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,538],[87,99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,533,541],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,469,498],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,493],[99,145,150,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,469,496,497],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,476],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,468],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,497,519],[99,145,405,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,469,499],[99,145,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466,469,470,476,477],[99,145,434,439,440,441,442,443,444,445,446,447,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,466]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"0990a7576222f248f0a3b888adcb7389f957928ce2afb1cd5128169086ff4d29","impliedFormat":1},{"version":"eb5b19b86227ace1d29ea4cf81387279d04bb34051e944bc53df69f58914b788","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"87d9d29dbc745f182683f63187bf3d53fd8673e5fca38ad5eaab69798ed29fbc","impliedFormat":1},{"version":"09ddcfcfbe77a8232d155ca1030005106b1328f6210df43629d0be750da07c16","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc69795d9954ee4ad57545b10c7bf1a7260d990231b1685c147ea71a6faa265c","impliedFormat":1},{"version":"8bc6c94ff4f2af1f4023b7bb2379b08d3d7dd80c698c9f0b07431ea16101f05f","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"57194e1f007f3f2cbef26fa299d4c6b21f4623a2eddc63dfeef79e38e187a36e","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","impliedFormat":1},{"version":"1123a83f35cf56c97de746f0a7250012153c61a167e4a61668bf50e558162d14","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e20d899c28ca26a2a7afc98beaa69e63ff7fba0a8bc47b4e3bf3ede5e09e424","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"085f552d005479e2e6a7311cdbbe5d8c55c497b4d19274285df161ee9684cd9c","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"007faacc9268357caa21d24169f3f3f2497af3e9241308df2d89f6e6d9bb3f2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"8caa5c86be1b793cd5f599e27ecb34252c41e011980f7d61ae4989a149ff6ccc","impliedFormat":1},{"version":"f9fd93190acb1ffe0bc0fb395df979452f8d625071e9ffc8636e4dfb86ab2508","impliedFormat":1},{"version":"5f41fd8732a89e940c58ce22206e3df85745feb8983e2b4c6257fb8cbb118493","impliedFormat":1},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1},{"version":"1cfa8647d7d71cb03847d616bd79320abfc01ddea082a49569fda71ac5ece66b","impliedFormat":1},{"version":"bb7a61dd55dc4b9422d13da3a6bb9cc5e89be888ef23bbcf6558aa9726b89a1c","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"cfe4ef4710c3786b6e23dae7c086c70b4f4835a2e4d77b75d39f9046106e83d3","impliedFormat":1},{"version":"cbea99888785d49bb630dcbb1613c73727f2b5a2cf02e1abcaab7bcf8d6bf3c5","impliedFormat":1},{"version":"3a8bddb66b659f6bd2ff641fc71df8a8165bafe0f4b799cc298be5cd3755bb20","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"2dad084c67e649f0f354739ec7df7c7df0779a28a4f55c97c6b6883ae850d1ce","impliedFormat":1},{"version":"fa5bbc7ab4130dd8cdc55ea294ec39f76f2bc507a0f75f4f873e38631a836ca7","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"cf86de1054b843e484a3c9300d62fbc8c97e77f168bbffb131d560ca0474d4a8","impliedFormat":1},{"version":"196c960b12253fde69b204aa4fbf69470b26daf7a430855d7f94107a16495ab0","impliedFormat":1},{"version":"ee15ea5dd7a9fc9f5013832e5843031817a880bf0f24f37a29fd8337981aae07","impliedFormat":1},{"version":"bf24f6d35f7318e246010ffe9924395893c4e96d34324cde77151a73f078b9ad","impliedFormat":1},{"version":"ea53732769832d0f127ae16620bd5345991d26bf0b74e85e41b61b27d74ea90f","impliedFormat":1},{"version":"10595c7ff5094dd5b6a959ccb1c00e6a06441b4e10a87bc09c15f23755d34439","impliedFormat":1},{"version":"9620c1ff645afb4a9ab4044c85c26676f0a93e8c0e4b593aea03a89ccb47b6d0","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"a9af0e608929aaf9ce96bd7a7b99c9360636c31d73670e4af09a09950df97841","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"08ed0b3f0166787f84a6606f80aa3b1388c7518d78912571b203817406e471da","impliedFormat":1},{"version":"47e5af2a841356a961f815e7c55d72554db0c11b4cba4d0caab91f8717846a94","impliedFormat":1},{"version":"65f43099ded6073336e697512d9b80f2d4fec3182b7b2316abf712e84104db00","impliedFormat":1},{"version":"f5f541902bf7ae0512a177295de9b6bcd6809ea38307a2c0a18bfca72212f368","impliedFormat":1},{"version":"b0decf4b6da3ebc52ea0c96095bdfaa8503acc4ac8e9081c5f2b0824835dd3bd","impliedFormat":1},{"version":"ca1b882a105a1972f82cc58e3be491e7d750a1eb074ffd13b198269f57ed9e1b","impliedFormat":1},{"version":"fc3e1c87b39e5ba1142f27ec089d1966da168c04a859a4f6aab64dceae162c2b","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"61888522cec948102eba94d831c873200aa97d00d8989fdfd2a3e0ee75ec65a2","impliedFormat":1},{"version":"4e10622f89fea7b05dd9b52fb65e1e2b5cbd96d4cca3d9e1a60bb7f8a9cb86a1","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"59bf32919de37809e101acffc120596a9e45fdbab1a99de5087f31fdc36e2f11","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"faa03dffb64286e8304a2ca96dd1317a77db6bfc7b3fb385163648f67e535d77","impliedFormat":1},{"version":"c40c848daad198266370c1c72a7a8c3d18d2f50727c7859fcfefd3ff69a7f288","impliedFormat":1},{"version":"ac60bbee0d4235643cc52b57768b22de8c257c12bd8c2039860540cab1fa1d82","impliedFormat":1},{"version":"6428e6edd944ce6789afdf43f9376c1f2e4957eea34166177625aaff4c0da1a0","impliedFormat":1},{"version":"ada39cbb2748ab2873b7835c90c8d4620723aedf323550e8489f08220e477c7f","impliedFormat":1},{"version":"6e5f5cee603d67ee1ba6120815497909b73399842254fc1e77a0d5cdc51d8c9c","impliedFormat":1},{"version":"8dba67056cbb27628e9b9a1cba8e57036d359dceded0725c72a3abe4b6c79cd4","impliedFormat":1},{"version":"70f3814c457f54a7efe2d9ce9d2686de9250bb42eb7f4c539bd2280a42e52d33","impliedFormat":1},{"version":"154dd2e22e1e94d5bc4ff7726706bc0483760bae40506bdce780734f11f7ec47","impliedFormat":1},{"version":"ef61792acbfa8c27c9bd113f02731e66229f7d3a169e3c1993b508134f1a58e0","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"0131e203d8560edb39678abe10db42564a068f98c4ebd1ed9ffe7279c78b3c81","impliedFormat":1},{"version":"f6404e7837b96da3ea4d38c4f1a3812c96c9dcdf264e93d5bdb199f983a3ef4b","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"8b8f00491431fe82f060dfe8c7f2180a9fb239f3d851527db909b83230e75882","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","affectsGlobalScope":true,"impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"903e299a28282fa7b714586e28409ed73c3b63f5365519776bf78e8cf173db36","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"dd3900b24a6a8745efeb7ad27629c0f8a626470ac229c1d73f1fe29d67e44dca","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ec29be0737d39268696edcec4f5e97ce26f449fa9b7afc2f0f99a86def34a418","impliedFormat":1},{"version":"aeab39e8e0b1a3b250434c3b2bb8f4d17bbec2a9dbce5f77e8a83569d3d2cbc2","impliedFormat":1},{"version":"ec6cba1c02c675e4dd173251b156792e8d3b0c816af6d6ad93f1a55d674591aa","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"d729408dfde75b451530bcae944cf89ee8277e2a9df04d1f62f2abfd8b03c1e1","impliedFormat":1},{"version":"e15d3c84d5077bb4a3adee4c791022967b764dc41cb8fa3cfa44d4379b2c95f5","impliedFormat":1},{"version":"5f58e28cd22e8fc1ac1b3bc6b431869f1e7d0b39e2c21fbf79b9fa5195a85980","impliedFormat":1},{"version":"e1fc1a1045db5aa09366be2b330e4ce391550041fc3e925f60998ca0b647aa97","impliedFormat":1},{"version":"63533978dcda286422670f6e184ac516805a365fb37a086eeff4309e812f1402","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"31fb49ef3aa3d76f0beb644984e01eab0ea222372ea9b49bb6533be5722d756c","impliedFormat":1},{"version":"33cd131e1461157e3e06b06916b5176e7a8ec3fce15a5cfe145e56de744e07d2","impliedFormat":1},{"version":"889ef863f90f4917221703781d9723278db4122d75596b01c429f7c363562b86","impliedFormat":1},{"version":"3556cfbab7b43da96d15a442ddbb970e1f2fc97876d055b6555d86d7ac57dae5","impliedFormat":1},{"version":"437751e0352c6e924ddf30e90849f1d9eb00ca78c94d58d6a37202ec84eb8393","impliedFormat":1},{"version":"48e8af7fdb2677a44522fd185d8c87deff4d36ee701ea003c6c780b1407a1397","impliedFormat":1},{"version":"d11308de5a36c7015bb73adb5ad1c1bdaac2baede4cc831a05cf85efa3cc7f2f","impliedFormat":1},{"version":"38e4684c22ed9319beda6765bab332c724103d3a966c2e5e1c5a49cf7007845f","impliedFormat":1},{"version":"f9812cfc220ecf7557183379531fa409acd249b9e5b9a145d0d52b76c20862de","affectsGlobalScope":true,"impliedFormat":1},{"version":"e650298721abc4f6ae851e60ae93ee8199791ceec4b544c3379862f81f43178c","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"680793958f6a70a44c8d9ae7d46b7a385361c69ac29dcab3ed761edce1c14ab8","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"b838d4c72740eb0afd284bf7575b74c624b105eff2e8c7b4aeead57e7ac320ff","impliedFormat":1},{"version":"913ddbba170240070bd5921b8f33ea780021bdf42fbdfcd4fcb2691b1884ddde","impliedFormat":1},{"version":"b4e6d416466999ff40d3fe5ceb95f7a8bfb7ac2262580287ac1a8391e5362431","impliedFormat":1},{"version":"5fe23bd829e6be57d41929ac374ee9551ccc3c44cee893167b7b5b77be708014","impliedFormat":1},{"version":"0a626484617019fcfbfc3c1bc1f9e84e2913f1adb73692aa9075817404fb41a1","impliedFormat":1},{"version":"438c7513b1df91dcef49b13cd7a1c4720f91a36e88c1df731661608b7c055f10","impliedFormat":1},{"version":"cf185cc4a9a6d397f416dd28cca95c227b29f0f27b160060a95c0e5e36cda865","impliedFormat":1},{"version":"0086f3e4ad898fd7ca56bb223098acfacf3fa065595182aaf0f6c4a6a95e6fbd","impliedFormat":1},{"version":"efaa078e392f9abda3ee8ade3f3762ab77f9c50b184e6883063a911742a4c96a","impliedFormat":1},{"version":"54a8bb487e1dc04591a280e7a673cdfb272c83f61e28d8a64cf1ac2e63c35c51","impliedFormat":1},{"version":"021a9498000497497fd693dd315325484c58a71b5929e2bbb91f419b04b24cea","impliedFormat":1},{"version":"9385cdc09850950bc9b59cca445a3ceb6fcca32b54e7b626e746912e489e535e","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"84124384abae2f6f66b7fbfc03862d0c2c0b71b826f7dbf42c8085d31f1d3f95","impliedFormat":1},{"version":"63a8e96f65a22604eae82737e409d1536e69a467bb738bec505f4f97cce9d878","impliedFormat":1},{"version":"3fd78152a7031315478f159c6a5872c712ece6f01212c78ea82aef21cb0726e2","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"58b49e5c1def740360b5ae22ae2405cfac295fee74abd88d74ac4ea42502dc03","impliedFormat":1},{"version":"512fc15cca3a35b8dbbf6e23fe9d07e6f87ad03c895acffd3087ce09f352aad0","impliedFormat":1},{"version":"9a0946d15a005832e432ea0cd4da71b57797efb25b755cc07f32274296d62355","impliedFormat":1},{"version":"a52ff6c0a149e9f370372fc3c715d7f2beee1f3bab7980e271a7ab7d313ec677","impliedFormat":1},{"version":"fd933f824347f9edd919618a76cdb6a0c0085c538115d9a287fa0c7f59957ab3","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"6a1aa3e55bdc50503956c5cd09ae4cd72e3072692d742816f65c66ca14f4dfdd","impliedFormat":1},{"version":"ab75cfd9c4f93ffd601f7ca1753d6a9d953bbedfbd7a5b3f0436ac8a1de60dfa","impliedFormat":1},{"version":"f95180f03d827525ca4f990f49e17ec67198c316dd000afbe564655141f725cd","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"1364f64d2fb03bbb514edc42224abd576c064f89be6a990136774ecdd881a1da","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"950fb67a59be4c2dbe69a5786292e60a5cb0e8612e0e223537784c731af55db1","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"07ca44e8d8288e69afdec7a31fa408ce6ab90d4f3d620006701d5544646da6aa","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"4e4475fba4ed93a72f167b061cd94a2e171b82695c56de9899275e880e06ba41","impliedFormat":1},{"version":"97c5f5d580ab2e4decd0a3135204050f9b97cd7908c5a8fbc041eadede79b2fa","impliedFormat":1},{"version":"c99a3a5f2215d5b9d735aa04cec6e61ed079d8c0263248e298ffe4604d4d0624","impliedFormat":1},{"version":"49b2375c586882c3ac7f57eba86680ff9742a8d8cb2fe25fe54d1b9673690d41","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"847e160d709c74cc714fbe1f99c41d3425b74cd47b1be133df1623cd87014089","impliedFormat":1},{"version":"9fee04f1e1afa50524862289b9f0b0fdc3735b80e2a0d684cec3b9ff3d94cecc","impliedFormat":1},{"version":"5cdc27fbc5c166fc5c763a30ac21cbac9859dc5ba795d3230db6d4e52a1965bb","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"f416c9c3eee9d47ff49132c34f96b9180e50485d435d5748f0e8b72521d28d2e","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"14e5cdec6f8ae82dfd0694e64903a0a54abdfe37e1d966de3d4128362acbf35f","impliedFormat":1},{"version":"bbc183d2d69f4b59fd4dd8799ffdf4eb91173d1c4ad71cce91a3811c021bf80c","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"8dbc4134a4b3623fc476be5f36de35c40f2768e2e3d9ed437e0d5f1c4cd850f6","impliedFormat":1},{"version":"4e06330a84dec7287f7ebdd64978f41a9f70a668d3b5edc69d5d4a50b9b376bb","impliedFormat":1},{"version":"65bfa72967fbe9fc33353e1ac03f0480aa2e2ea346d61ff3ea997dfd850f641a","impliedFormat":1},{"version":"c06f0bb92d1a1a5a6c6e4b5389a5664d96d09c31673296cb7da5fe945d54d786","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"872caaa31423f4345983d643e4649fb30f548e9883a334d6d1c5fff68ede22d4","impliedFormat":1},{"version":"94404c4a878fe291e7578a2a80264c6f18e9f1933fbb57e48f0eb368672e389c","impliedFormat":1},{"version":"5c1b7f03aa88be854bc15810bfd5bd5a1943c5a7620e1c53eddd2a013996343e","impliedFormat":1},{"version":"09dfc64fcd6a2785867f2368419859a6cc5a8d4e73cbe2538f205b1642eb0f51","impliedFormat":1},{"version":"bcf6f0a323653e72199105a9316d91463ad4744c546d1271310818b8cef7c608","impliedFormat":1},{"version":"01aa917531e116485beca44a14970834687b857757159769c16b228eb1e49c5f","impliedFormat":1},{"version":"351475f9c874c62f9b45b1f0dc7e2704e80dfd5f1af83a3a9f841f9dfe5b2912","impliedFormat":1},{"version":"ac457ad39e531b7649e7b40ee5847606eac64e236efd76c5d12db95bf4eacd17","impliedFormat":1},{"version":"187a6fdbdecb972510b7555f3caacb44b58415da8d5825d03a583c4b73fde4cf","impliedFormat":1},{"version":"d4c3250105a612202289b3a266bb7e323db144f6b9414f9dea85c531c098b811","impliedFormat":1},{"version":"95b444b8c311f2084f0fb51c616163f950fb2e35f4eaa07878f313a2d36c98a4","impliedFormat":1},{"version":"741067675daa6d4334a2dc80a4452ca3850e89d5852e330db7cb2b5f867173b1","impliedFormat":1},{"version":"f8acecec1114f11690956e007d920044799aefeb3cece9e7f4b1f8a1d542b2c9","impliedFormat":1},{"version":"178071ccd043967a58c5d1a032db0ddf9bd139e7920766b537d9783e88eb615e","impliedFormat":1},{"version":"3a17f09634c50cce884721f54fd9e7b98e03ac505889c560876291fcf8a09e90","impliedFormat":1},{"version":"32531dfbb0cdc4525296648f53b2b5c39b64282791e2a8c765712e49e6461046","impliedFormat":1},{"version":"0ce1b2237c1c3df49748d61568160d780d7b26693bd9feb3acb0744a152cd86d","impliedFormat":1},{"version":"e489985388e2c71d3542612685b4a7db326922b57ac880f299da7026a4e8a117","impliedFormat":1},{"version":"5cad4158616d7793296dd41e22e1257440910ea8d01c7b75045d4dfb20c5a41a","impliedFormat":1},{"version":"04d3aad777b6af5bd000bfc409907a159fe77e190b9d368da4ba649cdc28d39e","affectsGlobalScope":true,"impliedFormat":1},{"version":"74efc1d6523bd57eb159c18d805db4ead810626bc5bc7002a2c7f483044b2e0f","impliedFormat":1},{"version":"19252079538942a69be1645e153f7dbbc1ef56b4f983c633bf31fe26aeac32cd","impliedFormat":1},{"version":"bc11f3ac00ac060462597add171220aed628c393f2782ac75dd29ff1e0db871c","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"3b0b1d352b8d2e47f1c4df4fb0678702aee071155b12ef0185fce9eb4fa4af1e","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"a344403e7a7384e0e7093942533d309194ad0a53eca2a3100c0b0ab4d3932773","impliedFormat":1},{"version":"b7fff2d004c5879cae335db8f954eb1d61242d9f2d28515e67902032723caeab","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"bb18bf4a61a17b4a6199eb3938ecfa4a59eb7c40843ad4a82b975ab6f7e3d925","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"e9b6fc05f536dfddcdc65dbcf04e09391b1c968ab967382e48924f5cb90d88e1","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"2b664c3cc544d0e35276e1fb2d4989f7d4b4027ffc64da34ec83a6ccf2e5c528","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"3cd8f0464e0939b47bfccbb9bb474a6d87d57210e304029cd8eb59c63a81935d","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"3026abd48e5e312f2328629ede6e0f770d21c3cd32cee705c450e589d015ee09","impliedFormat":1},{"version":"8b140b398a6afbd17cc97c38aea5274b2f7f39b1ae5b62952cfe65bf493e3e75","impliedFormat":1},{"version":"7663d2c19ce5ef8288c790edba3d45af54e58c84f1b37b1249f6d49d962f3d91","impliedFormat":1},{"version":"5cce3b975cdb72b57ae7de745b3c5de5790781ee88bcb41ba142f07c0fa02e97","impliedFormat":1},{"version":"00bd6ebe607246b45296aa2b805bd6a58c859acecda154bfa91f5334d7c175c6","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"0d28b974a7605c4eda20c943b3fa9ae16cb452c1666fc9b8c341b879992c7612","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"87ac2fb61e629e777f4d161dff534c2023ee15afd9cb3b1589b9b1f014e75c58","impliedFormat":1},{"version":"13c8b4348db91e2f7d694adc17e7438e6776bc506d5c8f5de9ad9989707fa3fe","impliedFormat":1},{"version":"3c1051617aa50b38e9efaabce25e10a5dd9b1f42e372ef0e8a674076a68742ed","impliedFormat":1},{"version":"07a3e20cdcb0f1182f452c0410606711fbea922ca76929a41aacb01104bc0d27","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"4cd4b6b1279e9d744a3825cbd7757bbefe7f0708f3f1069179ad535f19e8ed2c","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"c0eeaaa67c85c3bb6c52b629ebbfd3b2292dc67e8c0ffda2fc6cd2f78dc471e6","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"b95a6f019095dd1d48fd04965b50dfd63e5743a6e75478343c46d2582a5132bf","impliedFormat":99},{"version":"c2008605e78208cfa9cd70bd29856b72dda7ad89df5dc895920f8e10bcb9cd0a","impliedFormat":99},{"version":"b97cb5616d2ab82a98ec9ada7b9e9cabb1f5da880ec50ea2b8dc5baa4cbf3c16","impliedFormat":99},{"version":"d23df9ff06ae8bf1dcb7cc933e97ae7da418ac77749fecee758bb43a8d69f840","affectsGlobalScope":true,"impliedFormat":1},{"version":"040c71dde2c406f869ad2f41e8d4ce579cc60c8dbe5aa0dd8962ac943b846572","affectsGlobalScope":true,"impliedFormat":1},{"version":"3586f5ea3cc27083a17bd5c9059ede9421d587286d5a47f4341a4c2d00e4fa91","impliedFormat":1},{"version":"a6df929821e62f4719551f7955b9f42c0cd53c1370aec2dd322e24196a7dfe33","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},"9dd9d642cdb87d4d5b3173217e0c45429b3e47a6f5cf5fb0ead6c644ec5fed01",{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"52dcc257df5119fb66d864625112ce5033ac51a4c2afe376a0b299d2f7f76e4a","impliedFormat":1},{"version":"e5bab5f871ef708d52d47b3e5d0aa72a08ee7a152f33931d9a60809711a2a9a3","impliedFormat":1},{"version":"e16dc2a81595736024a206c7d5c8a39bfe2e6039208ef29981d0d95434ba8fcf","impliedFormat":1},{"version":"38cb107048cd8ba54a70014ef9a30cf57bee0d9f10a0ca4cefa974056e1ee460","impliedFormat":1},{"version":"19ee8416e6473ed6c7adb868fa796b5653cf0fa2a337658e677eaa0d134388c3","impliedFormat":1},{"version":"1328ab4e442614b28cdb3d4b414cf68325c0da0dca07287a338d0654b7a00261","impliedFormat":1},{"version":"a039dc21f045919f3cbee2ec13812cc6cc3eebc99dae4be00973230f468d19a6","impliedFormat":1},{"version":"3fbe57af01460e49dcd29df55d6931e1672bc6f1be0fb073d11410bc16f9037d","impliedFormat":1},{"version":"f760be449e8562ec5c09bb5187e8e1eabf3c113c0c58cddda53ef8c69f3e2131","impliedFormat":1},{"version":"44325ed13294fce6ab825b82947bbeed2611db7dad9d9135260192f375e5a189","impliedFormat":1},{"version":"e392e8fb5b514eafc585601c1d781485aa6dd6a320e75daf1064a4c6918a1b45","impliedFormat":1},{"version":"46e4a36e8ddbdfb4e7330e11c81c970dc8b218611df9183d39c41c5f8c653b55","impliedFormat":1},{"version":"3cc8a3d123b6b232d48d34b51b785f9da8d193f5b5817fa521fcd2f3b9315c55","impliedFormat":1},{"version":"6332f565867cf4a740a70e30f31cefba37ef7cebcf74f22eab8d744fde6d193e","impliedFormat":1},{"version":"9a195d8476f48523446ece812e5450b5b1ec8c3b6abf99efb8ee2479524f6f56","impliedFormat":1},{"version":"17f2922d41ddd032830a91371c948cd9ce903b35c95adca72271a54584f19b0b","impliedFormat":1},{"version":"3eed76ede2a1a14d7c9bb0a642041282dcc264811139d3dd275c9fe14efc9840","impliedFormat":1},{"version":"354a7f8e1287d9d6b7561bc97fdd8cbc2f7c1dd79e4cb37b942e8a5cfaff1085","impliedFormat":1},{"version":"8d369483f0c2b9ee388129cfdb6a43bc8112b377e86a41884bd06e19ce04f4c1","impliedFormat":99},{"version":"b558c9a18ea4e6e4157124465c3ef1063e64640da139e67be5edb22f534f2f08","impliedFormat":1},{"version":"01374379f82be05d25c08d2f30779fa4a4c41895a18b93b33f14aeef51768692","impliedFormat":1},{"version":"b0dee183d4e65cf938242efaf3d833c6b645afb35039d058496965014f158141","impliedFormat":1},{"version":"c0bbbf84d3fbd85dd60d040c81e8964cc00e38124a52e9c5dcdedf45fea3f213","impliedFormat":1},"79fbdf1919fea4932858cca6c5f67ac18834b75e80a9ac9a0a8391548ebd1f22",{"version":"0c5f112b6d3377b9e8214d8920e1a69d8098b881d941f2ab3ca45234d13d68de","impliedFormat":1},{"version":"359e7188a3ad226e902c43443a45f17bd53bf279596aece7761dc72ffa22b30d","impliedFormat":1},{"version":"aa50d0691c396fb3677d7240e8fb0b842ebf7e113a14ef092833717e3cb2f7fa","impliedFormat":1},{"version":"5585e4ba561c8a827c2ad10b56135cac1aaf9aa84bfe3e9389ed8a84c439461f","impliedFormat":1},{"version":"0339d33fe49fbc1c70842c886195e01eafd37f7431dd7f32209dd0544c289474","impliedFormat":1},{"version":"cf70b9a6eab897a0168ef9d31ca13a9b8b69fe7f9da2c251528c076eea9c2db1","impliedFormat":1},{"version":"e308de1b989eb709570fdf26d45bb01f0031d8809273206a1d6fd53570e8dbac","impliedFormat":1},{"version":"13a4d931c625360ab1cbf68961b13a60969a17cf3247bd60e18a49fb498b68e5","impliedFormat":1},{"version":"55863858e28f768266adad3a19db6da5bbb5a057b07ba1b7cce099cf3f576df5","impliedFormat":1},{"version":"1201dba1a374e877db58ee8f5a208c68852ec2e152a0e8940950933d22cc5399","affectsGlobalScope":true,"impliedFormat":1},{"version":"89cbb41c032a8602412a55d89c9fbee8af199ffb3e89e52a0306d42518f491c3","impliedFormat":1},{"version":"3b251e4edc903f60ab560be43d72840f58a5bb6f6b297a78147436b6dba0bf51","impliedFormat":1},{"version":"021fbcae20ddc7ca7bf04cdb02a8c51f0d96afdde6a8462fb73b09ab4136ff7a","impliedFormat":1},{"version":"adaf4b35134a87afc9b749fb8a52ad062983e2460f9634c2638828b00c00c768","impliedFormat":1},{"version":"8443bbb1e167b4cca6d192eab6f9ab94442054f9b1c945f05070c23896396365","impliedFormat":1},{"version":"e345d3575db86233616b0b5e217149629e2b12c07526607b54ea4c18e85bb041","impliedFormat":1},{"version":"bbe98bf29952b80a91789cc6a3a3727aa958e652f32b145740229fe4b02f2a0a","impliedFormat":1},{"version":"134aa737ada947d36f2455992423d4cbd092c3cf325e52250c98ba9c8a8654df","impliedFormat":1},{"version":"3016511eadb560b6874050f8ff2ca671c64a663a48c60a24e3e7ddef92c3b095","impliedFormat":1},{"version":"542bc2aca628050c8b6b44abfbaae74f5c86de3eeb54718266456f58fc4152fb","impliedFormat":1},{"version":"1237f5aa64d4d5b9a261c07cf85678a60f6528378d9e91bc5a9abf4c31ac9b6f","impliedFormat":1},{"version":"b614199714e24dce517772560eadbe4cc829a7a4572c67aa0360d6b81f31a8b4","impliedFormat":1},{"version":"861b3b1cea0c4dbfd58cd3cb7a630ea8270b4ce92091941c263f4b4c6c21119b","impliedFormat":1},{"version":"8d35820323a2758d61684679eddc3f1d0cc051c55258b3243aee14b6b8e285c1","impliedFormat":1},{"version":"000876a9f6a3a17b1c7014047366cd2c7faa9c4849aae5a835b5f4c314ae5bc5","impliedFormat":1},{"version":"da440f879ec47f7113408fb75f239f437b9ee812fba67562c499f10ef012464a","impliedFormat":1},{"version":"ea75bec6e4b171bef2ea4378035c583803119f0c9caa626ff8ed3e60146a9daa","impliedFormat":1},{"version":"09bfb8631546d864b87078bcfd7099ba4bbd9dc106913605816f179aa4d6e28c","impliedFormat":1},{"version":"06b589495ccb33638b95551972542efef8658639a851c9832505641160b4356f","impliedFormat":1},{"version":"448ae408883377930fb80d69635f949f3425c0f32c49c5656c73f8a6ae90d702","impliedFormat":1},{"version":"46b659d0bf6a2389297cc2acf6fd430fdb379b897848656070cfb9d02d20524a","affectsGlobalScope":true,"impliedFormat":1},{"version":"bd100e695e8e49d997bd9e7102c885886c0a5c52f665955c03eb95aafa9a16f5","affectsGlobalScope":true},{"version":"a3d3f704c5339a36da3ca8c62b29072f87e86c783b8452d235992142ec71aa2d","impliedFormat":1},{"version":"ffa4095694b576198c7b79644d4cfe6111d2351904c8a4ea9ca0ae42777220f9","signature":"56ff06f5106d466dedfd264f1cf4956d3a810fb9e0fc06f5ac5d5457ab8fd36b"},{"version":"9f216d222c1479427caf29c88adfbac45e9f90efb50d2cf182833261f33ec958","signature":"20a815fad85873c9e0db1362408807056e3a4611999b2e0460fa5f522c419e21"},{"version":"f074bd70661d2b71370a39ca2f778b8cfe052aa53de33c2ed6384af7bc197d6f","signature":"3938fa209f8eacc4c61d22bd1b329e3edb630f4b8146d14aacfa12673919e595"},{"version":"17fe7abec9ac3b0490900713de3696725c172e42d40e0e9e5445dc2c5498bdb0","signature":"4bf2e9adffd2f8614ee9021d918e9a96a46d67c9976b6e4bc38992753ee0968c"},{"version":"a3be6116f7b2e96c4f95f9c70ada4d50b26dd4a7794d9a1afc4641211bb95f5a","signature":"b1fcb19dd3f00992e1c3c6d776184d83201451ed652ff76633406edb314de306"},{"version":"4f59c5aa22fb0779fae97a5cb9b6968b1503671d861934e7ce7b904b37185f09","signature":"ef835d7074644072fb6dde9465c404d7bde0c246bc9feff6eeaf258787664b78"},{"version":"28416c790a507d8758fc08666456984783edb02bfefc0a0a6959196c80485952","signature":"11f6206eda142fcf42a3605ed41c4580e7621a736371975cbb3624705c03eca6"},{"version":"7b2d040743c0dd4d66257a3edb657a7ed59db0106911e15d2cfe61f76191b1a1","signature":"c51626cb8b003111d35cab3c107694c5d14a3e3143a395588d43e24df41b1779"},{"version":"9827ad90f9c803a06fbe95b705c0dbf3685d89122562591497be9c23afc3f3cf","signature":"1af8e437be0ef8fd1a4ccc381c766e586f2f6d0149d1f3a174d3f39ff378fae1"},{"version":"418140221ddc50fbb39d75972a11a17dd628d3df03912afbc79baf357549e7ec","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},"f7cd21d469cf01664ba7be0711d9ea2906f881786a2e71358f5def31418c2483",{"version":"d3cfde44f8089768ebb08098c96d01ca260b88bccf238d55eee93f1c620ff5a5","impliedFormat":1},{"version":"293eadad9dead44c6fd1db6de552663c33f215c55a1bfa2802a1bceed88ff0ec","impliedFormat":1},{"version":"833e92c058d033cde3f29a6c7603f517001d1ddd8020bc94d2067a3bc69b2a8e","impliedFormat":1},{"version":"08b2fae7b0f553ad9f79faec864b179fc58bc172e295a70943e8585dd85f600c","impliedFormat":1},{"version":"f12edf1672a94c578eca32216839604f1e1c16b40a1896198deabf99c882b340","impliedFormat":1},{"version":"e3498cf5e428e6c6b9e97bd88736f26d6cf147dedbfa5a8ad3ed8e05e059af8a","impliedFormat":1},{"version":"dba3f34531fd9b1b6e072928b6f885aa4d28dd6789cbd0e93563d43f4b62da53","impliedFormat":1},{"version":"f672c876c1a04a223cf2023b3d91e8a52bb1544c576b81bf64a8fec82be9969c","impliedFormat":1},{"version":"e4b03ddcf8563b1c0aee782a185286ed85a255ce8a30df8453aade2188bbc904","impliedFormat":1},{"version":"2329d90062487e1eaca87b5e06abcbbeeecf80a82f65f949fd332cfcf824b87b","impliedFormat":1},{"version":"25b3f581e12ede11e5739f57a86e8668fbc0124f6649506def306cad2c59d262","impliedFormat":1},{"version":"4fdb529707247a1a917a4626bfb6a293d52cd8ee57ccf03830ec91d39d606d6d","impliedFormat":1},{"version":"a9ebb67d6bbead6044b43714b50dcb77b8f7541ffe803046fdec1714c1eba206","impliedFormat":1},{"version":"5780b706cece027f0d4444fbb4e1af62dc51e19da7c3d3719f67b22b033859b9","impliedFormat":1},{"version":"289fa71217a224c457ff1e2b690d5c2c60a450ba599c88321509978ab05c81c5","signature":"0a35385b1921b3a63357dfd1d13ef8d67592391d0ec3f6c024d062d66a1df553"},{"version":"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","impliedFormat":1},{"version":"95da3c365e3d45709ad6e0b4daa5cdaf05e9076ba3c201e8f8081dd282c02f57","impliedFormat":1},"7f4b01c22920d2e89d74f7c11bbff9d155f661d9d553d27b1f8c2785bdd5892a",{"version":"085bb2d52064e32d057de1f57cf47840817ac4bc233038e1d06b25f7326c9e80","signature":"392a9cbc27c3a5844fc0add6a75ab66f03d88cbfa11dfeffc6b26709ced694a3"},"60e557a572d68282806c270ca3faee51ccd939ef8b1215edfbd532289f560b82",{"version":"764fa3dff5600c8994bd0d21c2dd72ef1bb756c9416f0fdda0f23f5ee25530fe","signature":"b2b05808ff4216ffe44db17634310cf81af753f0965710bc59334308c3925af4"},{"version":"3b36130b713fe846be3b272e26f3d05e51f3c1575620ef128167f2cfc5aee53e","signature":"a30a6893e8bbc071505ca13314ef9c3d496f7ddacc6ac57d506aa61c7f426647"},"05c2ec3b1b5536f9faf8f51c0ccfbf7e10308f1d1a94345ce08e9de65d08ff87",{"version":"d18bf4ed05f991e9366cffe3e809271c8c6cde78edbb5ce3b56a0a8ede75528d","signature":"64c7d3822f5741b41a3fc57fc147c9da1c5e489e7936a3cd2127497e75a001eb"},{"version":"8f6103c07624657b42ed9b01532ec824601baf6737f25e4d2a04f40972efee49","signature":"31444dac517ea0dd2859a0d4c051f567a8b3dda10e06eb1c800e0d41c17aa466"},"9fa627855848ea0bceea10d2481c05424fda60272dc93c8c3b61010861615219","2deb2183a366676a947907aa59bf4bd8bedea936115fb5a0b38dc055f1574e4f","931fdd288d1b1763e65debf2535d3269de6f91868e4bd7ef09a5d5c20cc28b1e",{"version":"06463d398ca86be6f18e4ed50e3e41a38876af38c98df909acfdcb8f5659e8a0","signature":"8d9fe77bdddca0bbd1870066aecc57771eac36879bb0c53d6b9c381e7539636d"},{"version":"ee61bf2972194e8f49bbae6287f89250f8ffdf7d4ebfd08e57df530133b649d1","signature":"3a37f1b4190910fe8b7088def6b1f86f24b6ca91648861195957afffd27e9272"},{"version":"b4f62d47f676d3f81bd1bbe3d9f5e46b57b56b56531b7ae07c53b83aacdadaa1","signature":"0dec5ab439dd8e9467ee79202d6e703341ed777042f08da85ff6b0035e43b393"},{"version":"f2aab42313544de6ed98af37580f935a2ffd5f0109bd4667cc072e98fb772c78","signature":"fd9fb16f26e5e18912548f363b1c34147ee67ded672457b857034d052899d426"},{"version":"c10c44bea9ee4f4a923300f656a9856d56a08e165318669aa038cfb11254a84f","signature":"c53574228fd5e2c4a773248bc8ec18e4e3bd7e5b12219b4c952326c731d4ffb0"},{"version":"2ee58a8d959f35c06eb20d418697fbcea592da6b8d37c189ea61c61c566c1643","signature":"0599cdd5f5d812c23c9ab657da0ff9ec1121d2fe18b382a1e59a46fb54d76e79"},"bed9d5b536a6f9db469dd48969cd4a126f33ef5bb8686a07d99049fcbb4669b8",{"version":"b7a59a9238a1d0934dfdb1c352bffd918d52900fd703a46c3b167d9e8d6def59","signature":"7a048a1217c301bd0e790e2db2cd55ab1ffbf0bfc59bdb94842358543f1173c3"},{"version":"d5ad17ee560d1ab05a2b273019d6284cc4075e162833b651c231eed30f40b6d2","signature":"7a048a1217c301bd0e790e2db2cd55ab1ffbf0bfc59bdb94842358543f1173c3"},{"version":"0f8b9cb7b7f9bd4812565b11a9da79b036b093a8977856f16f6112ce60c224db","signature":"f829b58b3574acba3c72603b2e7e84e6e223add472f465cc1a3c4bb9dd981e3a"},"db750ace38033ca24c41711725dad2eb2cd76bedf5c3ed1934ffbb1fafd8450b",{"version":"2368a31d44ccc59758e3b3c682fee74e820b08fad98623905a85092018c06e3b","impliedFormat":99},"9afa558d52ed1451d6a82b6629afbb2c6dd0f78959ca6e23ba4ab58291266a65",{"version":"d0c1ae9a57e07bada9efe63248a3dcae315162495fa1e640345375acb731c835","signature":"4ec573c9a7a6a942df52c7242a91390e4b60b15e0d2a465be493b481fff98466"},{"version":"ad96e9f845d390c33a2d66c1ff86d1dd629c0ef295386d69a23a4817d901c8b2","signature":"1a7e3e41e1f025efef637c8edd69cd8dc55f78f884c8a9199ff1290d7781c9df"},{"version":"f941a490d798df5b4c1e84aebbd28e692afb9731d73a5986ce2bd38ccce35153","signature":"626f2e910f610ce499cd162570ad35dcede253f50ed0026ebe36eb8ada102074"},{"version":"e94a44230e4359d75a9b0826cecc75e785baf3abaf00f2e414205b6b7e33dd3f","signature":"fe3b337be297ca99ec220df68ba8a022b482200968b9e9b509c6b8c4a2261b39"},{"version":"9bcbebb149df05903f89a57a18eea86a76e2fc459c4b39bfe5a2c847c8ff4983","signature":"a013b06a2e8a57de465c4e503166248b7c1bc6535724e08b6744e436524fd5b1"},{"version":"3716aa39c86058ec6df05bb9075b74adcb43f60e456874597a0175fa65713aba","signature":"8f08acc74bfbd8c5999dc7507efe290fe2fee2f8932d57aee442a1b5eb384071"},{"version":"de808afd1e8ff95b1d8cb0defa8507eae4effeeba69640fa5f072d564f86f5d3","signature":"e0bafcec66b60ded367d98275325d322b4f00bee4a678e2324e02e0cdf5e908c"},{"version":"245aa18157b0a06dd133ea1c943dace3c7a281265126a540a75ae6ce78284d7e","signature":"6b753881943e78df20654cfd982992f8f6f898e614ac86d2f4528a7acd282f92"},{"version":"da3276531088f7d90f2b2a94ff329d826ac24ac74377fb19eff193d13b4f6cfa","signature":"e1cbc696e5cb26cf9ce1fc1924c65e418365e388006405eece60ffb7815a3623"},{"version":"4f0148a45234c646fc4fb84e123c99a29f3988c6bce9c387bdb5d0d7c75ba29e","signature":"2c3343c9bfa711023b94b2fa5d82531c071e26036fc2e672aa2ed7afb243f501"},{"version":"d588236de984d1faadd2e2f40af42a2b8664ca69658af75f24dc48a8c66ec1e9","signature":"180b37ba95c76b96de613e7e72197a5e08094262b9d58ac9a11cc0d47d869a88"},"55e27b93ee17fc4ec50789886e6497a7846d3d4fa8f7a41b85606d65c3acf68f","b54bf9bae737e80a381ffbcb40aa82940f3bfabf89270f989d6023aff3e7df65",{"version":"6eec0b712ee4fa23cdd367f5d866d6719b7c8812bc46c623668ed6072587ee80","impliedFormat":99},{"version":"34200a82ddb7fdf868d86595bf9729aac18a0e2795034431550551d0a31e7e9b","impliedFormat":99},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":99},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":99},{"version":"1ab59b972136fb41d90d704d6faeaa695fcc51be2bcd390e3d44f7d8fa055edf","impliedFormat":99},"9da84763e0ff337b27daec0b690c0aa50ae5b58467396d5542804df319efc6c7","f00df59648c1caeec2dbfacc2627f76bf73b10e82e2955512079f2a9d8455f14",{"version":"e817c7e4a7ee814d6b5a4940b388b6022ee19ac73fd956a27c13a2097d883a37","signature":"054061efa96439d6b183e09fe647fd1a8fa775fc1c94840990ca2f25a86aeef4"},"ebb668db4066eab05c0c7806a99567945a19f299d53aec3bb7df45f2c7ec3a54","52d46fc76049096d476b44719e50eb099d7dfb51be1d99c446339cb9225ab129",{"version":"ca1e6555f27a43cb62289d9de6e3961b619422ba64786836ca5660bb0084e7a4","signature":"5fae83fdfe1c2fd7f017a6feb47a50e99ce7a179676a5a43f9200ae557b99510"},"3e0a026643b12df9a0042bafd81f7df71f48cc62f5079d12a68215b4d4ad337b","f78c2c5fb6699a31c9b9e4026921e20f505fc5a9696eb3d120ef3d16307cb828","871c57d29d1886a73d7b33308c9665152ea7024f96b6acdb87b643c49add4e4c",{"version":"34a62e7f6f152c8100aa3c7c308c78946e2657c839802779b14eeaac2b039a97","signature":"614ce8f7d06bb17ee82a6fafbf31b854b3b8312c0d6708dd5004c7d70e8ea931"},"b1886697878387c1a689c23259b30bb7e8c834552683dc1742a26b99fa4cda3f","8ce9f0363aa5c5e9bf0a05cc75490200270c4ec89b679aaf32627c21767abf36","477d0f48a415bc2c67ab5dc2d8df8e9700966d9d7275a908b490e78cf9a8165c","55fae388468d08c422caac8bd0b668d4b1ac195cc295afb0826ffd887fbbfc69","937a5e3ee146dc227d1a8bb4b62309a915c25d0376129c9f4b0e4216053272aa","1cf0e272d454a07c7e6476bbf75f81320723bdb9386c42a2721c73c5f4938f4e",{"version":"f4e8f4151c3490cf7b68c685aabe901cbab19f962aaa2f118a97550e22689a76","impliedFormat":1},{"version":"799003c0ab928582fca04977f47b8d85b43a8de610f4eef0ad2d069fbb9f9399","impliedFormat":1},{"version":"d998eea476c695d8e4ff9d007d5b46d49ca2ffa052f74dc20ca516425abd57b1","impliedFormat":1},{"version":"a0bd46d587005aad4819980f6cf2dbcd80ebf584ed1a946202326a27158ba70e","impliedFormat":1},{"version":"07fcbb61a71bd69a92a5bbde69e60654666cf966b5675c2010c3bf9f436f056a","impliedFormat":1},{"version":"88b2eb23d36692162f2bf1e50577ebcde26de017260473e03ed9a0e61e2726a4","impliedFormat":1},{"version":"23ffbd8c0e20a697d2ea5a0cf7513fb6e42c955a7648f021da12541728f62182","impliedFormat":1},{"version":"43fba5fc019a4ce721a6f53ddb97fdc34c55049cfb793bc544d5c864ee5560b9","impliedFormat":1},{"version":"f4e12292c9a7663a13d152195019711c427c552eb0fa02705e0f61370cd5547a","impliedFormat":1},{"version":"c127ebf14d1b59d1604865008fb072865c5ca52277621f566092fe1f42ce0954","impliedFormat":1},{"version":"def638da26d84825a312113a20649d3086861de7c06a18ea13121278702976fd","impliedFormat":1},{"version":"fbaf86f8ba11298dea2727ce0da84b4ab6ae6c265e1919d44aff7d9b2bbc578a","impliedFormat":1},{"version":"c1010caaeaca8e420c6e040c2e822dbe18702459c93a7d2d5de38597d477b8cd","impliedFormat":1},{"version":"e1f0d8392efd9d71f2644eb97d3f33d90827e30ea8051d93b6f92bb11dff520a","impliedFormat":1},{"version":"085211167559ca307d4053bb8d2298d5ad83cbc3d2ae9bb4c8435a4cabf59369","impliedFormat":1},{"version":"55fc49198d8a85a73cdb79e596d9381cfdc9de93c32c77d42e661c1c1e7268ef","impliedFormat":1},{"version":"6a53fb3df8dd32ed1a65502ca30aeae19cfe80990e78ba68162d6cb2a7fed129","impliedFormat":1},{"version":"b5dcc18d7902597a5584a43c1146ca4fe0295ceb5125f724c1348f6a851dd6ed","impliedFormat":1},{"version":"0c6b0f3fbe6eb6a3805170b3766a341118c92ed7b6d1f193b9f35aa82f594846","impliedFormat":1},{"version":"60eaadb36cf157c5cae9c40e84fa367d04f52a150db3920dbe35139780739143","impliedFormat":1},{"version":"4680a32b1098c49dc87881329af1e68af9af94e051e1b9e19fed555a786f6ce6","impliedFormat":1},{"version":"89fcd129ec37f321cddcdb6b258ffe562de4281e90ec3ccbe7c1199ba39359ca","impliedFormat":1},{"version":"4313011f692861c2c1f5205d7f9a473e763adab6444f9853b96937b187fb19f7","impliedFormat":1},{"version":"caa57157e7bdb8d5f1efe56826fb84a6c8f22a1927bba7fa21fd54e2a44ccba2","impliedFormat":1},{"version":"6b74700abfe4a9b88be957fd8e373cfd998efb1a5f6ad122da49a92997e183ad","impliedFormat":1},{"version":"9ef1342f193bd8bae86c64e450c3ac468ef08652110355e1f3cdd45362eb95c4","impliedFormat":1},{"version":"6853c91662c36a2bf4c8371a87177c819007c76a23c293ef3f686ce9157ae4c8","impliedFormat":1},{"version":"9be1c5dabce43380d13fc621100676b03d420b5687b08d1288f479bee68ab7a8","impliedFormat":1},{"version":"8996d218010896712678e6a0337d8ef8b81c1066ab76f637dd8253f0d6ff838d","impliedFormat":1},{"version":"a15603bf387fc45defe28a68f405a6c29105e135c4e8538eeb6d0a1ef5b69a81","impliedFormat":1},{"version":"84e2532e4d42949a2775cdd8bb7b2b97370dd6ddb683d0c199b21bf6978b152d","impliedFormat":1},{"version":"22bf5f19f620db3b8392cfece44bdd587cdbed80ba39c88a53697d427135bf37","impliedFormat":1},{"version":"23ebbd8d484d07e1c1d8783169c20570ed8409966b28f6be6cf8e970d76ef491","impliedFormat":1},{"version":"18b6fa2c778cad6489f2febf76433453f5e2432ec3535f2d45ae7d803b93cc17","impliedFormat":1},{"version":"609d0d7419999cf44529e6ba687e2944b2fc7ad2570d278fd4e6b1683c075149","impliedFormat":1},{"version":"249cf421b8878a3fe948d9c02f6b0bae65491b3bb974c2ffc612341406fa78ff","impliedFormat":1},{"version":"b4aa22522d653428c8148ddbf1dcc1fb3a3471e15eb1964429a67c390d8c7f38","impliedFormat":1},{"version":"30b2cee905b1848b61c7d28082ebfa2675dd5545c0d25d1c093ce21a905cdccc","impliedFormat":1},{"version":"0a2a2eed4137368735205de97c245f2a685af1a7f1bf8d636b918a0ee4ff4326","impliedFormat":1},{"version":"69f342ce86706aa2835a62898e93ea7a1f21b1d89c70845da69371441bb6cd56","impliedFormat":1},{"version":"b5ab4282affcfd860dd1cc3201653f591509a586d110f8e5b1b010508ba79b2c","impliedFormat":1},{"version":"d396233f6cd3edf0d33c2fbfc84ded029c3ea4a05af3c94d09d31a367cced111","impliedFormat":1},{"version":"bc41a726c817624a5136ae893d7aac7c4dc93c771e8d243a670324bccf39b02b","impliedFormat":1},{"version":"710728600e4b3197f834c4dd1956443be787d2e647a72f190bf6519f235aaadd","impliedFormat":1},{"version":"a45097e01ef30ba26640fed365376ab3ccd5faf97d03f20daff3355a7e60286a","impliedFormat":1},{"version":"763cbb7c22199f43fd5c2b1566af5ba96bf7366f125dd31a038a2291cbc89254","impliedFormat":1},{"version":"031933bf279b7563e11100b5e1746397caf3a278596796a87bc0db23cf68dc9e","impliedFormat":1},{"version":"a4a54c1f58fc6e25a82e2c0f651bf680058bd7f72cfb2d43b85ee0ab5fe2e87e","impliedFormat":1},{"version":"9613d789b6f1037f2523a8f70e1b736f1da4566b470593da062be5c9e13dac57","impliedFormat":1},{"version":"0d2a320763a0c9c71493f8f1069971018c8720a6e7e5a8f10c26b6de79aa2f7d","impliedFormat":1},{"version":"817e0df27a237a268dc16e5acffc19f9a74467093af7a0ba164ee927007a4d25","impliedFormat":1},{"version":"43102521b5ca50ff1865188c3c60790feaed94dc9262b25d4adec4dbc76f9035","impliedFormat":1},{"version":"f99947f8d873b960b0115e506ef9c43f4e40c2071b1d20375564538af4a6023b","impliedFormat":1},{"version":"c1e5ad5ca89d18d2a36d25e8ec105623648cf35615825e202c7d8295a49d61ab","impliedFormat":1},{"version":"2b6c9cb81da4e0a2e32a58230e8c0dec49fc5b345efb7f7a3648b98956be4b13","impliedFormat":1},{"version":"99e34af3ede50062dcc826a1c3ce2d45562060dfd0f29f8066381a6ef548bf2a","impliedFormat":1},{"version":"49f5c2a23ea5fc4b2cdb4426f09d1c8b83f8409fa2af13ef38845cc9b9d4bc3d","impliedFormat":1},{"version":"e935227675144b64ecde3489e4a5e242eeb25fdd6b7464b8c21ad1f7a0faa88b","impliedFormat":1},{"version":"b42e6bbe88dc79c2d6dc5605fb9c15184e70f64bdd7b8d4069b802b90ce86df6","impliedFormat":1},{"version":"b9cd712399fdc00fdae07e96c9b39c3cb311e2a8a5425f1bd583f13cab35e44b","impliedFormat":1},{"version":"5a978550ae131b7fef441d67372fd972abab98ea9fdb9fa266e8bdc89edcb8d6","impliedFormat":1},{"version":"4f287919cfc1d26420db9f0457cd5c8780b1ef0a9f949570936abe48d3a43d91","impliedFormat":1},{"version":"496b23b2fd07e614bc01d90dd4388996cb18cd5f3a612d98201e9f683e58ad2e","impliedFormat":1},{"version":"dcfbe42824f37c5fb6dc7b9427ef2500791ec0d30825ecb614f15b8d5bf5a667","impliedFormat":1},{"version":"390124ad2361b46bf01851d25e331cd7eed355d04451d8b2a4aa985c9de4f8ce","impliedFormat":1},{"version":"14d94f17772c3a58eda01b6603490983d845ee2012cd643f7497b4e22566aacb","impliedFormat":1},{"version":"03ef2386c683707ce741a1c30cb126e8c51a908aa0acc01c3471fafb9baaacd5","impliedFormat":1},{"version":"66a372e03c41d2d5e920df5282dadcec2acae4c629cb51cab850825d2a144cea","impliedFormat":1},{"version":"5b48ba9a30a93176a93c87f9e0abf26a9df457eeb808928009439ca578b56f27","impliedFormat":1},{"version":"4707625392316d3c16edbd0716f4ac310e8ff5d346d58f4d01a2b7e0533a23df","impliedFormat":1},{"version":"154d58a4b2d9c552dc864ea39c223d66efd0ed2dd8b55bd13db5225d14322915","impliedFormat":1},{"version":"6a830433fa072931b4ea3eb9aa5fa7d283f470080586a27bfe69837a0f12de9a","impliedFormat":1},{"version":"d25e930e181f4f69b2b128514538f2abb54ef1d48a046ad776ac6f1cda885a72","impliedFormat":1},{"version":"0259b4c21bc93b52ca82c755f97fc90481072bcc44a8010131b2ea7326cf03fe","impliedFormat":1},{"version":"bea43a13a1104a640da0cb049db85c6993f484a6cc03660496b97824719ecc91","impliedFormat":1},{"version":"0224239d61fe66d4900544d912b2e11c2cca24b4707d53fdb94b874a01e29f48","impliedFormat":1},{"version":"2bce8fd2d16a9432110bbe0ba1e663fd02f7d8b8968cd10178ea7bc306c4a5df","impliedFormat":1},{"version":"9c4ad63738346873d685e5c086acbf41199e7022eff5b72bb668931e9ca42404","impliedFormat":1},{"version":"cfb6329bf8ce324e83fe4bbdee537d866a0d5328246f149a0958b75d033de409","impliedFormat":1},{"version":"efc3816f19ea87a7050c84271ea3d3aad9631a517c168013c4f4b6724c287ce0","impliedFormat":1},{"version":"f99f6737336140047e8dd4ade3859f08331aa4b17bc2bd5f156a25c54e0febbc","impliedFormat":1},{"version":"12a2b25c7c9c05c8994adf193e65749926acfcc076381f7166c2f709a97bdf0a","impliedFormat":1},{"version":"0f93a3fdd517c1e45218cd0027c1d6b82237e379dc6b66d693aab1fe74c82e81","impliedFormat":1},{"version":"03c753da0bee80ad0d0f1819b9b42dfe9bf9f436664caf15325aa426246fd891","impliedFormat":1},{"version":"18f5bf1dae429c451f20171427c9e3223fade4346af4dfd817725cbeb247a09d","impliedFormat":1},{"version":"a4eece5fab202e840dd84f7239e511017a8162edb8fc8b54ff2851c5c844125c","impliedFormat":1},{"version":"c4a94af483a63bf947d89f97553a55df5107c605ec8a26f0b9b8bdcc14bd6d89","impliedFormat":1},{"version":"19de2915ccebc0a1482c2337b34cb178d446def2493bf775c4018a4ea355adb8","impliedFormat":1},{"version":"9be8fc03c8b5392cd17d40fd61063d73f08d0ee3457ecf075dcb3768ae1427bd","impliedFormat":1},{"version":"3b568b63f0e8b3873629a4d7a918dce4266ad41461004ab979f8dcdfd13532bb","impliedFormat":1},{"version":"a5e5223c775fe30d606b8aaa521953c925d5ad176a531c2b69437d2461aaabbd","impliedFormat":1},{"version":"8cbf41d2d1ce8ac2066783ae00613c33feef07493796f638e30beaf892e4354a","impliedFormat":1},{"version":"e22ad737718160df198cd428f18da707177d0467934cecdeed4be6e067b0c619","impliedFormat":1},{"version":"15bf5ed8cb7c1a1e1db53fa9b45bc1a1c73c0497735343a8d0c59fdb596a3744","impliedFormat":1},{"version":"791fce84bce8b6948e4f23422d9cbbd7d08c74b3f91cca12dcae83d96079798b","impliedFormat":1},{"version":"8a2619c8e24305f6b9700b35af178394b995dcb28690a57a71cca87ee7e709ae","impliedFormat":1},{"version":"f95fd2fc3cc164921a891f5d6c935fa0d014a576223dd098fc64677e696b0025","impliedFormat":1},{"version":"8c9cecaaa9caba9a8caa47f46dcf24b524b27899b286d8edcc75a81b370d2ba3","impliedFormat":1},{"version":"2b7a82692ecc877c5379df9653902e23f2d0d0bc9f210ec3cf9e47be54413c5c","impliedFormat":1},{"version":"e2ad09c011cf9d7ee128875406bef787eeb504659495f42656a0098c15fe646c","impliedFormat":1},{"version":"eb518567ea6b0b2623f9a6d37c364e1b1ac9d8b508d79e558f64ac05c17e2685","impliedFormat":1},{"version":"630a48fb8f6b07161588e0aee3f9d301c59c97e1532c884118f89368baf4073b","impliedFormat":1},{"version":"14736c608aa46120f8d6d0bc5e0721b46b927bc7eba20e479600571935f27062","impliedFormat":1},{"version":"7574803692d2230db13205a7749b9c3587dccaccdf9e76f003f9e08078bb6d09","impliedFormat":1},{"version":"f3cc1588e666651c51353b1728460bee8acbc6e0f36be8c025eaaf292dca525d","impliedFormat":1},{"version":"0d4ea8a20527dcf3ad6cf1bd188b8ad4e449df174fad09b9e540ed81080af834","impliedFormat":1},{"version":"aa82876d59912d25becff5a79ed7341af04c71bfeb2221cc0417bc34531125e2","impliedFormat":1},{"version":"6f4b0389f439adc84cba35d45428668eabcfbdd351ba17e459d414ca51ab8eb8","impliedFormat":1},{"version":"d5dd33d15fbb07668c264b38065ac542a07a7650af4917727bbc09b58570e862","impliedFormat":1},{"version":"7d90202d0212e9cdc91a20bfddf04a539c89f09fe1d64db3343546fa2eb37e71","impliedFormat":1},{"version":"1a5d073c95a3a4480b17d2fa7fd41862a9df0cb2afaee86834b13649e96bdb45","impliedFormat":1},{"version":"2092495a5b3116c760527a690c4529748f2d8b126cdd5f56b2ce2230b48aba3f","impliedFormat":1},{"version":"620b29d6adbd4061bc0a8fedf145fcc8e8fc9648fb6e0a39726e33babb4e07bc","impliedFormat":1},{"version":"931eda51b5977f7f3fa7a0d9afde01cfd8b0cc1df0bb66dcf8c2cf6e7090384e","impliedFormat":1},{"version":"b084a412374bdd124048c52c4e8a82d64f3adec6c0a9ad5ecbb7317636039b0f","impliedFormat":1},{"version":"11199daa694c3ced3cc2a382a3fa7bd64e95eb40f9bbc3979fc8fb43f5ba38cc","impliedFormat":1},{"version":"2c86f279d7db3c024de0f21cd9c8c2c972972f842357016bfbbd86955723b223","impliedFormat":1},{"version":"dfb53b9d748df3e140b0fddb75f74d21d7623e800bb1f233817a1a2118d4bb24","impliedFormat":1},{"version":"8cfc293b33082003cacbf7856b8b5e2d6dd3bde46abbd575b0c935dc83af4844","impliedFormat":1},{"version":"7730c538d6d35efe95d2c0d246b1371565b13037e893178033360b4c9d2ac863","impliedFormat":1},{"version":"b256694544b0d45495942720852d9597116979d52f2b53c559fda31f635c60df","impliedFormat":1},{"version":"794e8831c68cc471671430ee0998397ea7a62c3b706b30304efdc3eaff77545a","impliedFormat":1},{"version":"9cfc1b227477e31988e3fb18d26b6988618f4a5da9b7da6bc3df7fc12fb2602e","impliedFormat":1},{"version":"264a292b6024567dd901fdabbf3239a8742bea426432cdbda4cf390b224188e1","impliedFormat":1},{"version":"f1556a28bb8e33862dcfa9da7e6f1dca0b149faf433fe6a50153ae76f3362db1","impliedFormat":1},{"version":"1d321aea1c6a77b2a44e02e5c2aeff290e3f1675ead1a86652b6d77f5fea2b32","impliedFormat":1},{"version":"4910efc2ce1f96d6e71a9e7c9437812ffae5764b33ab3831c614663f62294124","impliedFormat":1},{"version":"e3ceab51a36e8b34ab787af1a7cf02b9312b6651bac67c750579b3f05af646c1","impliedFormat":1},{"version":"baf9f145bcee1b765bed6e79fd45e1ff0ca297a81315944de81eb5d6fff2d13d","impliedFormat":1},{"version":"2afd62362b83db93cd20de22489fe4d46c6f51822069802620589a51ccad4b99","impliedFormat":1},{"version":"9f0cd9bd4ab608123b88328c78814738cbdee620f29258b89ef8cd923f07ff9c","impliedFormat":1},{"version":"801186c9e765583c825f28dab63a7ad12db5609e36dc6d9acbdc97d23888a463","impliedFormat":1},{"version":"96c515141c6135ccd6fb655fb9e3500074a9216ba956fb685dc8edc33f689594","impliedFormat":1},{"version":"416af6d65fc76c9ced6795f255cb1096c9d7947bede75b82289732b74d902784","impliedFormat":1},{"version":"a280c68b128ebba35fb044965d67895201c2f83b6b28281bb8b023ade68bf665","impliedFormat":1},{"version":"6fa118f15723b099a41d3beea98ed059bcd1b3eda708acf98c5eff0c7e88832f","impliedFormat":1},{"version":"dcbf582243e20ea50d283f28f4f64e9990b4ed4a608757e996160c63cff6aa99","impliedFormat":1},{"version":"efa432d8fd562529c4e9f859fd936676dd8fef5d3b4bedb06f754e4740056ea9","impliedFormat":1},{"version":"a59b66720b2ccf2e0150fafb49e8da8dabdf4e1be36244a4ccd92f5bd18e1e9e","impliedFormat":1},{"version":"c657fb1ec3b727d6a14a24c71ea20c41cb7d26a503e8e41b726bb919eb964534","impliedFormat":1},{"version":"50d6d3174868f6e974355bf8e8db8c8b3fcf059315282a0c359ecf799d95514a","impliedFormat":1},{"version":"86bf79091014a1424fc55122caa47f08622b721a4d614b97dd620e3037711541","impliedFormat":1},{"version":"7a63313dff3a57f824a926e49a7262f7bd14e0e833cf45fa5af6da25286769c2","impliedFormat":1},{"version":"36dcaeffe1a1aed1cb84d4feba32895bf442795170edccc874fa32232b2354e5","impliedFormat":1},{"version":"686c6962d04d90edafc174aa5940acb9c9db8949c8d425131c01d796cf9a3aef","impliedFormat":1},{"version":"2b1dbc3d5762d6865744b6e7be94b8b9004097698c37e93e06983e42dd8fe93b","impliedFormat":1},{"version":"eb5e8f74826bdf3a6a0644d37a0f48133f8ad0b5298cc2c574102868542ba4eb","impliedFormat":1},{"version":"c6a82a9673ba517cf04dd0803513257d0adf101aed2e3b162a54d840c9a1a3b2","impliedFormat":1},{"version":"fc9f0f415abaa323efcecc4a4e0b6763bfe576e32043546d44f1de6541b6399b","impliedFormat":1},{"version":"2c4d772ac7ac56a44deef82903364eb7c78dd7bc997701123df0ce4639fe39bb","impliedFormat":1},{"version":"9369ef11eed17c1c223fdea9c0fa39e83f3722914ef390b1448db3d71620c93a","impliedFormat":1},{"version":"aa84130dbc9049bba6095f87932138698f53259b642635f6c9e92dd0ddc7512c","impliedFormat":1},{"version":"084ceadd21efabd4b58667dca00d4f644306099151d2ee18cd28a395855b8009","impliedFormat":1},{"version":"b9503e29f06c99b352b7cae052da19e3599fa42899509d32b23a27c9bb5bebf6","impliedFormat":1},{"version":"75188920fe6ccc14070fe9a65c036049f1141d968c627b623d4a897ec3587e15","impliedFormat":1},{"version":"e2e1df7f45013d2b34f8d08e6ae5a9339724b0ea251b5445fcca3e170e640105","impliedFormat":1},{"version":"af06feb5d18a6ea11c088b683bdb571800d1f76b98d848eecdf41e5ec8f317fd","impliedFormat":1},{"version":"0596af52b95e0c8adc2c07f49f109d746b164739c5866fa8bb394dd6329a3725","impliedFormat":1},{"version":"c3365d08fe7a1ccc3b8e8638edc30123007f3241b4604e2585b9f14422ab97d8","impliedFormat":1},{"version":"a7a3d96b04bb0ec8cb7d2669767c4756f97dd70d08548f9e6522dde4de8e8a03","impliedFormat":1},{"version":"745e960e885a4ba04c872225cbb44bd67a7490d169ceaefab7c0dfc444768676","impliedFormat":1},{"version":"0b1ce1768cde3535493a9daf99e3bbb8c7dcc3a7f9d8cd358cb846af71ce5cdf","impliedFormat":1},{"version":"48b9603f6e8a7c94b727277592a089f94261baa64e6c9d18165da0481663a69e","impliedFormat":1},{"version":"3c20a3bb0c50c819419f44aa55acc58476dad4754a16884cef06012d02b0722f","impliedFormat":1},{"version":"4dc64902cb86e677a928293593658fbf53388f9a30d2b934140c70a7267b07ec","impliedFormat":1},{"version":"cb4fd56539a61d163ea9befe6b0292c32aa68a104c1f68f61416f1bc769bcfba","impliedFormat":1},{"version":"0d852bdc2b72b22393a8eebe374ee3efe3e0d44e630037b5e1b6087985388e62","impliedFormat":1},{"version":"b6c9a2deefb6a57ff68d2a38d33c34407b9939487fc9ee9f32ba3ecf2987a88a","impliedFormat":1},{"version":"f6b371377bab3018dac2bca63e27502ecbd5d06f708ad7e312658d3b5315d948","impliedFormat":1},{"version":"faa72893e85cb8ebb1dafde6b427e5204e60bb5f3ee6576bb64c01db1f255bc8","impliedFormat":1},{"version":"95b7ed47b31a6eaddcdd853ee0871f2bb61e39ce36a01d03dfafb83766f6c10c","impliedFormat":1},{"version":"19287d6b76288c2814f1633bdd68d2b76748757ffd355e73e41151644e4773d6","impliedFormat":1},{"version":"fc4e6ec7dade5f9d422b153c5d8f6ad074bd9cc4e280415b7dc58fb5c52b5df1","impliedFormat":1},{"version":"3aea973106e1184db82d8880f0ca134388b6cbc420f7309d1c8947b842886349","impliedFormat":1},{"version":"765e278c464923da94dda7c2b281ece92f58981642421ae097862effe2bd30fa","impliedFormat":1},{"version":"de260bed7f7d25593f59e859bd7c7f8c6e6bb87e8686a0fcafa3774cb5ca02d8","impliedFormat":1},{"version":"d95c4eaad4df9e564859f0c74a177fa0b2e5f8a155939b52580566ab6b311c3f","impliedFormat":1},{"version":"7192a6d17bfa06e83ba14287907b7c671bef9b7111c146f59c6ea753cfc736b9","impliedFormat":1},{"version":"5156d3d392db5d77e1e2f3ea723c0a8bd3ca8acffe3b754b10c84b12f55a6e10","impliedFormat":1},{"version":"a6494e7833ee04386a9f0c686726f7cb05f52f6e069d9293475ccb1e791ee0da","impliedFormat":1},{"version":"d9af0c89a310256851238f509a22aa1071a464d35dc22ea8c2a0bae42dd81bc5","impliedFormat":1},{"version":"291642a66e55e6ca38b029bc6921c7301f5c7b7acf21ae588a5f352e6c1f6d58","impliedFormat":1},{"version":"43cd7c37298b051d1ce0307d94105bcd792c6c7e017282c9d13f1097c27408e8","impliedFormat":1},{"version":"e00d8cce6e2e627654e49c543b582568ad0bf27c1d4ad1018d26aff78d7599df","impliedFormat":1},{"version":"ed13354f0d96fb6d5878655b1fead51722b54875e91d5e53ef16de5b71a0e278","impliedFormat":1},{"version":"fcb934d0fcdee06a8571bd90aa3a63aa288c784b3ebcecfe7ae90d3104d321f4","impliedFormat":1},{"version":"af682dfabe85688289b420d939020a10eb61f0120e393d53c127f1968b3e9f66","impliedFormat":1},{"version":"0dca04006bf13f72240c6a6a502df9c0b49c41c3cab2be75e81e9b592dcd4ea8","impliedFormat":1},{"version":"7dc0b5e3d7be8e1f451f0545448c2eaa02683f230797d24434b36f9820d5a641","impliedFormat":1},{"version":"247af61cdc3f4ec7876b9e993a2ecdd069e10934ff790c9cee5811842bff49eb","impliedFormat":1},{"version":"4be8c2c63d5cd1381081d90021ddfaef106881df4129eddeeaba906f2d0f75d0","impliedFormat":1},{"version":"012f621d6eb28172afb1b2dc23898d8bc74cf35a6d76b63e5581aa8e50fa71b3","impliedFormat":1},{"version":"3a561fa91097e4580c5349ce72e69d247c31c11d29f39e1d0bd3716042ff2c0b","impliedFormat":1},{"version":"bc9981a79dda3badea61d716d368a280c370267e900f43321f828495f4fef23c","impliedFormat":1},{"version":"2ed3b93d55aea416d7be8d49fe25016430caab0fe64c87d641e4c2c551130d17","impliedFormat":1},{"version":"3d66dfc31dd26092c3663d9623b6fc5cec90878606941a19e2b884c4eacd1a24","impliedFormat":1},{"version":"6916c678060af14a8ce8d78a1929d84184e9507fba7ab75142c1bcb646e1c789","impliedFormat":1},{"version":"3eea74afae095028597b3954bde69390f568afc66d457f64fff56e416ea47811","impliedFormat":1},{"version":"549fb2d19deb7d7cae64922918ddddf190109508cc6c7c47033478f7359556d2","impliedFormat":1},{"version":"e7023afc677a74f03f8ccb567532fe9eedd1f5241ee74be7b75ac2336514f6f6","impliedFormat":1},{"version":"ff55505622eac7d104b9ab9570f4cc67166ba47dd8f3badfb85605d55dd6bdc9","impliedFormat":1},{"version":"102fac015b1eebfa13305cb90fd91a4f0bbcabb10f2343556b3483bbb0a04b62","impliedFormat":1},{"version":"18a1f4493f2dbad5fd4f7d9bfba683c98cf5ed5a4fa704fa0d9884e3876e2446","impliedFormat":1},{"version":"f57e6707d035ab89a03797d34faef37deefd3dd90aa17d90de2f33dce46a2c56","impliedFormat":1},{"version":"cc8b559b2cf9380ca72922c64576a43f000275c72042b2af2415ce0fb88d7077","impliedFormat":1},{"version":"1a337ca294c428ba8f2eb01e887b28d080ee4a4307ae87e02e468b1d26af4a74","impliedFormat":1},{"version":"310fe80ff40a158c2de408efbe9de11e249c53d2de5e33ca32798e6f3fbc8822","impliedFormat":1},{"version":"d6ce96c7bb34945c1d444101f44e0f8ba0bba8ab7587a6cc009a9934b538c335","impliedFormat":1},{"version":"1b10a2715917601939a9288d49beccd45b591723256495b229569cd67bbe48a8","impliedFormat":1},{"version":"7498dfdeed2e003ec49cdf726ff6c293002d1d7fdadbc398ce8aafe6d0688de7","impliedFormat":1},{"version":"8492306a4864a1dc6fc7e0cc0de0ae9279cbd37f3aae3e9dc1065afcdc83dddc","impliedFormat":1},{"version":"9c86abbc4fd0248f56abc12aaecd76854517389af405d5ec2eb187fdb00a606f","impliedFormat":1},{"version":"9ffd906f14f8b059d6b95d6640920f530507e596e548f7a595da58ab66e3ce76","impliedFormat":1},{"version":"1884bccc10ce40adca470c2c371c1c938b36824f169c56f7f43d860416ca0a4c","impliedFormat":1},{"version":"986b55b4f920c99d77c1845f2542df6f746cb5adc9ab93eb1545a7e6ef37590d","impliedFormat":1},{"version":"cd00906068b81fbd8a22d021580ac505e272844408174520fafed0ae00627a5d","impliedFormat":1},{"version":"69fab68a769c17a52a24b868aeb644f3ee14abaa5064115f575ddd59231105ce","impliedFormat":1},{"version":"e181eb86b2caf80fe18c72efce6b913bc226e4a69a5456eaf4f859f1c29c6fd6","impliedFormat":1},{"version":"93f7871380478bc6acf02ad9f3dc7da0c21997caebbe782eb93a11b7bd06a46d","impliedFormat":1},{"version":"d00279ab020713264f570d5181c89ca362b7de8abddf96733de86bce0eca082c","impliedFormat":1},{"version":"f7db473f1d5d2a124f14886ac9dbfeccfbb94a98bbe1610a47c30c2933afa279","impliedFormat":1},{"version":"f44cf6c6d608ef925831e550b19841b5d71bd87195bd346604ff05644fb0d29c","impliedFormat":1},{"version":"154f23902d7a3fcdace4c20b654da7355fee4b7f807d1f77d6c9a24a8756013a","impliedFormat":1},{"version":"562f4f3c75a497d3ad7709381f850bb8c7646a9c6e94fdf8e91928e23d155411","impliedFormat":1},{"version":"4583380b676ee59b70a9696b42acfa986cd5f32430f37672e04f31f40b05df74","impliedFormat":1},{"version":"ad0a13f35a0d88803979f8ea9050ad7441e09d21a509abf2f303e18c1267af17","impliedFormat":1},{"version":"ba9781c718ab3d09cbde1216029072698d2da6135f0d2f856ba387d6caceb13e","impliedFormat":1},{"version":"d7c597c14698ba5fc8010076afa426f029b2d8edabb5073270c070cc645ba638","impliedFormat":1},{"version":"bd2afc69cf1d85cd950a99813bc7eff007d8afa496e7c2142a845cd1181d0474","impliedFormat":1},{"version":"558b462b23ea186d094dbff158d652acd58c0988c9fd53af81a8903412aa5901","impliedFormat":1},{"version":"0e984ae642a15973d652fd7b0d2712a284787d0d7a1db99aa49af0121e47f1df","impliedFormat":1},{"version":"0ad53ee208a23eef2a5cb3d85f2a9dc1019fd5e69179c4b0c02dc56c40d611c4","impliedFormat":1},{"version":"7a6898b26947bd356f33f4efef3eb23e61174d85dca19f41a8780d6bb4bfb405","impliedFormat":1},{"version":"9fe30349d26f34e85209fb06340bac34177f7eae3d6bb69dc12cd179d2c13ddf","impliedFormat":1},{"version":"d568c51d2c4360fd407445e39f4d86891dba04083402602bf5f24fd3969cacbb","impliedFormat":1},{"version":"b2483a924349ec835f4d778dd6787447a2f8bfbb651164851bff29d5b3d990a6","impliedFormat":1},{"version":"aae66889332cff4b2f7586c5c8758abc394d8d1c48f9b04b0c257e58f629d285","impliedFormat":1},{"version":"0f86c85130c64d6dbe6a9090bb3df71c4b0987bce4a08afe1ac4ece597655b9c","impliedFormat":1},{"version":"0ce28ad2671baed24517e1c1f4f2a986029137635bce788ee8fb542f002ac5b8","impliedFormat":1},{"version":"cd12e4fe77d24db98d66049360a4269299bcfb9dc3a1b47078ab1b4afac394cb","impliedFormat":1},{"version":"1589e5ac394b2b2e64264da3e1798d0e103b4f408f5bae1527d9e706f98269c7","impliedFormat":1},{"version":"ff8181aa0fde5ec2d737aecc5ebaa9e881379041f13e5ce1745620e17f78dcf9","impliedFormat":1},{"version":"0b2e54504b568c08df1e7db11c105786742866ba51e20486ab9b2286637d268f","impliedFormat":1},{"version":"bc1ffc3a2dca8ee715571739be3ec74d079e60505e1d0d2446e4978f6c75ba5c","impliedFormat":1},{"version":"770a40373470dff27b3f7022937ea2668a0854d7977c9d22073e1c62af537727","impliedFormat":1},{"version":"a0f8ce72cb02247a112ce4a2fa0f122478a8e99c90a5e6b676b41a68b1891ad2","impliedFormat":1},{"version":"6e957ea18b2bf951cf3995d115ad9bfa439e8d891aeb1afc901d793202c0b90d","impliedFormat":1},{"version":"a1c65bd78725f9172b5846c3c58ddf4bcbb43a30ab19e951f0102552fbfd3d5d","impliedFormat":1},{"version":"04718c7325e7df4bac9a6d026a0a2bd5a8b54501f274aaf93a03b5d1d0635bd1","impliedFormat":1},{"version":"405205f932d4e0ce688a380fa3150b1c7ff60e7fc89909e11a33eab7af240edb","impliedFormat":1},{"version":"566fc1a6616a522f8b45082032a33e6d37ff7df3f7d4d63c3cce9017d0345178","impliedFormat":1},{"version":"3b699b08db04559803b85aa0809748e61427b3d831f77834b8206e9f2ed20c93","impliedFormat":1},{"version":"b27242dd3af2a5548d0c7231db7da63d6373636d6c4e72d9b616adaa2acef7e1","impliedFormat":1},{"version":"e0ee7ba0571b83c53a3d6ec761cf391e7128d8f8f590f8832c28661b73c21b68","impliedFormat":1},{"version":"072bfd97fc61c894ef260723f43a416d49ebd8b703696f647c8322671c598873","impliedFormat":1},{"version":"e70875232f5d5528f1650dd6f5c94a5bed344ecf04bdbb998f7f78a3c1317d02","impliedFormat":1},{"version":"8e495129cb6cd8008de6f4ff8ce34fe1302a9e0dcff8d13714bd5593be3f7898","impliedFormat":99},"ee315de689a95897bb54764f2b45c106490cb7b725651fc2c071cfa77932cd83","77b13aa8b7fdff6cbe52c96b1b2222418251567c037534ba16cbff2be825a26a",{"version":"771f42f64e7823d6f92018e12a1c653bfa2f51b3914f8906fb26917215bc400e","signature":"509e239a097a9e6ed3c511b283d0e9bfece76c1abb61bc6f53dd7b46d1cabb29"},"b461a0df72b65f68a1fc66868262f29a205a8c4b1247d63cfb526ff7347adc4d","7a93f2a3b37c35f1f1fbf39dceeef4c8f23bd5e9e8dab4d82290a2730cdca93b","7edf699514893140c9e3f253da0acaa31e8e675ef8f66505aeb25068e0148bac","1447246c0124b94488cb5508e6c754a768633d49b22681715fd1542fd9dc014b","754fc9bdaa3b0cfddcd1f1ab88e7cfd37ea4bcb29ec8c13f3873d040c3cb8b36","dc79e41b1c08ed08b7931a16103ccdd0e7145e64870ac423055b7778dc334a86","bb5eda2fa9febd02b7d3472b9235d4e8d3388817eedf7513623ec817646c37cd","5a256b049c236fa23f36483177df7a5209ca7e15cc5fe6674247aae73838b3b6",{"version":"d1604b3b1555d56a6b6471d444777099c2410c4fadba0600a634acd00be2f0df","signature":"45b373ad2e114de335dd3eaf62f9658266d71c2f34537489f88f3b4815fa72f8"},{"version":"d5e7f716f0f74bb25523f3d5237952f1ed9d987e14ace2746187521a4eb25f76","signature":"59b773c85d82f560f9c7492e2609f37dc329c247914603831f6655b1e5090aa2"},{"version":"a01c5938b5dc6e819c0a4fc1e86a90da723d42f28f9b23a4657be78c0e6b8a15","signature":"872981c7daf929ee5ed35e720f59692075154510ce720a68d7a59859e1da78b0"},"8419030131409201d3ad797bb319496d35572512cac2612ceafe6df8f2576079","b10d1bf48682b29b7a70fffbc44dcf1ee2e9a51abaf369ccba5a1249f7bf8f5b","3bdd6bb08fdf67ac70bf1960b9c4b530d9e45863887a4be42b36b5b9813c31c4","a3ef450d30cd8249ea3a63c47455f4c20a6e9731e20ed0eb46891922d65c7fb5","c0ee1684787b5c190d1aa9cbb0c0ec7c6c8a57b1533ea937a815f89c5a8faa69",{"version":"d59ee6238cc100b0802d28ef8af6c1b9f8e91bfcf4edb5af1afb167140b3a290","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"4949090d70dc78fca6706978b9d3efdb17f0558df3a827dc0ca86d4697dd8202","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"69779615a21bc23ba8d6b8337c1e40c3a7acde3e10b107f9ffe9402c29c195da","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"765fa8b3ed4af86af75d1c43ead9714b4d85c36cba7e9e25e8fa1a82663c9bc8","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"d07f59c14d8b4a708c74e9106a3b24518792a1db606ce0478ca99b03e175a943","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"e382126a0461c82085890372246391048d2fa475ccc20bde0de2a234ede2b0aa","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"d1f8574cbdc204413ae8fb1caf842dc157436725cc4cc97b7733f07df23c331f","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"89961a06f4659e4651b07bef4e094ff0827356496513cac9817e0385c0e09b8c","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"ef073dd3d5992b39e9d7a069d22342d5270ce8b9b9c31396df7e705ebf1d930e","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"d2b6f4f1ef3f7426227cdada24c67865a5b58ae0d64e89d7b5639404e8d4947d","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"dacc04fa5d817e860fd739b61a4f0e8a315bbeec3598d93a311f70b42cc72ca6","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"4e2fadedec679e373a74315d586af8451a801b2e11a31a320ff2f018402f700a","signature":"2cc743b624d6891f9275f11f76fedfe235af04641c806e7dc65e55740db4dd29"},{"version":"f2f23fe34b735887db1d5597714ae37a6ffae530cafd6908c9d79d485667c956","impliedFormat":1},{"version":"5bba0e6cd8375fd37047e99a080d1bd9a808c95ecb7f3043e3adc125196f6607","impliedFormat":1}],"root":[410,435,467,[469,479],494,[497,518],[520,533],[539,554],[812,842]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true,"target":7},"referencedMap":[[832,1],[833,2],[834,3],[835,4],[836,5],[837,6],[838,7],[839,8],[840,9],[831,10],[841,11],[842,12],[410,13],[363,14],[468,14],[496,15],[495,14],[142,16],[143,16],[144,17],[99,18],[145,19],[146,20],[147,21],[94,14],[97,22],[95,14],[96,14],[148,23],[149,24],[150,25],[151,26],[152,27],[153,28],[154,28],[155,29],[156,30],[157,31],[158,32],[100,14],[98,14],[159,33],[160,34],[161,35],[193,36],[162,37],[163,38],[164,39],[165,40],[166,41],[167,42],[168,43],[169,44],[170,45],[171,46],[172,46],[173,47],[174,14],[175,48],[177,49],[176,50],[178,51],[179,52],[180,53],[181,54],[182,55],[183,56],[184,57],[185,58],[186,59],[187,60],[188,61],[189,62],[190,63],[101,14],[102,14],[103,14],[141,64],[191,65],[192,66],[86,14],[198,67],[199,68],[197,69],[195,70],[196,71],[84,14],[87,72],[286,69],[843,14],[844,14],[519,14],[437,14],[85,14],[642,73],[621,74],[718,14],[622,75],[558,73],[559,14],[560,14],[561,14],[562,14],[563,14],[564,14],[565,14],[566,14],[567,14],[568,14],[569,14],[570,73],[571,73],[572,14],[573,14],[574,14],[575,14],[576,14],[577,14],[578,14],[579,14],[580,14],[582,14],[581,14],[583,14],[584,14],[585,73],[586,14],[587,14],[588,73],[589,14],[590,14],[591,73],[592,14],[593,73],[594,73],[595,73],[596,14],[597,73],[598,73],[599,73],[600,73],[601,73],[603,73],[604,14],[605,14],[602,73],[606,73],[607,14],[608,14],[609,14],[610,14],[611,14],[612,14],[613,14],[614,14],[615,14],[616,14],[617,14],[618,73],[619,14],[620,14],[623,76],[624,73],[625,73],[626,77],[627,78],[628,73],[629,73],[630,73],[631,73],[634,73],[632,14],[633,14],[556,14],[635,14],[636,14],[637,14],[638,14],[639,14],[640,14],[641,14],[643,79],[644,14],[645,14],[646,14],[648,14],[647,14],[649,14],[650,14],[651,14],[652,73],[653,14],[654,14],[655,14],[656,14],[657,73],[658,73],[660,73],[659,73],[661,14],[662,14],[663,14],[664,14],[811,80],[665,73],[666,73],[667,14],[668,14],[669,14],[670,14],[671,14],[672,14],[673,14],[674,14],[675,14],[676,14],[677,14],[678,14],[679,73],[680,14],[681,14],[682,14],[683,14],[684,14],[685,14],[686,14],[687,14],[688,14],[689,14],[690,73],[691,14],[692,14],[693,14],[694,14],[695,14],[696,14],[697,14],[698,14],[699,14],[700,73],[701,14],[702,14],[703,14],[704,14],[705,14],[706,14],[707,14],[708,14],[709,73],[710,14],[711,14],[712,14],[713,14],[714,14],[715,14],[716,73],[717,14],[719,81],[555,73],[720,14],[721,73],[722,14],[723,14],[724,14],[725,14],[726,14],[727,14],[728,14],[729,14],[730,14],[731,73],[732,14],[733,14],[734,14],[735,14],[736,14],[737,14],[738,14],[743,82],[741,83],[742,84],[740,85],[739,73],[744,14],[745,14],[746,73],[747,14],[748,14],[749,14],[750,14],[751,14],[752,14],[753,14],[754,14],[755,14],[756,73],[757,73],[758,14],[759,14],[760,14],[761,73],[762,14],[763,73],[764,14],[765,79],[766,14],[767,14],[768,14],[769,14],[770,14],[771,14],[772,14],[773,14],[774,14],[775,73],[776,73],[777,14],[778,14],[779,14],[780,14],[781,14],[782,14],[783,14],[784,14],[785,14],[786,14],[787,14],[788,14],[789,73],[790,73],[791,14],[792,14],[793,73],[794,14],[795,14],[796,14],[797,14],[798,14],[799,14],[800,14],[801,14],[802,14],[803,14],[804,14],[805,14],[806,73],[557,86],[807,14],[808,14],[809,14],[810,14],[436,87],[537,14],[536,14],[535,88],[538,89],[534,90],[448,14],[438,91],[439,92],[465,93],[440,94],[441,95],[442,96],[443,97],[444,98],[445,99],[446,100],[447,101],[466,102],[450,103],[463,104],[462,14],[449,105],[451,106],[452,107],[453,108],[454,109],[455,110],[456,111],[457,112],[458,113],[459,114],[460,115],[461,116],[464,117],[93,118],[366,119],[370,120],[372,121],[219,122],[233,123],[337,124],[265,14],[340,125],[301,126],[310,127],[338,128],[220,129],[264,14],[266,130],[339,131],[240,132],[221,133],[245,132],[234,132],[204,132],[292,134],[293,135],[209,14],[289,136],[294,137],[381,138],[287,137],[382,139],[271,14],[290,140],[394,141],[393,142],[296,137],[392,14],[390,14],[391,143],[291,69],[278,144],[279,145],[288,146],[305,147],[306,148],[295,149],[273,150],[274,151],[385,152],[388,153],[252,154],[251,155],[250,156],[397,69],[249,157],[225,14],[400,14],[403,14],[402,69],[404,158],[200,14],[331,14],[232,159],[202,160],[354,14],[355,14],[357,14],[360,161],[356,14],[358,162],[359,162],[218,14],[231,14],[365,163],[373,164],[377,165],[214,166],[281,167],[280,14],[272,150],[300,168],[298,169],[297,14],[299,14],[304,170],[276,171],[213,172],[238,173],[328,174],[205,175],[212,176],[201,124],[342,177],[352,178],[341,14],[351,179],[239,14],[223,180],[319,181],[318,14],[325,182],[327,183],[320,184],[324,185],[326,182],[323,184],[322,182],[321,184],[261,186],[246,186],[313,187],[247,187],[207,188],[206,14],[317,189],[316,190],[315,191],[314,192],[208,193],[285,194],[302,195],[284,196],[309,197],[311,198],[308,196],[241,193],[194,14],[329,199],[267,200],[303,14],[350,201],[270,202],[345,203],[211,14],[346,204],[348,205],[349,206],[332,14],[344,175],[243,207],[330,208],[353,209],[215,14],[217,14],[222,210],[312,211],[210,212],[216,14],[269,213],[268,214],[224,215],[277,216],[275,217],[226,218],[228,219],[401,14],[227,220],[229,221],[368,14],[367,14],[369,14],[399,14],[230,222],[283,69],[92,14],[307,223],[253,14],[263,224],[242,14],[375,69],[384,225],[260,69],[379,137],[259,226],[362,227],[258,225],[203,14],[386,228],[256,69],[257,69],[248,14],[262,14],[255,229],[254,230],[244,231],[237,149],[347,14],[236,232],[235,14],[371,14],[282,69],[364,233],[83,14],[91,234],[88,69],[89,14],[90,14],[343,235],[336,236],[335,14],[334,237],[333,14],[374,238],[376,239],[378,240],[380,241],[383,242],[409,243],[387,243],[408,244],[389,245],[395,246],[396,247],[398,248],[405,249],[407,14],[406,250],[361,251],[427,252],[425,253],[426,254],[414,255],[415,253],[422,256],[413,257],[418,258],[428,14],[419,259],[424,260],[430,261],[429,262],[412,263],[420,264],[421,265],[416,266],[423,252],[417,267],[411,14],[433,268],[432,14],[431,14],[434,269],[81,14],[82,14],[13,14],[14,14],[16,14],[15,14],[2,14],[17,14],[18,14],[19,14],[20,14],[21,14],[22,14],[23,14],[24,14],[3,14],[25,14],[26,14],[4,14],[27,14],[31,14],[28,14],[29,14],[30,14],[32,14],[33,14],[34,14],[5,14],[35,14],[36,14],[37,14],[38,14],[6,14],[42,14],[39,14],[40,14],[41,14],[43,14],[7,14],[44,14],[49,14],[50,14],[45,14],[46,14],[47,14],[48,14],[8,14],[54,14],[51,14],[52,14],[53,14],[55,14],[9,14],[56,14],[57,14],[58,14],[60,14],[59,14],[61,14],[62,14],[10,14],[63,14],[64,14],[65,14],[11,14],[66,14],[67,14],[68,14],[69,14],[70,14],[1,14],[71,14],[72,14],[12,14],[76,14],[74,14],[79,14],[78,14],[73,14],[77,14],[75,14],[80,14],[119,270],[129,271],[118,270],[139,272],[110,273],[109,274],[138,250],[132,275],[137,276],[112,277],[126,278],[111,279],[135,280],[107,281],[106,250],[136,282],[108,283],[113,284],[114,14],[117,284],[104,14],[140,285],[130,286],[121,287],[122,288],[124,289],[120,290],[123,291],[133,250],[115,292],[116,293],[125,294],[105,295],[128,286],[127,284],[131,14],[134,296],[493,297],[485,298],[492,299],[487,14],[488,14],[486,300],[489,301],[480,14],[481,14],[482,297],[484,302],[490,14],[491,303],[483,304],[478,305],[479,306],[548,307],[814,308],[815,307],[816,309],[818,310],[819,307],[820,311],[821,307],[501,312],[502,313],[503,314],[504,315],[506,313],[505,313],[508,316],[510,317],[511,318],[512,319],[513,320],[514,321],[515,322],[516,322],[518,323],[521,324],[522,325],[524,326],[523,327],[526,328],[525,328],[527,329],[528,330],[530,331],[529,319],[531,317],[544,332],[823,333],[545,334],[824,335],[825,333],[830,336],[812,337],[554,338],[550,14],[549,338],[553,339],[551,14],[552,14],[813,338],[828,338],[829,14],[826,338],[827,14],[817,69],[547,340],[546,14],[543,69],[822,14],[533,341],[532,14],[539,342],[540,14],[542,343],[499,344],[467,14],[497,345],[498,346],[470,14],[477,347],[473,14],[474,14],[517,14],[471,14],[475,14],[472,14],[469,348],[494,14],[520,349],[507,14],[500,350],[509,351],[476,14],[541,14],[435,352]],"affectedFilesPendingEmit":[832,833,834,835,836,837,838,839,840,831,841,842,478,479,548,814,815,816,818,819,820,821,501,502,503,504,506,505,508,510,511,512,513,514,515,516,518,521,522,524,523,526,525,527,528,530,529,531,544,823,545,824,825,830,812,554,550,549,553,551,552,813,828,829,826,827,817,547,546,543,822,533,532,539,540,542,499,467,497,498,470,477,473,474,517,471,475,472,469,494,520,507,500,509,476,541,435],"version":"5.9.3"} \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..7f974ca --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "vitest/config"; +import path from "path"; + +export default defineConfig({ + resolve: { + alias: { "@": path.resolve(__dirname, "src") }, + }, + test: { + environment: "node", + include: ["tests/**/*.test.ts"], + globalSetup: ["tests/globalSetup.ts"], + setupFiles: ["tests/setup.ts"], + // Route handlers share one cached mongoose connection per worker, so + // run files sequentially against the single in-memory server. + fileParallelism: false, + testTimeout: 30_000, + hookTimeout: 120_000, + }, +});