From 33ef04fc0ed0c93054fb7e0688845ae3c3b23f99 Mon Sep 17 00:00:00 2001 From: Krishna Agarwal Date: Tue, 31 Mar 2026 12:59:45 +0800 Subject: [PATCH 01/11] Add modulemapper to tinyfish-cookbook --- modulemapper/.env.example | 2 + modulemapper/.gitignore | 4 + modulemapper/next-env.d.ts | 5 + modulemapper/next.config.js | 3 + modulemapper/package-lock.json | 943 +++++++++++++++++++ modulemapper/package.json | 21 + modulemapper/readme.md | 139 +++ modulemapper/src/app/api/discover/route.ts | 74 ++ modulemapper/src/app/api/scrape/route.ts | 230 +++++ modulemapper/src/app/api/synthesise/route.ts | 96 ++ modulemapper/src/app/globals.css | 54 ++ modulemapper/src/app/layout.tsx | 20 + modulemapper/src/app/page.tsx | 374 ++++++++ modulemapper/src/lib/types.ts | 44 + modulemapper/src/lib/universities.ts | 160 ++++ modulemapper/tsconfig.json | 21 + modulemapper/tsconfig.tsbuildinfo | 1 + modulemapper/vercel.json | 3 + 18 files changed, 2194 insertions(+) create mode 100644 modulemapper/.env.example create mode 100644 modulemapper/.gitignore create mode 100644 modulemapper/next-env.d.ts create mode 100644 modulemapper/next.config.js create mode 100644 modulemapper/package-lock.json create mode 100644 modulemapper/package.json create mode 100644 modulemapper/readme.md create mode 100644 modulemapper/src/app/api/discover/route.ts create mode 100644 modulemapper/src/app/api/scrape/route.ts create mode 100644 modulemapper/src/app/api/synthesise/route.ts create mode 100644 modulemapper/src/app/globals.css create mode 100644 modulemapper/src/app/layout.tsx create mode 100644 modulemapper/src/app/page.tsx create mode 100644 modulemapper/src/lib/types.ts create mode 100644 modulemapper/src/lib/universities.ts create mode 100644 modulemapper/tsconfig.json create mode 100644 modulemapper/tsconfig.tsbuildinfo create mode 100644 modulemapper/vercel.json diff --git a/modulemapper/.env.example b/modulemapper/.env.example new file mode 100644 index 000000000..7d6f2b94f --- /dev/null +++ b/modulemapper/.env.example @@ -0,0 +1,2 @@ +TINYFISH_API_KEY=your_tinyfish_key_here +GROQ_API_KEY=your_groq_key_here diff --git a/modulemapper/.gitignore b/modulemapper/.gitignore new file mode 100644 index 000000000..82e4bad80 --- /dev/null +++ b/modulemapper/.gitignore @@ -0,0 +1,4 @@ +.env.local +.env +node_modules +.next diff --git a/modulemapper/next-env.d.ts b/modulemapper/next-env.d.ts new file mode 100644 index 000000000..1b3be0840 --- /dev/null +++ b/modulemapper/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/modulemapper/next.config.js b/modulemapper/next.config.js new file mode 100644 index 000000000..d10837f26 --- /dev/null +++ b/modulemapper/next.config.js @@ -0,0 +1,3 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} +module.exports = nextConfig diff --git a/modulemapper/package-lock.json b/modulemapper/package-lock.json new file mode 100644 index 000000000..04c99938a --- /dev/null +++ b/modulemapper/package-lock.json @@ -0,0 +1,943 @@ +{ + "name": "modulemapper", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "modulemapper", + "version": "0.1.0", + "dependencies": { + "next": "15.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.0.tgz", + "integrity": "sha512-UcCO481cROsqJuszPPXJnb7GGuLq617ve4xuAyyNG4VSSocJNtMU5Fsx+Lp6mlN8c7W58aZLc5y6D/2xNmaK+w==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.0.tgz", + "integrity": "sha512-ZU8d7xxpX14uIaFC3nsr4L++5ZS/AkWDm1PzPO6gD9xWhFkOj2hzSbSIxoncsnlJXB1CbLOfGVN4Zk9tg83PUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.0.tgz", + "integrity": "sha512-DQ3RiUoW2XC9FcSM4ffpfndq1EsLV0fj0/UY33i7eklW5akPUCo6OX2qkcLXZ3jyPdo4sf2flwAED3AAq3Om2Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.0.tgz", + "integrity": "sha512-M+vhTovRS2F//LMx9KtxbkWk627l5Q7AqXWWWrfIzNIaUFiz2/NkOFkxCFyNyGACi5YbA8aekzCLtbDyfF/v5Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.0.tgz", + "integrity": "sha512-Qn6vOuwaTCx3pNwygpSGtdIu0TfS1KiaYLYXLH5zq1scoTXdwYfdZtwvJTpB1WrLgiQE2Ne2kt8MZok3HlFqmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.0.tgz", + "integrity": "sha512-yeNh9ofMqzOZ5yTOk+2rwncBzucc6a1lyqtg8xZv0rH5znyjxHOWsoUtSq4cUTeeBIiXXX51QOOe+VoCjdXJRw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.0.tgz", + "integrity": "sha512-t9IfNkHQs/uKgPoyEtU912MG6a1j7Had37cSUyLTKx9MnUpjj+ZDKw9OyqTI9OwIIv0wmkr1pkZy+3T5pxhJPg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.0.tgz", + "integrity": "sha512-WEAoHyG14t5sTavZa1c6BnOIEukll9iqFRTavqRVPfYmfegOAd5MaZfXgOGG6kGo1RduyGdTHD4+YZQSdsNZXg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.0.tgz", + "integrity": "sha512-J1YdKuJv9xcixzXR24Dv+4SaDKc2jj31IVUEMdO5xJivMTXuE6MAdIi4qPjSymHuFG8O5wbfWKnhJUcHHpj5CA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001781", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "optional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/next/-/next-15.1.0.tgz", + "integrity": "sha512-QKhzt6Y8rgLNlj30izdMbxAwjHMFANnLwDwZ+WQh5sMhyt4lEBqDK9QpvWHtIM4rINKPoJ8aiRZKg5ULSybVHw==", + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details.", + "license": "MIT", + "dependencies": { + "@next/env": "15.1.0", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.1.0", + "@next/swc-darwin-x64": "15.1.0", + "@next/swc-linux-arm64-gnu": "15.1.0", + "@next/swc-linux-arm64-musl": "15.1.0", + "@next/swc-linux-x64-gnu": "15.1.0", + "@next/swc-linux-x64-musl": "15.1.0", + "@next/swc-win32-arm64-msvc": "15.1.0", + "@next/swc-win32-x64-msvc": "15.1.0", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/modulemapper/package.json b/modulemapper/package.json new file mode 100644 index 000000000..508fab119 --- /dev/null +++ b/modulemapper/package.json @@ -0,0 +1,21 @@ +{ + "name": "modulemapper", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "15.3.1", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5" + } +} diff --git a/modulemapper/readme.md b/modulemapper/readme.md new file mode 100644 index 000000000..9c97559ee --- /dev/null +++ b/modulemapper/readme.md @@ -0,0 +1,139 @@ +# ModuleMapper + +**Real student reviews for any university course, instantly.** + +ModuleMapper lets you look up any course at any university and get a structured, AI-synthesised verdict based on live student reviews scraped from Reddit, RateMyProfessors, university course platforms, and student blogs — all in real time. + +--- + +## What it does + +Type in a course code (e.g. `BT1101`) and a university (e.g. `NUS`) and ModuleMapper will: + +1. **Discover** the right sources for that university in real-time — subreddits, course review platforms like NUSMods or Bruinwalk, the official course catalog page +2. **Scrape** all sources concurrently using parallel TinyFish web agents, streaming live progress back to you as it runs +3. **Synthesise** everything with an LLM into a structured verdict +4. **Display** a clean dashboard with score, difficulty, workload, student quotes, exam tips, grading patterns, and more + +--- + +## Architecture +``` +User Input (course code + university) + │ + ▼ +┌─────────────────────────────────────┐ +│ /api/discover │ +│ Groq LLM figures out in real-time: │ +│ - Which subreddits to search │ +│ - Course platform URL (NUSMods, │ +│ Bruinwalk, Carta, etc.) │ +│ - Official course catalog URL │ +└──────────────┬──────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ /api/scrape │ +│ Spawns N TinyFish agents in │ +│ parallel, streams SSE progress: │ +│ │ +│ ┌─────────────┐ ┌───────────────┐ │ +│ │ RateMyProf │ │ r/nus │ │ +│ └─────────────┘ └───────────────┘ │ +│ ┌─────────────┐ ┌───────────────┐ │ +│ │ NUSMods │ │ Student blogs │ │ +│ └─────────────┘ └───────────────┘ │ +└──────────────┬──────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ /api/synthesise │ +│ Groq LLM analyses all raw data │ +│ → structured JSON verdict │ +└──────────────┬──────────────────────┘ + │ + ▼ + Next.js Frontend + (score, reviews, tags, + difficulty, workload…) +``` + +--- + +## Tech Stack + +| Layer | Technology | +|---|---| +| Framework | Next.js 15 (App Router) | +| Language | TypeScript | +| Web scraping | TinyFish Web Agent API | +| LLM (discover + synthesise) | Groq — `llama-3.3-70b-versatile` | +| Streaming | Server-Sent Events (SSE) | +| Styling | Inline CSS with CSS variables | +| Deployment | Vercel | + +--- + +## How to run locally + +**1. Clone the repo** +```bash +git clone https://github.com/YOUR_USERNAME/modulemapper.git +cd modulemapper +``` + +**2. Install dependencies** +```bash +npm install +``` + +**3. Set up environment variables** + +Create a `.env.local` file: +``` +TINYFISH_API_KEY=your_tinyfish_key_here +GROQ_API_KEY=your_groq_key_here +``` + +- Get a TinyFish key (500 free steps, no credit card): https://agent.tinyfish.ai/api-keys +- Get a Groq key (free): https://console.groq.com + +**4. Run the dev server** +```bash +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) + +--- + +## How to use + +1. Enter a **course code** — e.g. `BT1101`, `CS50`, `MATH101` +2. Enter a **university** — e.g. `NUS`, `Harvard`, `MIT` +3. Click **Analyse** +4. Watch the agents run live, then read your verdict + +Works for any university worldwide. + +--- + +## Environment Variables + +| Variable | Description | +|---|---| +| `TINYFISH_API_KEY` | TinyFish Web Agent API key for scraping | +| `GROQ_API_KEY` | Groq API key for LLM inference | + +--- + +## Claude Skill + +A Claude skill version of ModuleMapper is available — it does the same thing directly inside Claude without needing the web app. + +Install: download `modulemapper.skill` from [Releases](../../releases) and upload to **Claude.ai → Settings → Skills** + +Or via CLI: +```bash +npx skills add KrishnaAgarwal7531/skills- --skill modulemapper +``` diff --git a/modulemapper/src/app/api/discover/route.ts b/modulemapper/src/app/api/discover/route.ts new file mode 100644 index 000000000..e60dce3e4 --- /dev/null +++ b/modulemapper/src/app/api/discover/route.ts @@ -0,0 +1,74 @@ +import { NextRequest } from 'next/server' + +export const runtime = 'nodejs' + +const GROQ_API = 'https://api.groq.com/openai/v1/chat/completions' +const GROQ_KEY = process.env.GROQ_API_KEY! + +export async function GET(req: NextRequest) { + const code = req.nextUrl.searchParams.get('code')?.trim().toUpperCase() + const university = req.nextUrl.searchParams.get('university')?.trim() + + if (!code || !university) { + return Response.json({ error: 'Missing code or university' }, { status: 400 }) + } + + const prompt = `You are a university course research assistant. Given a university and course code, return the best sources to scrape for student reviews. + +University: ${university} +Course code: ${code} + +Return ONLY valid JSON (no markdown, no explanation): +{ + "title": "", + "subreddits": ["", ""], + "courseplatformUrl": "", + "courseplatformName": "", + "officialUrl": "", + "rmpQuery": "${code} ${university}", + "blogQuery": "${code} ${university} course review" +} + +Rules: +- Only include URLs you are confident are real and specific to this course. Use null if unsure — do not hallucinate URLs. +- subreddits[0] = university's own sub (e.g. "nus", "berkeley", "uoft"). subreddits[1] = best regional/general academic sub.` + + try { + const response = await fetch(GROQ_API, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${GROQ_KEY}` + }, + body: JSON.stringify({ + model: 'llama-3.3-70b-versatile', + messages: [{ role: 'user', content: prompt }], + temperature: 0.1, + max_tokens: 400 + }) + }) + + if (!response.ok) throw new Error('Groq failed') + + const data = await response.json() + const text = data.choices?.[0]?.message?.content || '' + const clean = text.replace(/```json|```/g, '').trim() + const parsed = JSON.parse(clean) + + return Response.json({ code, university, ...parsed }) + } catch { + // Safe fallback if LLM call fails + const uniSlug = university.toLowerCase().replace(/\s+/g, '') + return Response.json({ + code, + university, + title: code, + subreddits: [uniSlug, 'college'], + courseplatformUrl: null, + courseplatformName: null, + officialUrl: null, + rmpQuery: `${code} ${university}`, + blogQuery: `${code} ${university} course review` + }) + } +} diff --git a/modulemapper/src/app/api/scrape/route.ts b/modulemapper/src/app/api/scrape/route.ts new file mode 100644 index 000000000..2ff0e59a4 --- /dev/null +++ b/modulemapper/src/app/api/scrape/route.ts @@ -0,0 +1,230 @@ +import { NextRequest } from 'next/server' + +export const runtime = 'nodejs' + +const TINYFISH_ENDPOINT = 'https://agent.tinyfish.ai/v1/automation/run-sse' +const TINYFISH_KEY = process.env.TINYFISH_API_KEY! + +interface AgentConfig { + id: string + source: string + url: string + goal: string +} + +function buildAgents(params: { + code: string + university: string + subreddits: string[] + courseplatformUrl: string | null + courseplatformName: string | null + officialUrl: string | null + rmpQuery: string + blogQuery: string +}): AgentConfig[] { + const agents: AgentConfig[] = [] + + // Rate My Professors — find professors for this course, extract ratings + reviews + agents.push({ + id: 'rmp', + source: 'Rate My Professor', + url: `https://www.ratemyprofessors.com/search/professors?q=${encodeURIComponent(params.rmpQuery)}`, + goal: `Extract professor reviews for ${params.code} at ${params.university}. + +You are on the search results page. Do this efficiently: +1. Look at the professors listed. Only click into professors who clearly teach ${params.code} or its department. +2. For each relevant professor (max 3), read their ratings and the written reviews visible on their profile page. Do NOT paginate or load more — just read what is immediately visible. +3. Return immediately as JSON: +{ + "professors": [ + { "name": "...", "overallRating": 4.2, "difficultyRating": 3.1, "reviews": ["review text", ...] } + ] +} + +Stay focused. Do not explore unrelated professors or pages.` + }) + + // Reddit — one agent per subreddit, max 2 + for (let i = 0; i < Math.min(params.subreddits.length, 2); i++) { + const sub = params.subreddits[i] + agents.push({ + id: `reddit_${sub}`, + source: `r/${sub}`, + url: `https://www.reddit.com/r/${sub}/search/?q=${encodeURIComponent(params.code)}&sort=relevance&t=all`, + goal: `Extract student reviews of ${params.code} at ${params.university} from this Reddit search page. + +You are already on the search results. Do this efficiently: +1. Scan the post titles on this page. Identify posts that are specifically about ${params.code} (reviews, advice, "is it worth it", experience posts). Ignore unrelated posts entirely. +2. Click into the 2 most relevant posts only. Read the post body and the top 5-8 comments. Do NOT scroll endlessly or load more comments. +3. Extract key info: workload, difficulty, grading, exam tips, professor mentions, overall recommendation. +4. Return immediately as JSON: +{ + "reviews": ["student quote or paraphrase with context", ...], + "workloadMentions": ["..."], + "examTips": ["..."], + "professorMentions": ["..."], + "gradingInfo": ["..."] +} + +Be precise. 2 posts maximum. Do not click anything unrelated.` + }) + } + + // Course platform (NUSMods, Bruinwalk, etc.) — just read what's on the page + if (params.courseplatformUrl && params.courseplatformName) { + agents.push({ + id: 'platform', + source: params.courseplatformName, + url: params.courseplatformUrl, + goal: `Extract course reviews and ratings for ${params.code} from this page. + +You are already on the course page. Read what is visible: +- Overall rating, workload rating, difficulty rating (numbers) +- All written student reviews shown on this page + +Do NOT navigate away. Do NOT click into individual reviews if they require separate page loads — just extract what is visible here. + +Return as JSON: +{ "overallRating": 4.1, "workloadRating": 3.5, "difficultyRating": 3.8, "reviews": ["...", ...] }` + }) + } + + // Official course page — just read the description, no navigation + if (params.officialUrl) { + agents.push({ + id: 'official', + source: 'Official course page', + url: params.officialUrl, + goal: `Extract the official course info for ${params.code} from this page. + +You are already on the page. Read only what is visible here — do NOT navigate elsewhere. +Extract: course title, description, learning outcomes, topics, prerequisites, assessment breakdown (exam %, CA %, project %). + +Return as JSON: +{ "title": "...", "description": "...", "learningOutcomes": ["..."], "topics": ["..."], "prerequisites": "...", "assessmentBreakdown": "..." }` + }) + } + + // Student blogs — Google search, try for up to 3 relevant articles + agents.push({ + id: 'blogs', + source: 'Student blogs', + url: `https://www.google.com/search?q=${encodeURIComponent(params.blogQuery)}`, + goal: `Find student blog reviews of ${params.code} at ${params.university}. + +You are on Google search results. Do this efficiently: +1. Scan the results. Click any result whose title/snippet clearly indicates it is a personal student review or experience post about ${params.code}. Try to find up to 3 such articles — if fewer exist, that is fine. +2. On each article, read only the main content. Extract the student's verdict, workload comments, exam tips, and recommendation. +3. Return as JSON: +{ + "reviews": ["detailed paraphrase of student experience and advice", ...], + "source_urls": ["url1", ...] +} + +If no results look relevant at all, return { "reviews": [], "source_urls": [] } immediately. Do not guess or click unrelated links.` + }) + + return agents +} + +async function runTinyFishAgent(agent: AgentConfig): Promise<{ source: string; raw: string; error?: string }> { + try { + const response = await fetch(TINYFISH_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': TINYFISH_KEY + }, + body: JSON.stringify({ + url: agent.url, + goal: agent.goal, + browser_profile: 'stealth' + }) + }) + + if (!response.ok) { + const errText = await response.text() + return { source: agent.source, raw: '', error: `HTTP ${response.status}: ${errText}` } + } + + const reader = response.body?.getReader() + if (!reader) return { source: agent.source, raw: '', error: 'No stream' } + + const decoder = new TextDecoder() + let buffer = '' + let finalResult = '' + + while (true) { + const { done, value } = await reader.read() + if (done) break + + buffer += decoder.decode(value, { stream: true }) + const lines = buffer.split('\n') + buffer = lines.pop() || '' + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || !trimmed.startsWith('data:')) continue + const data = trimmed.slice(5).trim() + if (!data || data === '[DONE]') continue + + try { + const parsed = JSON.parse(data) + if (parsed.type === 'COMPLETE' && parsed.result) { + finalResult = typeof parsed.result === 'string' + ? parsed.result + : JSON.stringify(parsed.result) + } else if (parsed.type === 'COMPLETE' && parsed.status === 'COMPLETED') { + finalResult = finalResult || 'completed' + } + } catch { /* skip malformed lines */ } + } + } + + if (!finalResult) { + return { source: agent.source, raw: '', error: 'No result returned from agent' } + } + + return { source: agent.source, raw: finalResult } + } catch (err) { + return { source: agent.source, raw: '', error: String(err) } + } +} + +export async function POST(req: NextRequest) { + const body = await req.json() + const { code, university, subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery } = body + + const agents = buildAgents({ code, university, subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery }) + + const encoder = new TextEncoder() + + const stream = new ReadableStream({ + async start(controller) { + const send = (data: object) => { + controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) + } + + send({ type: 'agents', agents: agents.map(a => ({ id: a.id, source: a.source })) }) + + const promises = agents.map(async (agent) => { + send({ type: 'agent_start', id: agent.id, source: agent.source }) + const result = await runTinyFishAgent(agent) + send({ type: 'agent_done', id: agent.id, source: agent.source, raw: result.raw, error: result.error }) + return result + }) + + const results = await Promise.all(promises) + send({ type: 'all_done', results }) + controller.close() + } + }) + + return new Response(stream, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + } + }) +} diff --git a/modulemapper/src/app/api/synthesise/route.ts b/modulemapper/src/app/api/synthesise/route.ts new file mode 100644 index 000000000..c88aade6c --- /dev/null +++ b/modulemapper/src/app/api/synthesise/route.ts @@ -0,0 +1,96 @@ +import { NextRequest } from 'next/server' + +export const runtime = 'nodejs' + +const GROQ_API = 'https://api.groq.com/openai/v1/chat/completions' +const GROQ_KEY = process.env.GROQ_API_KEY! + +export async function POST(req: NextRequest) { + const { code, university, results } = await req.json() + + const rawDataText = results + .filter((r: { raw: string; error?: string }) => r.raw && !r.error) + .map((r: { source: string; raw: string }) => `=== SOURCE: ${r.source} ===\n${r.raw}`) + .join('\n\n') + + if (!rawDataText.trim()) { + return Response.json({ error: 'No data scraped' }, { status: 400 }) + } + + const prompt = `You are an expert at analysing student course reviews. Analyse the following scraped data about the course ${code} at ${university} and return a structured JSON verdict. + +The data may include Reddit posts with fields like "reviews", "workloadMentions", "examTips", "professorMentions", "gradingInfo" — use ALL of these fields when building your verdict. + +SCRAPED DATA: +${rawDataText.slice(0, 14000)} + +Return ONLY valid JSON (no markdown, no explanation) with this exact structure: +{ + "score": , + "verdict": , + "summary": <2-3 sentence AI-written paragraph summarising the course experience>, + "difficulty": , + "workload": , + "hoursPerWeek": , + "hasExam": , + "examDifficulty": , + "averageGrade": , + "gradingPattern": , + "assessment": , + "attendance": , + "whatYouLearn": , + "tags": [ + {"label": , "color": <"blue"|"green"|"amber"|"red">} + ], + "bestFor": , + "notGreatIf": , + "reviews": [ + { + "text": , + "source": , + "sentiment": <"positive"|"negative"|"mixed">, + "date": + } + ], + "sourceCounts": { + : + } +} + +Rules: +- score reflects genuine student sentiment (not just your opinion) +- Extract real student quotes for reviews, at least 8 if available +- whatYouLearn should come from the official course page if available +- tags: blue=general info, green=positive trait, amber=neutral/warning, red=negative +- If data is insufficient for a field, use sensible defaults or "Unknown"` + + const response = await fetch(GROQ_API, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${GROQ_KEY}` + }, + body: JSON.stringify({ + model: 'llama-3.3-70b-versatile', + messages: [{ role: 'user', content: prompt }], + temperature: 0.3, + max_tokens: 3000 + }) + }) + + if (!response.ok) { + const err = await response.text() + return Response.json({ error: `Groq error: ${err}` }, { status: 500 }) + } + + const data = await response.json() + const text = data.choices?.[0]?.message?.content || '' + + try { + const clean = text.replace(/```json|```/g, '').trim() + const parsed = JSON.parse(clean) + return Response.json(parsed) + } catch { + return Response.json({ error: 'Failed to parse Groq response', raw: text }, { status: 500 }) + } +} diff --git a/modulemapper/src/app/globals.css b/modulemapper/src/app/globals.css new file mode 100644 index 000000000..4cbcd8818 --- /dev/null +++ b/modulemapper/src/app/globals.css @@ -0,0 +1,54 @@ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + --blue: #185FA5; + --blue-light: #E6F1FB; + --blue-mid: #378ADD; + --blue-dark: #0C447C; + --green-light: #EAF3DE; + --green-dark: #27500A; + --amber-light: #FAEEDA; + --amber-dark: #633806; + --red-light: #FCEBEB; + --red-dark: #791F1F; + --gray-bg: #F7F8FA; + --gray-border: #E2E6EC; + --text-primary: #0F1923; + --text-secondary: #6B7685; + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; +} + +body { + font-family: 'DM Sans', sans-serif; + background: var(--gray-bg); + color: var(--text-primary); + min-height: 100vh; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.35; } +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes shimmer { + 0% { background-position: -600px 0; } + 100% { background-position: 600px 0; } +} + +.animate-in { + animation: fadeIn 0.4s ease forwards; +} + +.skeleton { + background: linear-gradient(90deg, #e8edf2 25%, #f0f4f8 50%, #e8edf2 75%); + background-size: 600px 100%; + animation: shimmer 1.4s infinite; + border-radius: var(--radius-sm); +} diff --git a/modulemapper/src/app/layout.tsx b/modulemapper/src/app/layout.tsx new file mode 100644 index 000000000..16300cf37 --- /dev/null +++ b/modulemapper/src/app/layout.tsx @@ -0,0 +1,20 @@ +import type { Metadata } from 'next' +import './globals.css' + +export const metadata: Metadata = { + title: 'ModuleMapper — Real student reviews, every university', + description: 'Paste any course code and university. Get real student reviews, workload reports, grading patterns, and professor feedback in one place.', +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + {children} + + ) +} diff --git a/modulemapper/src/app/page.tsx b/modulemapper/src/app/page.tsx new file mode 100644 index 000000000..98d5edd90 --- /dev/null +++ b/modulemapper/src/app/page.tsx @@ -0,0 +1,374 @@ +'use client' +import { useState, useRef, useEffect } from 'react' +import type { CourseVerdict, ReviewCard } from '@/lib/types' + +interface Agent { + id: string + source: string + status: 'waiting' | 'running' | 'done' | 'error' + statusText?: string +} + +type AppState = 'idle' | 'discovering' | 'scraping' | 'synthesising' | 'done' | 'error' + +export default function Home() { + const [code, setCode] = useState('') + const [university, setUniversity] = useState('') + const [appState, setAppState] = useState('idle') + const [agents, setAgents] = useState([]) + const [verdict, setVerdict] = useState(null) + const [error, setError] = useState('') + const [showAllReviews, setShowAllReviews] = useState(false) + const [discoveryData, setDiscoveryData] = useState | null>(null) + const abortRef = useRef(null) + + async function handleAnalyse() { + if (!code.trim() || !university.trim()) return + setError('') + setVerdict(null) + setAgents([]) + setShowAllReviews(false) + setAppState('discovering') + + try { + const discRes = await fetch(`/api/discover?code=${encodeURIComponent(code.trim().toUpperCase())}&university=${encodeURIComponent(university.trim())}`) + const disc = await discRes.json() + if (disc.error) throw new Error(disc.error) + setDiscoveryData(disc) + setAppState('scraping') + + abortRef.current = new AbortController() + const scrapeRes = await fetch('/api/scrape', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(disc), + signal: abortRef.current.signal + }) + + if (!scrapeRes.body) throw new Error('No stream') + const reader = scrapeRes.body.getReader() + const decoder = new TextDecoder() + const allResults: { source: string; raw: string }[] = [] + let buffer = '' + + while (true) { + const { done, value } = await reader.read() + if (done) break + buffer += decoder.decode(value, { stream: true }) + const lines = buffer.split('\n') + buffer = lines.pop() || '' + + for (const line of lines) { + const trimmed = line.trim() + if (!trimmed || !trimmed.startsWith('data:')) continue + const data = trimmed.slice(5).trim() + if (data === '[DONE]') continue + try { + const event = JSON.parse(data) + if (event.type === 'agents') { + setAgents(event.agents.map((a: { id: string; source: string }) => ({ ...a, status: 'waiting' }))) + } else if (event.type === 'agent_start') { + setAgents(prev => prev.map(a => a.id === event.id ? { ...a, status: 'running', statusText: 'Scraping...' } : a)) + } else if (event.type === 'agent_done') { + setAgents(prev => prev.map(a => a.id === event.id ? { ...a, status: event.error ? 'error' : 'done', statusText: event.error ? 'Error' : 'Done' } : a)) + if (event.raw) allResults.push({ source: event.source, raw: event.raw }) + } else if (event.type === 'all_done') { + break + } + } catch { /* skip malformed */ } + } + } + + setAppState('synthesising') + const synthRes = await fetch('/api/synthesise', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ code: code.trim().toUpperCase(), university: university.trim(), results: allResults }) + }) + const synth = await synthRes.json() + if (synth.error) throw new Error(synth.error) + setVerdict(synth) + setAppState('done') + } catch (err: unknown) { + if (err instanceof Error && err.name === 'AbortError') return + setError(err instanceof Error ? err.message : 'Something went wrong') + setAppState('error') + } + } + + const displayedReviews = verdict + ? showAllReviews ? verdict.reviews : verdict.reviews.slice(0, 4) + : [] + + return ( +
+
+ +
+
+ + ModuleMapper + +
+

+ real student reviews · any university · any course +

+
+ +
+
+
+ + setCode(e.target.value)} + onKeyDown={e => e.key === 'Enter' && handleAnalyse()} + style={{ width: '100%', padding: '10px 14px', border: '0.5px solid var(--gray-border)', borderRadius: 'var(--radius-md)', fontSize: 14, background: 'var(--gray-bg)', color: 'var(--text-primary)', outline: 'none', fontFamily: "'DM Mono', monospace" }} + /> +
+
+ + setUniversity(e.target.value)} + onKeyDown={e => e.key === 'Enter' && handleAnalyse()} + style={{ width: '100%', padding: '10px 14px', border: '0.5px solid var(--gray-border)', borderRadius: 'var(--radius-md)', fontSize: 14, background: 'var(--gray-bg)', color: 'var(--text-primary)', outline: 'none' }} + /> +
+ +
+
+ + {(appState === 'scraping' || appState === 'synthesising' || appState === 'done') && agents.length > 0 && ( +
+ {agents.map(agent => ( +
+
+ {agent.source} {agent.status === 'done' ? '· done' : agent.status === 'error' ? '· error' : agent.status === 'running' ? '· scraping...' : '· waiting'} +
+ ))} + {appState === 'synthesising' && ( +
+
+ Groq is synthesising verdict... +
+ )} +
+ )} + + {appState === 'discovering' && ( +
+
+ Discovering sources for {university}... +
+ )} + + {appState === 'error' && ( +
+ {error} +
+ )} + + {verdict && appState === 'done' && ( +
+
+

+ {code.toUpperCase()} · {university} +

+

+ {(discoveryData as { title?: string })?.title || `${code.toUpperCase()} Course Review`} +

+ {verdict.sourceCounts && ( +
+ {Object.entries(verdict.sourceCounts).map(([src, count]) => ( + + {src} + + ))} +
+ )} +
+ +
+
+
+
+ {typeof verdict.score === 'number' ? verdict.score.toFixed(1) : verdict.score} +
+
+
{verdict.verdict}
+
Overall verdict out of 10
+
+
+

{verdict.summary}

+
+ {verdict.tags?.map((tag, i) => { + const colors: Record = { + blue: { bg: 'var(--blue-light)', text: 'var(--blue-dark)' }, + green: { bg: 'var(--green-light)', text: 'var(--green-dark)' }, + amber: { bg: 'var(--amber-light)', text: 'var(--amber-dark)' }, + red: { bg: 'var(--red-light)', text: 'var(--red-dark)' } + } + const c = colors[tag.color] || colors.blue + return ( + + {tag.label} + + ) + })} +
+
+ +
+
+ + +
+

{verdict.hoursPerWeek}

+
+
+ +
+ {[ + { label: 'Final exam', val: verdict.hasExam ? 'Yes' : 'No', sub: verdict.examDifficulty }, + { label: 'Average grade', val: verdict.averageGrade, sub: verdict.gradingPattern }, + { label: 'Assessment', val: verdict.assessment, sub: '' }, + { label: 'Attendance', val: verdict.attendance, sub: '' } + ].map((s, i) => ( +
+
{s.label}
+
{s.val}
+ {s.sub &&
{s.sub}
} +
+ ))} +
+ + {verdict.bestFor && ( +
+
+
Best for
+
{verdict.bestFor}
+
+
+
Not great if
+
{verdict.notGreatIf}
+
+
+ )} + + {verdict.whatYouLearn && verdict.whatYouLearn.length > 0 && ( +
+

What you will learn

+
+ {verdict.whatYouLearn.map((item, i) => ( +
+
+ {item} +
+ ))} +
+
+ )} + +

Student reviews

+
+ {displayedReviews.map((review: ReviewCard, i: number) => { + const sentColors: Record = { + positive: { bg: 'var(--green-light)', text: 'var(--green-dark)' }, + negative: { bg: 'var(--red-light)', text: 'var(--red-dark)' }, + mixed: { bg: 'var(--amber-light)', text: 'var(--amber-dark)' } + } + const sc = sentColors[review.sentiment] || sentColors.mixed + return ( +
+
+ {review.source} + {review.sentiment} +
+

"{review.text}"

+ {review.date &&

{review.date}

} +
+ ) + })} +
+ {verdict.reviews.length > 4 && ( + + )} +
+ )} +
+
+ ) +} + +function DonutChart({ value, label, color }: { value: number; label: string; color: string }) { + const canvasRef = useRef(null) + + useEffect(() => { + const canvas = canvasRef.current + if (!canvas) return + const ctx = canvas.getContext('2d') + if (!ctx) return + + const size = 90 + const cx = size / 2, cy = size / 2 + const r = 32, lineW = 10 + const pct = Math.min(Math.max(value, 0), 10) / 10 + + ctx.clearRect(0, 0, size, size) + ctx.beginPath() + ctx.arc(cx, cy, r, 0, Math.PI * 2) + ctx.strokeStyle = 'rgba(0,0,0,0.07)' + ctx.lineWidth = lineW + ctx.stroke() + + ctx.beginPath() + ctx.arc(cx, cy, r, -Math.PI / 2, -Math.PI / 2 + pct * Math.PI * 2) + ctx.strokeStyle = color + ctx.lineWidth = lineW + ctx.lineCap = 'round' + ctx.stroke() + + ctx.fillStyle = '#0F1923' + ctx.font = '500 16px DM Mono, monospace' + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillText(Math.round(value).toString(), cx, cy) + }, [value, color]) + + return ( +
+ +
{label}
+
{Math.round(value)} / 10
+
+ ) +} diff --git a/modulemapper/src/lib/types.ts b/modulemapper/src/lib/types.ts new file mode 100644 index 000000000..3cfe2d9c5 --- /dev/null +++ b/modulemapper/src/lib/types.ts @@ -0,0 +1,44 @@ +export interface DiscoveryResult { + subreddits: string[] + courseplatform: { name: string; url: string } | null + officialpage: string | null + rmp_query: string + blog_query: string +} + +export interface AgentResult { + source: string + url: string + reviews: string[] + raw_text: string + status: 'done' | 'error' | 'empty' +} + +export interface ReviewCard { + text: string + source: string + sentiment: 'positive' | 'negative' | 'mixed' + date: string +} + +export interface CourseVerdict { + score: number + verdict: string + summary: string + difficulty: number + workload: number + hoursPerWeek: string + hasExam: boolean + examDifficulty: string + averageGrade: string + gradingPattern: string + assessment: string + attendance: string + whatYouLearn: string[] + tags: { label: string; color: 'blue' | 'green' | 'amber' | 'red' }[] + bestFor: string + notGreatIf: string + reviews: ReviewCard[] + totalReviews: number + sourceCounts: Record +} diff --git a/modulemapper/src/lib/universities.ts b/modulemapper/src/lib/universities.ts new file mode 100644 index 000000000..960bc2cdb --- /dev/null +++ b/modulemapper/src/lib/universities.ts @@ -0,0 +1,160 @@ +export interface UniversityProfile { + subreddits: string[] + courseplatform: { name: string; urlTemplate: string } | null + officialTemplate: string | null + country: string +} + +const UNIVERSITY_PROFILES: Record = { + 'nus': { + subreddits: ['nus', 'SGExams', 'singapore'], + courseplatform: { name: 'NUSMods', urlTemplate: 'https://nusmods.com/modules/{code}' }, + officialTemplate: 'https://nusmods.com/modules/{code}/information', + country: 'SG' + }, + 'national university of singapore': { + subreddits: ['nus', 'SGExams', 'singapore'], + courseplatform: { name: 'NUSMods', urlTemplate: 'https://nusmods.com/modules/{code}' }, + officialTemplate: 'https://nusmods.com/modules/{code}/information', + country: 'SG' + }, + 'ntu': { + subreddits: ['ntu', 'SGExams', 'singapore'], + courseplatform: { name: 'NTU Course Review', urlTemplate: 'https://www.ntu.edu.sg/education/undergraduate-programme/courses/{code}' }, + officialTemplate: null, + country: 'SG' + }, + 'nanyang technological university': { + subreddits: ['ntu', 'SGExams', 'singapore'], + courseplatform: null, + officialTemplate: null, + country: 'SG' + }, + 'harvard': { + subreddits: ['harvard', 'ApplyingToCollege', 'college'], + courseplatform: { name: 'Harvard Course Reviews', urlTemplate: 'https://www.harvardcrimson.com/topic/courses/' }, + officialTemplate: 'https://courses.harvard.edu/search?q={code}', + country: 'US' + }, + 'mit': { + subreddits: ['mit', 'ApplyingToCollege', 'college'], + courseplatform: { name: 'Courseroad', urlTemplate: 'https://courseroad.mit.edu/' }, + officialTemplate: 'https://student.mit.edu/catalog/search.cgi?search={code}', + country: 'US' + }, + 'stanford': { + subreddits: ['stanford', 'ApplyingToCollege', 'college'], + courseplatform: { name: 'Stanford Carta', urlTemplate: 'https://carta.stanford.edu/course/{code}' }, + officialTemplate: 'https://exploredegrees.stanford.edu/search/?q={code}', + country: 'US' + }, + 'oxford': { + subreddits: ['oxford', 'UniUK', 'uniuk'], + courseplatform: null, + officialTemplate: 'https://www.ox.ac.uk/admissions/undergraduate/courses/course-listing', + country: 'UK' + }, + 'cambridge': { + subreddits: ['cambridge', 'UniUK', 'uniuk'], + courseplatform: null, + officialTemplate: 'https://www.undergraduate.study.cam.ac.uk/courses', + country: 'UK' + }, + 'imperial': { + subreddits: ['imperialcollege', 'UniUK'], + courseplatform: null, + officialTemplate: null, + country: 'UK' + }, + 'ucl': { + subreddits: ['ucl', 'UniUK'], + courseplatform: null, + officialTemplate: null, + country: 'UK' + }, + 'toronto': { + subreddits: ['uoft', 'UofT'], + courseplatform: { name: 'UofT Course Evals', urlTemplate: 'https://course-evals.utoronto.ca/' }, + officialTemplate: 'https://artsci.calendar.utoronto.ca/search-courses?course_keyword={code}', + country: 'CA' + }, + 'university of toronto': { + subreddits: ['uoft', 'UofT'], + courseplatform: { name: 'UofT Course Evals', urlTemplate: 'https://course-evals.utoronto.ca/' }, + officialTemplate: 'https://artsci.calendar.utoronto.ca/search-courses?course_keyword={code}', + country: 'CA' + }, + 'melbourne': { + subreddits: ['unimelb', 'australia'], + courseplatform: null, + officialTemplate: 'https://handbook.unimelb.edu.au/search?query={code}', + country: 'AU' + }, + 'iit': { + subreddits: ['iit', 'JEENEETards', 'india'], + courseplatform: null, + officialTemplate: null, + country: 'IN' + }, + 'nyu': { + subreddits: ['nyu', 'college'], + courseplatform: null, + officialTemplate: 'https://courses.nyu.edu/search?query={code}', + country: 'US' + }, + 'ucla': { + subreddits: ['ucla', 'college'], + courseplatform: { name: 'Bruinwalk', urlTemplate: 'https://www.bruinwalk.com/search/?q={code}' }, + officialTemplate: 'https://registrar.ucla.edu/Academics/Course-Descriptions', + country: 'US' + }, + 'uc berkeley': { + subreddits: ['berkeley', 'college'], + courseplatform: { name: 'Berkeley Course Guide', urlTemplate: 'https://guide.berkeley.edu/courses/' }, + officialTemplate: 'https://classes.berkeley.edu/search/class/?q={code}', + country: 'US' + }, + 'smu': { + subreddits: ['smusingapore', 'SGExams', 'singapore'], + courseplatform: null, + officialTemplate: null, + country: 'SG' + }, +} + +export function getUniversityProfile(university: string, courseCode: string): { + subreddits: string[] + courseplatformUrl: string | null + courseplatformName: string | null + officialUrl: string | null + rmpQuery: string + blogQuery: string +} { + const key = university.toLowerCase().trim() + let profile: UniversityProfile | null = null + + for (const [k, v] of Object.entries(UNIVERSITY_PROFILES)) { + if (key.includes(k) || k.includes(key)) { + profile = v + break + } + } + + const uniSlug = university.toLowerCase().replace(/\s+/g, '') + const subreddits = profile?.subreddits ?? [uniSlug, 'college', 'university'] + + const courseplatformUrl = profile?.courseplatform + ? profile.courseplatform.urlTemplate.replace('{code}', courseCode) + : null + + const courseplatformName = profile?.courseplatform?.name ?? null + + const officialUrl = profile?.officialTemplate + ? profile.officialTemplate.replace('{code}', courseCode) + : null + + const rmpQuery = `${courseCode} ${university}` + const blogQuery = `${courseCode} ${university} course review` + + return { subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery } +} diff --git a/modulemapper/tsconfig.json b/modulemapper/tsconfig.json new file mode 100644 index 000000000..fba2bf379 --- /dev/null +++ b/modulemapper/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { "@/*": ["./src/*"] } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/modulemapper/tsconfig.tsbuildinfo b/modulemapper/tsconfig.tsbuildinfo new file mode 100644 index 000000000..a3aecec55 --- /dev/null +++ b/modulemapper/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/next/dist/server/after/builtin-request-context.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/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/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/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/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/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/lib/revalidate.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/build/webpack/plugins/app-build-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/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/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/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/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/prefetch-rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/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/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.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/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/clean-async-snapshot-instance.d.ts","./node_modules/next/dist/server/app-render/clean-async-snapshot.external.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata-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/collect-segment-data.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/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/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/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/client/components/react-dev-overlay/types.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/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/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/types.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/cli/next-test.d.ts","./node_modules/next/dist/server/config-shared.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/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./src/lib/universities.ts","./src/app/api/discover/route.ts","./src/app/api/scrape/route.ts","./src/app/api/synthesise/route.ts","./src/lib/types.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.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/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./src/app/layout.tsx","./src/app/page.tsx"],"fileIdsList":[[95,141],[95,138,141],[95,140,141],[141],[95,141,146,174],[95,141,142,147,152,160,171,182],[95,141,142,143,152,160],[90,91,92,95,141],[95,141,144,183],[95,141,145,146,153,161],[95,141,146,171,179],[95,141,147,149,152,160],[95,140,141,148],[95,141,149,150],[95,141,151,152],[95,140,141,152],[95,141,152,153,154,171,182],[95,141,152,153,154,167,171,174],[95,141,149,152,155,160,171,182],[95,141,152,153,155,156,160,171,179,182],[95,141,155,157,171,179,182],[93,94,95,96,97,98,99,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],[95,141,152,158],[95,141,159,182,187],[95,141,149,152,160,171],[95,141,161],[95,141,162],[95,140,141,163],[95,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],[95,141,165],[95,141,166],[95,141,152,167,168],[95,141,167,169,183,185],[95,141,152,171,172,174],[95,141,173,174],[95,141,171,172],[95,141,174],[95,141,175],[95,138,141,171,176],[95,141,152,177,178],[95,141,177,178],[95,141,146,160,171,179],[95,141,180],[95,141,160,181],[95,141,155,166,182],[95,141,146,183],[95,141,171,184],[95,141,159,185],[95,141,186],[95,136,141],[95,136,141,152,154,163,171,174,182,185,187],[95,141,171,188],[95,141,192,193,194,195,197,401,414,426],[95,141,192,193,194,195,196,401,414,426],[95,141,192,193,194,196,197,401,414,426],[95,141,192,194,195,196,197,401,414,426],[95,141,192,193,195,196,197,401,414,426],[95,141,190,191],[95,141,192],[95,141,428],[95,141,430],[95,141,432,433,434,435],[95,141,437],[86,95,141,210,211,212,214,406],[86,95,141,200,216,225,226,227,228,353,406],[95,141,406],[95,141,211,236,305,344,360],[86,95,141],[95,141,385],[95,141,200,384,406],[95,141,289,305,333,469],[95,141,298,315,344,359],[95,141,261],[95,141,348],[95,141,347,348,349],[95,141,347],[86,89,95,141,155,198,207,208,211,215,226,229,230,282,287,335,345,355,401,406],[86,95,141,213,250,285,381,382,406,469],[95,141,213,469],[95,141,285,286,287,406,469],[95,141,469],[86,95,141,213,214,469],[95,141,208,346,352],[95,141,166,306,360],[95,141,306,360],[95,141,192,306],[95,141,192,283,306,307],[95,141,241,259,360,462],[95,141,341,457,458,459,460,461],[95,141,340],[95,141,340,341],[95,141,227,238,239,283],[95,141,240,241,283],[95,141,283],[87,95,141,192,451],[95,141,182,192],[95,141,192,213,248],[95,141,192,213],[95,141,246,251],[95,141,192,247,404],[95,141,155,189,192,193,194,195,196,197,401,412,413,426],[95,141,153,155,199,216,236,264,280,283,350,406,469],[95,141,207,351],[95,141,401],[85,95,141],[95,141,166,289,303,324,326,359,360],[95,141,166,289,303,323,324,325,359,360],[95,141,317,318,319,320,321,322],[95,141,319],[95,141,323],[95,141,192,247,306,404],[95,141,192,306,402,404],[95,141,192,306,404],[95,141,280,356],[95,141,356],[95,141,155,199,404],[95,141,311],[95,140,141,310],[95,141,199,222,233,235,265,283,298,299,300,302,335,359,362],[95,141,301],[95,141,233,241,283],[95,141,298,359],[95,141,298,307,308,309,311,312,313,314,315,316,327,328,329,330,331,332,359,360,469],[95,141,296],[95,141,155,166,199,200,216,221,233,235,236,237,241,269,280,281,282,335,355,401,406,469],[95,141,359],[95,140,141,199,211,235,282,300,315,355,357,358],[95,141,298],[95,140,141,221,265,291,292,293,294,295,296,297],[95,141,155,199,200,291,292,407],[95,141,199,211,280,282,283,300,355,359],[95,141,155,200,406],[95,141,155,171,199,200,362],[83,95,141,155,166,182,198,199,200,213,216,222,233,235,236,237,242,264,265,266,268,269,272,274,277,278,279,283,354,355,360,362,363,406],[95,141,155,171],[86,87,88,95,141,216,229,362,401,404,405,469],[95,141,155,171,182,231,383,385,386,387,469],[95,141,166,182,198,231,236,265,266,272,280,283,355,360,362,367,368,369,375,381,397,398],[95,141,207,208,229,282,346,355,406],[87,95,141,155,182,265,362,373,406],[95,141,288],[95,141,155,394,395,396],[95,141,362,406],[95,141,216,235,265,354,404],[95,141,155,166,272,280,362,369,375,377,381,397,400],[95,141,155,207,208,381,390],[86,95,141,242,354,392,406],[95,141,155,213,242,376,377,388,389,391,393,406],[89,95,141,233,234,235,401,404],[83,95,141,155,166,182,207,208,215,216,222,236,237,265,266,268,269,280,283,354,355,360,361,362,367,368,369,370,372,374,404],[95,141,155,171,208,362,375,394,399],[95,141,202,203,204,205,206],[95,141,273,363],[95,141,275],[95,141,273],[95,141,275,276],[95,141,155,199,216,221],[85,87,95,141,155,166,192,200,216,222,233,235,236,237,263,362,401,404],[95,141,155,166,182,199,223,227,265,361],[95,141,292],[95,141,293],[95,141,294],[95,141,218,219],[95,141,155,216,218,222],[95,141,217,219],[95,141,220],[95,141,218,231],[95,141,218,243],[95,141,218],[95,141,271,361,363],[95,141,270],[95,141,231,360,361],[95,141,267,361],[95,141,231,360],[95,141,335],[95,141,199,222,232,234,265,283,289,300,303,304,334,362],[95,141,241,252,255,256,257,258,259],[95,141,343],[95,141,211,234,235,283,298,311,315,336,337,338,339,341,342,345,354,359,406,407],[95,141,241],[95,141,263],[95,141,155,222,234,244,260,262,264,362,401,404],[95,141,241,252,253,254,255,256,257,258,259,402],[95,141,231],[95,141,355,367,407,408],[95,141,155,363,406],[95,141,155],[95,141,291,298],[95,141,290],[83,95,141,407],[95,141,291,364,406],[95,141,155,199,223,365,366,406,407,408],[95,141,192,238,240,283],[95,141,284],[87,95,141,192],[95,141,192,360],[89,95,141,192,235,237,401,404],[87,95,141,451,452],[95,141,192,251],[85,95,141,166,182,192,245,247,249,250,404],[95,141,199,213,360],[95,141,360,371],[85,95,141,153,155,166,192,251,285,401,402,403],[95,141,192,193,194,195,196,197,401,414],[95,141,192,423,424,425,426],[95,141,146],[95,141,378,379,380],[95,141,378],[85,95,141,155,157,166,189,192,193,194,195,196,197,198,200,269,323,400,404,414,426],[95,141,439],[95,141,441],[95,141,443],[95,141,445],[95,141,447,448,449],[95,141,453],[95,141,417,427,429,431,436,438,440,442,444,446,450,454,456,464,465,467,468,469,470],[95,141,455],[95,141,463],[95,141,247],[95,141,466],[95,140,141,314,360,365,367,407,408,409,410,411,414,415,416],[95,141,189],[95,141,171,189],[95,108,112,141,182],[95,108,141,171,182],[95,103,141],[95,105,108,141,179,182],[95,141,160,179],[95,103,141,189],[95,105,108,141,160,182],[95,100,101,104,107,141,152,171,182],[95,108,115,141],[95,100,106,141],[95,108,129,130,141],[95,104,108,141,174,182,189],[95,129,141,189],[95,102,103,141,189],[95,108,141],[95,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,141],[95,108,123,141],[95,108,115,116,141],[95,106,108,116,117,141],[95,107,141],[95,100,103,108,141],[95,108,112,116,117,141],[95,112,141],[95,106,108,111,141,182],[95,100,105,108,115,141],[95,141,171],[95,103,108,129,141,187,189],[95,141,417,418],[95,141,417],[95,141,471],[95,141,192,422]],"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":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"dd721e5707f241e4ef4ab36570d9e2a79f66aad63a339e3cbdbac7d9164d2431","impliedFormat":1},{"version":"24f8562308dd8ba6013120557fa7b44950b619610b2c6cb8784c79f11e3c4f90","impliedFormat":1},{"version":"3849a7f92d0e11b785f6ae7bedb25d9aad8d1234b3f1cf530a4e7404be26dd0a","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"631eff75b0e35d1b1b31081d55209abc43e16b49426546ab5a9b40bdd40b1f60","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":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","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":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"fad4e3c207fe23922d0b2d06b01acbfb9714c4f2685cf80fd384c8a100c82fd0","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":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"3da0083607976261730c44908eab1b6262f727747ef3230a65ecd0153d9e8639","impliedFormat":1},{"version":"12f0fb50e28b9d48fe5b7580580efe7cc0bd38e4b8c02d21c175aa9a4fd839b0","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"12b8dfed70961bea1861e5d39e433580e71323abb5d33da6605182ec569db584","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"7e560f533aaf88cf9d3b427dcf6c112dd3f2ee26d610e2587583b6c354c753db","impliedFormat":1},{"version":"71e0082342008e4dfb43202df85ea0986ef8e003c921a1e49999d0234a3019da","impliedFormat":1},{"version":"27ab780875bcbb65e09da7496f2ca36288b0c541abaa75c311450a077d54ec15","impliedFormat":1},{"version":"a9af0e608929aaf9ce96bd7a7b99c9360636c31d73670e4af09a09950df97841","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"b6db56e4903e9c32e533b78ac85522de734b3d3a8541bf24d256058d464bf04b","impliedFormat":1},{"version":"24daa0366f837d22c94a5c0bad5bf1fd0f6b29e1fae92dc47c3072c3fdb2fbd5","impliedFormat":1},{"version":"b68c4ed987ef5693d3dccd85222d60769463aca404f2ffca1c4c42781dce388e","impliedFormat":1},{"version":"cfb5b5d514eb4ad0ee25f313b197f3baa493eee31f27613facd71efb68206720","impliedFormat":1},{"version":"65f43099ded6073336e697512d9b80f2d4fec3182b7b2316abf712e84104db00","impliedFormat":1},{"version":"f040772329d757ecd38479991101ef7bc9bf8d8f4dd8ee5d96fe00aa264f2a2b","impliedFormat":1},{"version":"9715fe982fccf375c88ac4d3cc8f6a126a7b7596be8d60190a0c7d22b45b4be4","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"1fe24e25a00c7dd689cb8c0fb4f1048b4a6d1c50f76aaca2ca5c6cdb44e01442","impliedFormat":1},{"version":"672f293c53a07b8c1c1940797cd5c7984482a0df3dd9c1f14aaee8d3474c2d83","impliedFormat":1},{"version":"0a66cb2511fa8e3e0e6ba9c09923f664a0a00896f486e6f09fc11ff806a12b0c","impliedFormat":1},{"version":"d703f98676a44f90d63b3ffc791faac42c2af0dd2b4a312f4afdb5db471df3de","impliedFormat":1},{"version":"57d6ac03382e30e9213641ff4f18cf9402bb246b77c13c8e848c0b1ca2b7ef92","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"57e47d02e88abef89d214cdf52b478104dc17997015746e288cbb580beaef266","impliedFormat":1},{"version":"04a2d0bd8166f057cc980608bd5898bfc91198636af3c1eb6cb4eb5e8652fbea","impliedFormat":1},{"version":"376c21ad92ca004531807ea4498f90a740fd04598b45a19335a865408180eddd","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"48d37b90a04e753a925228f50304d02c4f95d57bf682f8bb688621c3cd9d32ec","impliedFormat":1},{"version":"361e2b13c6765d7f85bb7600b48fde782b90c7c41105b7dab1f6e7871071ba20","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"0cfe1d0b90d24f5c105db5a2117192d082f7d048801d22a9ea5c62fae07b80a0","impliedFormat":1},{"version":"ef61792acbfa8c27c9bd113f02731e66229f7d3a169e3c1993b508134f1a58e0","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"3ccf230b00deed31582c84b968cb3a977dae3b3446107d7aa790efaa079c06ac","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"5c2e5ca7d53236bbf483a81ae283e2695e291fe69490cd139b33fa9e71838a69","impliedFormat":1},{"version":"a73bee51e3820392023252c36348e62dd72e6bae30a345166e9c78360f1aba7e","impliedFormat":1},{"version":"6ea68b3b7d342d1716cc4293813410d3f09ff1d1ca4be14c42e6d51e810962e1","impliedFormat":1},{"version":"c319e82ac16a5a5da9e28dfdefdad72cebb5e1e67cbdcc63cce8ae86be1e454f","impliedFormat":1},{"version":"a23185bc5ef590c287c28a91baf280367b50ae4ea40327366ad01f6f4a8edbc5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"0c7c947ff881c4274c0800deaa0086971e0bfe51f89a33bd3048eaa3792d4876","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","affectsGlobalScope":true,"impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"a020158a317c07774393974d26723af551e569f1ba4d6524e8e245f10e11b976","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"15b36126e0089bfef173ab61329e8286ce74af5e809d8a72edcafd0cc049057f","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d07cbc787a997d83f7bde3877fec5fb5b12ce8c1b7047eb792996ed9726b4dde","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"8bba776476c48b0e319d243f353190f24096057acede3c2f620fee17ff885dba","impliedFormat":1},{"version":"a3abe92070fbd33714bd837806030b39cfb1f8283a98c7c1f55fffeea388809e","impliedFormat":1},{"version":"ceb6696b98a72f2dae802260c5b0940ea338de65edd372ff9e13ab0a410c3a88","impliedFormat":1},{"version":"2cd914e04d403bdc7263074c63168335d44ce9367e8a74f6896c77d4d26a1038","impliedFormat":1},{"version":"ac60bbee0d4235643cc52b57768b22de8c257c12bd8c2039860540cab1fa1d82","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"208c9af9429dd3c76f5927b971263174aaa4bc7621ddec63f163640cbd3c473c","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"45490817629431853543adcb91c0673c25af52a456479588b6486daba34f68bb","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"9f31420a5040dbfb49ab94bcaaa5103a9a464e607cabe288958f53303f1da32e","impliedFormat":1},{"version":"56013416784a6b754f3855f8f2bf6ce132320679b8a435389aca0361bce4df6b","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"9c066f3b46cf016e5d072b464821c5b21cc9adcc44743de0f6c75e2509a357ab","impliedFormat":1},{"version":"002eae065e6960458bda3cf695e578b0d1e2785523476f8a9170b103c709cd4f","impliedFormat":1},{"version":"c51641ab4bfa31b7a50a0ca37edff67f56fab3149881024345b13f2b48b7d2de","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"52abbd5035a97ebfb4240ec8ade2741229a7c26450c84eb73490dc5ea048b911","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4360ad4de54de2d5c642c4375d5eab0e7fe94ebe8adca907e6c186bbef75a54d","impliedFormat":1},{"version":"c338dff3233675f87a3869417aaea8b8bf590505106d38907dc1d0144f6402ef","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"9c9cae45dc94c2192c7d25f80649414fa13c425d0399a2c7cb2b979e4e50af42","impliedFormat":1},{"version":"068f063c2420b20f8845afadb38a14c640aed6bb01063df224edb24af92b4550","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"b8719d4483ebef35e9cb67cd5677b7e0103cf2ed8973df6aba6fdd02896ddc6e","impliedFormat":1},{"version":"643672ce383e1c58ea665a92c5481f8441edbd3e91db36e535abccbc9035adeb","impliedFormat":1},{"version":"6dd9bcf10678b889842d467706836a0ab42e6c58711e33918ed127073807ee65","impliedFormat":1},{"version":"8fa022ea514ce0ea78ac9b7092a9f97f08ead20c839c779891019e110fce8307","impliedFormat":1},{"version":"c93235337600b786fd7d0ff9c71a00f37ca65c4d63e5d695fc75153be2690f09","impliedFormat":1},{"version":"10179c817a384983f6925f778a2dac2c9427817f7d79e27d3e9b1c8d0564f1f4","impliedFormat":1},{"version":"ce791f6ea807560f08065d1af6014581eeb54a05abd73294777a281b6dfd73c2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"c0a666b005521f52e2db0b685d659d7ee9b0b60bc0d347dfc5e826c7957bdb83","impliedFormat":1},{"version":"807d38d00ce6ab9395380c0f64e52f2f158cc804ac22745d8f05f0efdec87c33","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"e17cd049a1448de4944800399daa4a64c5db8657cc9be7ef46be66e2a2cd0e7c","impliedFormat":1},{"version":"d05fb434f4ba073aed74b6c62eff1723c835de2a963dbb091e000a2decb5a691","impliedFormat":1},{"version":"10e6166be454ddb8c81000019ce1069b476b478c316e7c25965a91904ec5c1e3","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"4d4927cbee21750904af7acf940c5e3c491b4d5ebc676530211e389dd375607a","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"703989a003790524b4e34a1758941d05c121d5d352bccca55a5cfb0c76bca592","impliedFormat":1},{"version":"a58abf1f5c8feb335475097abeddd32fd71c4dc2065a3d28cf15cacabad9654a","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"671aeae7130038566a8d00affeb1b3e3b131edf93cbcfff6f55ed68f1ca4c1b3","impliedFormat":1},{"version":"f0f05149debcf31b3a717ce8dd16e0323a789905cb9e27239167b604153b8885","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"955c69dde189d5f47a886ed454ff50c69d4d8aaec3a454c9ab9c3551db727861","impliedFormat":1},{"version":"cec8b16ff98600e4f6777d1e1d4ddf815a5556a9c59bc08cc16db4fd4ae2cf00","impliedFormat":1},{"version":"9e21f8e2c0cfea713a4a372f284b60089c0841eb90bf3610539d89dbcd12d65a","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"c226288bda11cee97850f0149cc4ff5a244d42ed3f5a9f6e9b02f1162bf1e3f4","impliedFormat":1},{"version":"210a4ec6fd58f6c0358e68f69501a74aef547c82deb920c1dec7fa04f737915a","impliedFormat":1},{"version":"8eea4cc42d04d26bcbcaf209366956e9f7abaf56b0601c101016bb773730c5fe","impliedFormat":1},{"version":"f5319e38724c54dff74ee734950926a745c203dcce00bb0343cb08fbb2f6b546","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"e71e103fb212e015394def7f1379706fce637fec9f91aa88410a73b7c5cbd4e3","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"794998dc1c5a19ce77a75086fe829fb9c92f2fd07b5631c7d5e0d04fd9bc540c","impliedFormat":1},{"version":"2b0b12d0ee52373b1e7b09226eae8fbf6a2043916b7c19e2c39b15243f32bde2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"0427df5c06fafc5fe126d14b9becd24160a288deff40e838bfbd92a35f8d0d00","impliedFormat":1},{"version":"bdc5fd605a6d315ded648abf2c691a22d0b0c774b78c15512c40ddf138e51950","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"6cd4b0986c638d92f7204d1407b1cb3e0a79d7a2d23b0f141c1a0829540ce7ef","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"d58265e159fc3cb30aa8878ba5e986a314b1759c824ff66d777b9fe42117231a","impliedFormat":1},{"version":"ff8fccaae640b0bb364340216dcc7423e55b6bb182ca2334837fee38636ad32e","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"59ee66cf96b093b18c90a8f6dbb3f0e3b65c758fba7b8b980af9f2726c32c1a2","impliedFormat":1},{"version":"c590195790d7fa35b4abed577a605d283b8336b9e01fa9bf4ae4be49855940f9","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"026a43d8239b8f12d2fc4fa5a7acbc2ad06dd989d8c71286d791d9f57ca22b78","impliedFormat":1},{"version":"3bc8605900fd1668f6d93ce8e14386478b6caa6fda41be633ee0fe4d0c716e62","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"6dcf60530c25194a9ee0962230e874ff29d34c59605d8e069a49928759a17e0a","impliedFormat":1},{"version":"7cd657e359eac7829db5f02c856993e8945ffccc71999cdfb4ab3bf801a1bbc6","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"29c2aa0712786a4a504fce3acd50928f086027276f7490965cb467d2ce638bae","impliedFormat":1},{"version":"f14e63395b54caecc486f00a39953ab00b7e4d428a4e2c38325154b08eb5dcc2","impliedFormat":1},{"version":"e749bbd37dadf82c9833278780527c717226e1e2c9bc7b2576c8ec1c40ec5647","impliedFormat":1},{"version":"46e4e179b295f08d0bd0176fe44cf6c89558c9091d3cb3894f9eaaa42ea1add1","impliedFormat":1},{"version":"1101ceda2dfd8e0c7ae87cda8053533a187ecc58c5ef72074afb97d2bf4daa08","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"29164fb428c851bc35b632761daad3ae075993a0bf9c43e9e3bc6468b32d9aa5","impliedFormat":1},{"version":"3c01539405051bffccacffd617254c8d0f665cdce00ec568c6f66ccb712b734f","impliedFormat":1},{"version":"ef9021bdfe54f4df005d0b81170bd2da9bfd86ef552cde2a049ba85c9649658f","impliedFormat":1},{"version":"17a1a0d1c492d73017c6e9a8feb79e9c8a2d41ef08b0fe51debc093a0b2e9459","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"96e1caae9b78cde35c62fee46c1ec9fa5f12c16bc1e2ab08d48e5921e29a6958","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"9e0327857503a958348d9e8e9dd57ed155a1e6ec0071eb5eb946fe06ccdf7680","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"01aa917531e116485beca44a14970834687b857757159769c16b228eb1e49c5f","impliedFormat":1},{"version":"397f568f996f8ffcf12d9156342552b0da42f6571eadba6bce61c99e1651977d","impliedFormat":1},{"version":"e2fd426f3cbc5bbff7860378784037c8fa9c1644785eed83c47c902b99b6cda9","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"a52674bc98da7979607e0f44d4c015c59c1b1d264c83fc50ec79ff2cfea06723","impliedFormat":1},{"version":"bcca16e60015db8bbf6bd117e88c5f7269337aebb05fc2b0701ae658a458c9c3","impliedFormat":1},{"version":"5e1246644fab20200cdc7c66348f3c861772669e945f2888ef58b461b81e1cd8","impliedFormat":1},{"version":"eb39550e2485298d91099e8ab2a1f7b32777d9a5ba34e9028ea8df2e64891172","impliedFormat":1},{"version":"e108f38a04a607f9386d68a4c6f3fdae1b712960f11f6482c6f1769bab056c2e","impliedFormat":1},{"version":"a3128a84a9568762a2996df79717d92154d18dd894681fc0ab3a098fa7f8ee3b","affectsGlobalScope":true,"impliedFormat":1},{"version":"347791f3792f436950396dd6171d6450234358001ae7c94ca209f1406566ccbf","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"714d8ebb298c7acc9bd1f34bd479c57d12b73371078a0c5a1883a68b8f1b9389","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"14cf3683955f914b4695e92c93aae5f3fe1e60f3321d712605164bfe53b34334","impliedFormat":1},{"version":"f11d0dcaa4a1cba6d6513b04ceb31a262f223f56e18b289c0ba3133b4d3cd9a6","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"b95a6f019095dd1d48fd04965b50dfd63e5743a6e75478343c46d2582a5132bf","impliedFormat":99},{"version":"c2008605e78208cfa9cd70bd29856b72dda7ad89df5dc895920f8e10bcb9cd0a","impliedFormat":99},{"version":"b97cb5616d2ab82a98ec9ada7b9e9cabb1f5da880ec50ea2b8dc5baa4cbf3c16","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"00b0f43b3770f66aa1e105327980c0ff17a868d0e5d9f5689f15f8d6bf4fb1f4","affectsGlobalScope":true,"impliedFormat":1},"2437cce1e0849541450f7d6b650378eecfb0a9d5bcdb937e1847ae0eece384b6","ebc82fbe351ae2cf05c6416e9c16a07319b812dfe26c5ac4e23830e3bbf171eb","2389c9637b9b150ef53f21332df2513c78bda89e1839eac01eac58291ff0b439","ac7249258edc87e40eac45bb92623ed5afb002426b8935d6adb628edaee393e6","90e6a853545dbeafc01e7b8922a57dbd7231c641108ef7e111eba1b792ba1d06",{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"51bf55bb6eb80f11b3aa59fb0a9571565a7ea304a19381f6da5630f4b2e206c4","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"02f8ef78d46c5b27f108dbb56709daa0aff625c20247abb0e6bb67cd73439f9f","impliedFormat":1},{"version":"b7fff2d004c5879cae335db8f954eb1d61242d9f2d28515e67902032723caeab","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"bb0cd7862b72f5eba39909c9889d566e198fcaddf7207c16737d0c2246112678","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"6812502cc640de74782ce9121592ae3765deb1c5c8e795b179736b308dd65e90","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"2b664c3cc544d0e35276e1fb2d4989f7d4b4027ffc64da34ec83a6ccf2e5c528","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"bad68fd0401eb90fe7da408565c8aee9c7a7021c2577aec92fa1382e8876071a","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"fec01479923e169fb52bd4f668dbeef1d7a7ea6e6d491e15617b46f2cacfa37d","impliedFormat":1},{"version":"8a8fb3097ba52f0ae6530ec6ab34e43e316506eb1d9aa29420a4b1e92a81442d","impliedFormat":1},{"version":"44e09c831fefb6fe59b8e65ad8f68a7ecc0e708d152cfcbe7ba6d6080c31c61e","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"b10bc147143031b250dc36815fd835543f67278245bf2d0a46dca765f215124e","impliedFormat":1},{"version":"87affad8e2243635d3a191fa72ef896842748d812e973b7510a55c6200b3c2a4","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"1e4c6ac595b6d734c056ac285b9ee50d27a2c7afe7d15bd14ed16210e71593b0","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"3c7b3aecd652169787b3c512d8f274a3511c475f84dcd6cead164e40cad64480","impliedFormat":1},{"version":"9a01f12466488eccd8d9eafc8fecb9926c175a4bf4a8f73a07c3bcf8b3363282","impliedFormat":1},{"version":"b80f624162276f24a4ec78b8e86fbee80ca255938e12f8b58e7a8f1a6937120b","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"272a7e7dbe05e8aaba1662ef1a16bbd57975cc352648b24e7a61b7798f3a0ad7","affectsGlobalScope":true,"impliedFormat":1},{"version":"a1219ee18b9282b4c6a31f1f0bcc9255b425e99363268ba6752a932cf76662f0","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"1d63055b690a582006435ddd3aa9c03aac16a696fac77ce2ed808f3e5a06efab","impliedFormat":1},"5c0a2669dbbab61abd3f444aa1bd6df6b0f78e8699d68c6a71f0813eaa6851be","df820e7ebf61fd57ac58aa133da1204e9b5064e8745c99c6df1900bc449728f4"],"root":[[418,422],472,473],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true,"target":4},"referencedMap":[[403,1],[138,2],[139,2],[140,3],[95,4],[141,5],[142,6],[143,7],[90,1],[93,8],[91,1],[92,1],[144,9],[145,10],[146,11],[147,12],[148,13],[149,14],[150,14],[151,15],[152,16],[153,17],[154,18],[96,1],[94,1],[155,19],[156,20],[157,21],[189,22],[158,23],[159,24],[160,25],[161,26],[162,27],[163,28],[164,29],[165,30],[166,31],[167,32],[168,32],[169,33],[170,1],[171,34],[173,35],[172,36],[174,37],[175,38],[176,39],[177,40],[178,41],[179,42],[180,43],[181,44],[182,45],[183,46],[184,47],[185,48],[186,49],[97,1],[98,1],[99,1],[137,50],[187,51],[188,52],[196,53],[197,54],[195,55],[193,56],[194,57],[190,1],[192,58],[306,59],[191,1],[429,60],[431,61],[436,62],[438,63],[213,64],[354,65],[382,66],[287,1],[228,1],[211,1],[345,67],[366,68],[212,1],[384,69],[385,70],[334,71],[342,72],[262,73],[349,74],[350,75],[348,76],[347,1],[346,77],[383,78],[214,79],[286,1],[288,80],[230,1],[233,81],[215,82],[237,81],[266,81],[88,81],[353,83],[405,1],[227,1],[312,84],[313,85],[307,86],[459,1],[315,1],[316,86],[308,87],[463,88],[462,89],[458,1],[387,1],[341,90],[340,1],[457,91],[309,59],[240,92],[238,93],[460,1],[461,1],[239,94],[452,95],[455,96],[249,97],[248,98],[247,99],[466,59],[246,100],[290,1],[410,1],[413,1],[412,59],[414,101],[84,1],[351,102],[352,103],[376,1],[226,104],[198,1],[86,105],[328,59],[327,106],[326,107],[317,1],[318,1],[325,1],[320,1],[323,108],[319,1],[321,109],[324,110],[322,109],[210,1],[224,1],[225,81],[430,111],[439,112],[443,113],[357,114],[356,1],[83,1],[415,115],[200,116],[310,117],[311,118],[303,119],[295,1],[301,1],[302,120],[332,121],[296,122],[333,123],[330,124],[329,1],[331,1],[283,125],[358,126],[359,127],[297,128],[298,129],[293,130],[337,131],[199,132],[369,133],[280,134],[223,135],[406,136],[85,66],[388,137],[399,138],[386,1],[398,139],[89,1],[374,140],[269,1],[289,141],[370,1],[217,1],[397,142],[229,1],[363,143],[355,144],[396,1],[390,145],[216,1],[391,146],[393,147],[394,148],[377,1],[395,135],[236,149],[375,150],[400,151],[201,1],[204,1],[202,1],[206,1],[203,1],[205,1],[207,152],[209,1],[274,153],[273,1],[279,154],[275,155],[278,156],[277,156],[276,155],[222,157],[264,158],[362,159],[416,1],[447,160],[449,161],[300,1],[448,162],[360,126],[314,126],[208,1],[265,163],[219,164],[220,165],[221,166],[232,167],[336,167],[243,167],[267,168],[244,168],[231,169],[218,1],[272,170],[271,171],[270,172],[268,173],[361,174],[305,175],[335,176],[304,177],[344,178],[343,179],[339,180],[261,181],[263,182],[260,183],[234,184],[282,1],[435,1],[281,185],[338,1],[364,186],[294,187],[292,188],[291,189],[408,190],[411,1],[407,191],[365,191],[433,1],[432,1],[434,1],[409,1],[367,192],[258,59],[428,1],[241,193],[250,1],[285,194],[235,1],[441,59],[451,195],[257,59],[445,86],[256,196],[402,197],[255,195],[87,1],[453,198],[253,59],[254,59],[245,1],[284,1],[252,199],[251,200],[242,201],[299,31],[368,31],[392,1],[372,202],[371,1],[437,1],[259,59],[404,203],[423,59],[426,204],[427,205],[424,59],[425,1],[389,206],[381,207],[380,1],[379,208],[378,1],[401,209],[440,210],[442,211],[444,212],[446,213],[450,214],[454,215],[471,216],[456,217],[464,218],[465,219],[467,220],[417,221],[470,104],[469,1],[468,222],[373,223],[81,1],[82,1],[13,1],[14,1],[16,1],[15,1],[2,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[23,1],[24,1],[3,1],[25,1],[26,1],[4,1],[27,1],[31,1],[28,1],[29,1],[30,1],[32,1],[33,1],[34,1],[5,1],[35,1],[36,1],[37,1],[38,1],[6,1],[42,1],[39,1],[40,1],[41,1],[43,1],[7,1],[44,1],[49,1],[50,1],[45,1],[46,1],[47,1],[48,1],[8,1],[54,1],[51,1],[52,1],[53,1],[55,1],[9,1],[56,1],[57,1],[58,1],[60,1],[59,1],[61,1],[62,1],[10,1],[63,1],[64,1],[65,1],[11,1],[66,1],[67,1],[68,1],[69,1],[70,1],[1,1],[71,1],[72,1],[12,1],[76,1],[74,1],[79,1],[78,1],[73,1],[77,1],[75,1],[80,1],[115,224],[125,225],[114,224],[135,226],[106,227],[105,228],[134,222],[128,229],[133,230],[108,231],[122,232],[107,233],[131,234],[103,235],[102,222],[132,236],[104,237],[109,238],[110,1],[113,238],[100,1],[136,239],[126,240],[117,241],[118,242],[120,243],[116,244],[119,245],[129,222],[111,246],[112,247],[121,248],[101,249],[124,240],[123,238],[127,1],[130,250],[419,251],[420,252],[421,252],[472,253],[473,254],[422,1],[418,1]],"affectedFilesPendingEmit":[419,420,421,472,473,422,418],"version":"5.9.3"} \ No newline at end of file diff --git a/modulemapper/vercel.json b/modulemapper/vercel.json new file mode 100644 index 000000000..f92a3f8a9 --- /dev/null +++ b/modulemapper/vercel.json @@ -0,0 +1,3 @@ +{ + "framework": "nextjs" +} From fb77df4a078499146cf6e6625fa319708f58a67c Mon Sep 17 00:00:00 2001 From: Krishna Agarwal Date: Sat, 4 Apr 2026 14:43:43 +0800 Subject: [PATCH 02/11] Add modulemapper skill for university course research --- skills/modulemapper-skill/README.md | 45 +++++ skills/modulemapper-skill/modulemapper.skill | Bin 0 -> 2652 bytes .../modulemapper-skill/modulemapper/SKILL.md | 164 ++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 skills/modulemapper-skill/README.md create mode 100644 skills/modulemapper-skill/modulemapper.skill create mode 100644 skills/modulemapper-skill/modulemapper/SKILL.md diff --git a/skills/modulemapper-skill/README.md b/skills/modulemapper-skill/README.md new file mode 100644 index 000000000..e0ec6dfdc --- /dev/null +++ b/skills/modulemapper-skill/README.md @@ -0,0 +1,45 @@ +# ModuleMapper Skill for Claude + +Research any university course using live student reviews — directly inside Claude. + +## What it does + +Ask Claude things like: +- *"What is BT1101 like at NUS?"* +- *"Is CS2103T worth taking?"* +- *"How hard is MATH101 at MIT?"* +- *"What do students say about CS50 at Harvard?"* + +Claude will automatically scrape **Reddit**, **RateMyProfessors**, the university's **course review platform**, the **official course page**, and **student blogs** in real-time using TinyFish — then synthesise everything into a structured verdict with score, difficulty, workload, student quotes, and more. + +## Requirements + +- A **TinyFish API key** — get one free (500 steps, no credit card) at [tinyfish.ai](https://agent.tinyfish.ai/api-keys) +- Set it as the environment variable `TINYFISH_API_KEY` + +## Install + +1. Download `modulemapper.skill` from the [Releases](../../releases) page +2. Go to **Claude.ai → Settings → Skills** +3. Upload the `.skill` file +4. Done — Claude will now use this skill automatically whenever you ask about a course + +## How it works + +The skill follows a 4-step pipeline: + +1. **Discover** — searches the web in real-time to find the right subreddits, course review platform, and official course page for any university +2. **Scrape** — runs multiple TinyFish web agents in parallel across all sources +3. **Synthesise** — analyses all raw student data and produces a structured verdict +4. **Present** — displays score, difficulty, workload, student quotes, tags, and more + +Works for **any university worldwide** — not limited to a hardcoded list. + +## Built with + +- [TinyFish Web Agent](https://tinyfish.ai) — parallel web scraping +- [ModuleMapper](https://github.com/YOUR_USERNAME/modulemapper) — the original web app this skill is based on + +## License + +MIT diff --git a/skills/modulemapper-skill/modulemapper.skill b/skills/modulemapper-skill/modulemapper.skill new file mode 100644 index 0000000000000000000000000000000000000000..939c864043955e14773dae042a62f83d5c652792 GIT binary patch literal 2652 zcmV-i3ZwNvHN;RaYt%FA`(fps@~; zP>#i9B4aO*#*fv+DjhZGg-3L0B-x=dWJW3s$!dzFks|hoB%&E5k-CwwQFcbYPGT$; zQ9zRzGJQOgv2o(tB$fdllR!om`)`z-61D}(w^f|ciPc~LDKs6*2%8ckV-jX$_~d9{ zC{!aTTAB`pC8%=HuGgOIcHC>itFz1YUa3r_O!CW4t@fl=DnoKfnN<5sxv7rrkgOO% ztlKiwQyPjmV6mtBo!8jN5>J~Q_t~8o=v;SrLCi?>bYkgunasWPAT!iS7*LaiOZp)@ z&)0!`$C7mH+!f0Yi8L@Gy3yecl*koJRX61<8q}9E=m~$svZ3@S)FLR;AQk~OIdQo= z^+ZL8mdVr-cSBO8{ctK~hW)x4%TFJFf^E@5i!Mh1a`_q?&Rg10sxTqJg=;|BdUR%RH9{eg(5BK*~} z-5NeRT^VhqTD4xn3o8buan}ly`-p&0F=5rLie`O?ER^voK(+UPPMs4^9i*wv#(G}s z%dqXumU2UU+<>b|z0#6Fplq31!phUxMXdYM7#*9k$39s~eOMrF5(?Yb@wn^~BNy5W zHDJvFunc)Ki}2qltXC0IY%On!M9HjsKo_yB^g}fmS~?g?e?*U3N8epGTSteFJ#Txv zR;7cJCL|e)kjY?gd)w=FyFFos-gKzog2HiITg&H4B?|@p_#;VwsHxOxp1nP8wqIXE z-u2me=el{;?(CnO937TeqSx$Gr0w#gGW6CHXQ`FU7VH!xbA!6kWSp;~%7A{&$5!~< z9Y0iER=WJg)s0`!VqFe`pdy@os0qd~Yxzh!gwd*y zdKxQycCVp{FlNR7Z7U~KbKyHw#@Fzh=e`ieE<9C9Hv0E!QI-zWjFiLheT7)&L5lmfQuok^VFvX`lfIVGUW)`?Sz zwzu0!FLt;z+uKg5;(#?k>M4Mh^yrtw=L`^N5hAZeAjit*FIBow08_o{q#mpiQvu`E z6EZMYm=a=PIdgE7q(|UmWFW}wWt^x8sXi*xfryz$r1h(homYB^3R5iu6-(c;MT8?( z`MOGoZxR{gL77QwlB#yz?<-$H`#i_QKz`nI0w@GR?Ut>c5Zo`nEiHB9@#MQi#2z8JCggZFDM+&F>+w#C>7C`g!^W_9fRa%zW8ju9;o;)&nlA8y&DK z@KeDY&cz9OrF|4Svu@-*%HhvGPw(G;mfkmAo7=eQ-8Vv6XVFSOfVlzPkK!gDUwM@?ldE}# z39of}@%$H$&=1{LJ$3?lvlAs@_}IfFaoFtCHrK9G*q!zDd)L?RS^x6n{8f8n^%{y+ z)?S?KcaG0nryI*RJ+rcd=YsW~YB%kviYd$UIy|L|Y&h^W8XO;!L+&UC9D)9L<|bzJ zOI8mg9%A&!#ob0Wn9)?(VIynBeI4hmXpJLMdxD0{NJbkWOlXIflciy%VuEyAzfYxQ zo4G#=d9kbxs#JOR>o1bp~v%| zpTsv9CrR{-4ihUg`P>+rvEyBgU84Z=QMQZKLHmfIPYohh!OGlMz6VB3x)*0e0oT=R zN1)+aq@?Kgd6aQFr^mcum1jD62t}Bx^D~~Z+rFWZL=&D^#8jrDJ7SQJacSsZOK~$R z?tu7G>J`*Ydt?6fa%m#}yh!z=A#Y3J@RDzwkSm1~HD$L|?yidY&aFGstU1e8{kv<$ zjaFdo)Z6X#&LLZkoiGuHed7jM`jBWVvzrrlxdL49oluIEw7yU%5G1pauuq-53%=Ju zdU%+!k?%7H**xpA!dInZumJ09)B8X+r{QKA@1KAD(;xC8`j5Y_6;W@V&9@z8L%Hxg zm$@K$!~YjM05oeb&rZVvbXzW~+(3i?PlkB;>8FoB*Ppjcx(3nwmUZy*T*I6EowLMc z*M*GVAh#CY{>^|G|B{!@MVdJ7#eyEqv%cpdO^n53@7U!WXCoivKPgN z`sN4LaIH$6aiZ`|!bnZr1!da*STaVR4;g z5}$9gcr8Gb_CFg}pCFYmn5sZ}{{m1;0Rj{Q6aWAK2mos{gj{Y(=f%(o000gc000#L z0000000000005+c00000ZEs|CY-Md>aByXEFH=iNOiV6qWKc^51^@s60096207C!( K00RmD00006j|Arc literal 0 HcmV?d00001 diff --git a/skills/modulemapper-skill/modulemapper/SKILL.md b/skills/modulemapper-skill/modulemapper/SKILL.md new file mode 100644 index 000000000..9f5b84be1 --- /dev/null +++ b/skills/modulemapper-skill/modulemapper/SKILL.md @@ -0,0 +1,164 @@ +--- +name: modulemapper +description: > + Use this skill to research any university course and produce a structured student review verdict. + Triggers when a user asks things like: "what is CS2103T like at NUS?", "review BT1101", + "is this course worth taking?", "how hard is MATH101 at MIT?", "what do students say about X course?", + "should I take [course code]?", or any request involving course reviews, module feedback, + workload, grading, or student opinions about a university course. Always use this skill — don't + just answer from training data, actually run the research workflow. +license: MIT +metadata: + author: KrishnaAgarwal7531 + version: "1.2" + tags: university courses reviews scraping tinyfish research +--- + +# ModuleMapper Skill + +Research any university course by scraping live student reviews from Reddit, RateMyProfessors, +the university's course platform, and student blogs — then synthesise into a structured verdict. + +--- + +## Pre-flight Check (REQUIRED) + +**1. CLI installed?** +```bash +which tinyfish && tinyfish --version || echo "TINYFISH_CLI_NOT_INSTALLED" +``` +If not installed, stop and tell the user: `npm install -g @tiny-fish/cli` + +**2. Authenticated?** +```bash +tinyfish auth status +``` +If not authenticated, stop and tell the user: `tinyfish auth login` + +Do NOT proceed until both checks pass. + +--- + +## Step 1 — Discover + +Given `{COURSE_CODE}` and `{UNIVERSITY}`, find the right sources via real-time web search. +Never use hardcoded URLs. + +- **Subreddits** — find the university's own sub + a regional academic sub. Pick 2. +- **Course review platform** — find student-run rating site (NUSMods, Bruinwalk, Carta, etc.) and build the direct URL for this course. If unsure, skip. +- **Official course page** — find the university catalog page for this code. If unsure, skip. +- Set `rmpQuery` = `"{COURSE_CODE} {UNIVERSITY}"` +- Set `blogQuery` = `"{COURSE_CODE} {UNIVERSITY} course review"` + +--- + +## Step 2 — Scrape in Parallel + +Run ALL agents at the same time using background processes. Do NOT run them one by one. + +```bash +# Fire all agents in parallel +tinyfish agent run --sync \ + --url "https://www.ratemyprofessors.com/search/professors?q={rmpQuery}" \ + "Extract professor reviews for {CODE} at {UNIVERSITY}. Scan professors, only click those who teach {CODE}, max 3. Read visible reviews only, do NOT paginate. Return JSON: {\"professors\": [{\"name\": \"...\", \"overallRating\": 4.2, \"difficultyRating\": 3.1, \"reviews\": [\"...\"]}]}" \ + > /tmp/mm_rmp.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.reddit.com/r/{subreddit1}/search/?q={CODE}&sort=relevance&t=all" \ + "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ + > /tmp/mm_reddit1.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.reddit.com/r/{subreddit2}/search/?q={CODE}&sort=relevance&t=all" \ + "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ + > /tmp/mm_reddit2.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.google.com/search?q={blogQuery}" \ + "Find student blog reviews of {CODE} at {UNIVERSITY}. Click max 3 clearly relevant results. Read main content only. Return JSON: {\"reviews\": [\"...\"], \"source_urls\": [\"...\"]}" \ + > /tmp/mm_blogs.json 2>&1 & + +# If course platform URL was found in Step 1, also run: +tinyfish agent run --sync \ + --url "{courseplatformUrl}" \ + "Extract reviews and ratings for {CODE}. Read only what is visible on this page. Return JSON: {\"overallRating\": 4.1, \"workloadRating\": 3.5, \"difficultyRating\": 3.8, \"reviews\": [\"...\"]}" \ + > /tmp/mm_platform.json 2>&1 & + +# Wait for ALL agents to finish +wait + +# Read all results +RMP=$(cat /tmp/mm_rmp.json 2>/dev/null) +REDDIT1=$(cat /tmp/mm_reddit1.json 2>/dev/null) +REDDIT2=$(cat /tmp/mm_reddit2.json 2>/dev/null) +BLOGS=$(cat /tmp/mm_blogs.json 2>/dev/null) +PLATFORM=$(cat /tmp/mm_platform.json 2>/dev/null) +``` + +--- + +## Step 3 — Synthesise + +Take all the collected results and analyse them together. Produce a verdict with: + +- **Score** — 1 to 10 based on genuine student sentiment +- **Verdict** — one line e.g. "Generally recommended" or "Mixed reviews" +- **Summary** — 2-3 sentences capturing the overall experience +- **Difficulty** — 1 to 10 +- **Workload** — 1 to 10 with estimated hours per week +- **Exam info** — has final exam? how hard? +- **Average grade** — what most students get +- **Grading pattern** — bell curved? absolute? +- **Assessment breakdown** — exams, assignments, projects +- **Attendance** — does it affect grade? +- **What you'll learn** — 4 to 6 key outcomes +- **Tags** — e.g. "Heavy workload", "Great prof", "Bell curved", "Project heavy" +- **Best for** — who should take this +- **Not great if** — who should avoid it +- **Student reviews** — at least 6 real quotes from scraped data with source labels + +--- + +## Step 4 — Present + +Display the verdict clearly. Format it like this: + +``` +📊 {CODE} · {UNIVERSITY} +{Course Title} + +Score: {score}/10 — {verdict} + +{summary paragraph} + +───────────────────────── +Difficulty: {x}/10 +Workload: {x}/10 · {hoursPerWeek} +Avg Grade: {averageGrade} ({gradingPattern}) +Final Exam: {Yes/No} · {examDifficulty} +Attendance: {attendance} +Assessment: {assessment} +───────────────────────── + +What you'll learn: +• {outcome1} +• {outcome2} +• ... + +Tags: {tag1} · {tag2} · {tag3} + +✅ Best for: {bestFor} +❌ Not great if: {notGreatIf} + +Student Reviews: +"{review1}" — {source} +"{review2}" — {source} +... +``` + +--- + +## Notes +- Skip any agent that errors and note it +- Warn user if fewer than 2 sources succeed +- Works for any university worldwide From c32cde8cdc95ad0ecf267cd839df1668de61b7f8 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:26:01 +0800 Subject: [PATCH 03/11] Delete skills/modulemapper-skill/modulemapper/SKILL.md --- .../modulemapper-skill/modulemapper/SKILL.md | 164 ------------------ 1 file changed, 164 deletions(-) delete mode 100644 skills/modulemapper-skill/modulemapper/SKILL.md diff --git a/skills/modulemapper-skill/modulemapper/SKILL.md b/skills/modulemapper-skill/modulemapper/SKILL.md deleted file mode 100644 index 9f5b84be1..000000000 --- a/skills/modulemapper-skill/modulemapper/SKILL.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -name: modulemapper -description: > - Use this skill to research any university course and produce a structured student review verdict. - Triggers when a user asks things like: "what is CS2103T like at NUS?", "review BT1101", - "is this course worth taking?", "how hard is MATH101 at MIT?", "what do students say about X course?", - "should I take [course code]?", or any request involving course reviews, module feedback, - workload, grading, or student opinions about a university course. Always use this skill — don't - just answer from training data, actually run the research workflow. -license: MIT -metadata: - author: KrishnaAgarwal7531 - version: "1.2" - tags: university courses reviews scraping tinyfish research ---- - -# ModuleMapper Skill - -Research any university course by scraping live student reviews from Reddit, RateMyProfessors, -the university's course platform, and student blogs — then synthesise into a structured verdict. - ---- - -## Pre-flight Check (REQUIRED) - -**1. CLI installed?** -```bash -which tinyfish && tinyfish --version || echo "TINYFISH_CLI_NOT_INSTALLED" -``` -If not installed, stop and tell the user: `npm install -g @tiny-fish/cli` - -**2. Authenticated?** -```bash -tinyfish auth status -``` -If not authenticated, stop and tell the user: `tinyfish auth login` - -Do NOT proceed until both checks pass. - ---- - -## Step 1 — Discover - -Given `{COURSE_CODE}` and `{UNIVERSITY}`, find the right sources via real-time web search. -Never use hardcoded URLs. - -- **Subreddits** — find the university's own sub + a regional academic sub. Pick 2. -- **Course review platform** — find student-run rating site (NUSMods, Bruinwalk, Carta, etc.) and build the direct URL for this course. If unsure, skip. -- **Official course page** — find the university catalog page for this code. If unsure, skip. -- Set `rmpQuery` = `"{COURSE_CODE} {UNIVERSITY}"` -- Set `blogQuery` = `"{COURSE_CODE} {UNIVERSITY} course review"` - ---- - -## Step 2 — Scrape in Parallel - -Run ALL agents at the same time using background processes. Do NOT run them one by one. - -```bash -# Fire all agents in parallel -tinyfish agent run --sync \ - --url "https://www.ratemyprofessors.com/search/professors?q={rmpQuery}" \ - "Extract professor reviews for {CODE} at {UNIVERSITY}. Scan professors, only click those who teach {CODE}, max 3. Read visible reviews only, do NOT paginate. Return JSON: {\"professors\": [{\"name\": \"...\", \"overallRating\": 4.2, \"difficultyRating\": 3.1, \"reviews\": [\"...\"]}]}" \ - > /tmp/mm_rmp.json 2>&1 & - -tinyfish agent run --sync \ - --url "https://www.reddit.com/r/{subreddit1}/search/?q={CODE}&sort=relevance&t=all" \ - "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ - > /tmp/mm_reddit1.json 2>&1 & - -tinyfish agent run --sync \ - --url "https://www.reddit.com/r/{subreddit2}/search/?q={CODE}&sort=relevance&t=all" \ - "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ - > /tmp/mm_reddit2.json 2>&1 & - -tinyfish agent run --sync \ - --url "https://www.google.com/search?q={blogQuery}" \ - "Find student blog reviews of {CODE} at {UNIVERSITY}. Click max 3 clearly relevant results. Read main content only. Return JSON: {\"reviews\": [\"...\"], \"source_urls\": [\"...\"]}" \ - > /tmp/mm_blogs.json 2>&1 & - -# If course platform URL was found in Step 1, also run: -tinyfish agent run --sync \ - --url "{courseplatformUrl}" \ - "Extract reviews and ratings for {CODE}. Read only what is visible on this page. Return JSON: {\"overallRating\": 4.1, \"workloadRating\": 3.5, \"difficultyRating\": 3.8, \"reviews\": [\"...\"]}" \ - > /tmp/mm_platform.json 2>&1 & - -# Wait for ALL agents to finish -wait - -# Read all results -RMP=$(cat /tmp/mm_rmp.json 2>/dev/null) -REDDIT1=$(cat /tmp/mm_reddit1.json 2>/dev/null) -REDDIT2=$(cat /tmp/mm_reddit2.json 2>/dev/null) -BLOGS=$(cat /tmp/mm_blogs.json 2>/dev/null) -PLATFORM=$(cat /tmp/mm_platform.json 2>/dev/null) -``` - ---- - -## Step 3 — Synthesise - -Take all the collected results and analyse them together. Produce a verdict with: - -- **Score** — 1 to 10 based on genuine student sentiment -- **Verdict** — one line e.g. "Generally recommended" or "Mixed reviews" -- **Summary** — 2-3 sentences capturing the overall experience -- **Difficulty** — 1 to 10 -- **Workload** — 1 to 10 with estimated hours per week -- **Exam info** — has final exam? how hard? -- **Average grade** — what most students get -- **Grading pattern** — bell curved? absolute? -- **Assessment breakdown** — exams, assignments, projects -- **Attendance** — does it affect grade? -- **What you'll learn** — 4 to 6 key outcomes -- **Tags** — e.g. "Heavy workload", "Great prof", "Bell curved", "Project heavy" -- **Best for** — who should take this -- **Not great if** — who should avoid it -- **Student reviews** — at least 6 real quotes from scraped data with source labels - ---- - -## Step 4 — Present - -Display the verdict clearly. Format it like this: - -``` -📊 {CODE} · {UNIVERSITY} -{Course Title} - -Score: {score}/10 — {verdict} - -{summary paragraph} - -───────────────────────── -Difficulty: {x}/10 -Workload: {x}/10 · {hoursPerWeek} -Avg Grade: {averageGrade} ({gradingPattern}) -Final Exam: {Yes/No} · {examDifficulty} -Attendance: {attendance} -Assessment: {assessment} -───────────────────────── - -What you'll learn: -• {outcome1} -• {outcome2} -• ... - -Tags: {tag1} · {tag2} · {tag3} - -✅ Best for: {bestFor} -❌ Not great if: {notGreatIf} - -Student Reviews: -"{review1}" — {source} -"{review2}" — {source} -... -``` - ---- - -## Notes -- Skip any agent that errors and note it -- Warn user if fewer than 2 sources succeed -- Works for any university worldwide From 7386c2b9c5a38a87ddc7184dd943a3a28707a9d8 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:26:11 +0800 Subject: [PATCH 04/11] Delete skills/modulemapper-skill/modulemapper.skill --- skills/modulemapper-skill/modulemapper.skill | Bin 2652 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 skills/modulemapper-skill/modulemapper.skill diff --git a/skills/modulemapper-skill/modulemapper.skill b/skills/modulemapper-skill/modulemapper.skill deleted file mode 100644 index 939c864043955e14773dae042a62f83d5c652792..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2652 zcmV-i3ZwNvHN;RaYt%FA`(fps@~; zP>#i9B4aO*#*fv+DjhZGg-3L0B-x=dWJW3s$!dzFks|hoB%&E5k-CwwQFcbYPGT$; zQ9zRzGJQOgv2o(tB$fdllR!om`)`z-61D}(w^f|ciPc~LDKs6*2%8ckV-jX$_~d9{ zC{!aTTAB`pC8%=HuGgOIcHC>itFz1YUa3r_O!CW4t@fl=DnoKfnN<5sxv7rrkgOO% ztlKiwQyPjmV6mtBo!8jN5>J~Q_t~8o=v;SrLCi?>bYkgunasWPAT!iS7*LaiOZp)@ z&)0!`$C7mH+!f0Yi8L@Gy3yecl*koJRX61<8q}9E=m~$svZ3@S)FLR;AQk~OIdQo= z^+ZL8mdVr-cSBO8{ctK~hW)x4%TFJFf^E@5i!Mh1a`_q?&Rg10sxTqJg=;|BdUR%RH9{eg(5BK*~} z-5NeRT^VhqTD4xn3o8buan}ly`-p&0F=5rLie`O?ER^voK(+UPPMs4^9i*wv#(G}s z%dqXumU2UU+<>b|z0#6Fplq31!phUxMXdYM7#*9k$39s~eOMrF5(?Yb@wn^~BNy5W zHDJvFunc)Ki}2qltXC0IY%On!M9HjsKo_yB^g}fmS~?g?e?*U3N8epGTSteFJ#Txv zR;7cJCL|e)kjY?gd)w=FyFFos-gKzog2HiITg&H4B?|@p_#;VwsHxOxp1nP8wqIXE z-u2me=el{;?(CnO937TeqSx$Gr0w#gGW6CHXQ`FU7VH!xbA!6kWSp;~%7A{&$5!~< z9Y0iER=WJg)s0`!VqFe`pdy@os0qd~Yxzh!gwd*y zdKxQycCVp{FlNR7Z7U~KbKyHw#@Fzh=e`ieE<9C9Hv0E!QI-zWjFiLheT7)&L5lmfQuok^VFvX`lfIVGUW)`?Sz zwzu0!FLt;z+uKg5;(#?k>M4Mh^yrtw=L`^N5hAZeAjit*FIBow08_o{q#mpiQvu`E z6EZMYm=a=PIdgE7q(|UmWFW}wWt^x8sXi*xfryz$r1h(homYB^3R5iu6-(c;MT8?( z`MOGoZxR{gL77QwlB#yz?<-$H`#i_QKz`nI0w@GR?Ut>c5Zo`nEiHB9@#MQi#2z8JCggZFDM+&F>+w#C>7C`g!^W_9fRa%zW8ju9;o;)&nlA8y&DK z@KeDY&cz9OrF|4Svu@-*%HhvGPw(G;mfkmAo7=eQ-8Vv6XVFSOfVlzPkK!gDUwM@?ldE}# z39of}@%$H$&=1{LJ$3?lvlAs@_}IfFaoFtCHrK9G*q!zDd)L?RS^x6n{8f8n^%{y+ z)?S?KcaG0nryI*RJ+rcd=YsW~YB%kviYd$UIy|L|Y&h^W8XO;!L+&UC9D)9L<|bzJ zOI8mg9%A&!#ob0Wn9)?(VIynBeI4hmXpJLMdxD0{NJbkWOlXIflciy%VuEyAzfYxQ zo4G#=d9kbxs#JOR>o1bp~v%| zpTsv9CrR{-4ihUg`P>+rvEyBgU84Z=QMQZKLHmfIPYohh!OGlMz6VB3x)*0e0oT=R zN1)+aq@?Kgd6aQFr^mcum1jD62t}Bx^D~~Z+rFWZL=&D^#8jrDJ7SQJacSsZOK~$R z?tu7G>J`*Ydt?6fa%m#}yh!z=A#Y3J@RDzwkSm1~HD$L|?yidY&aFGstU1e8{kv<$ zjaFdo)Z6X#&LLZkoiGuHed7jM`jBWVvzrrlxdL49oluIEw7yU%5G1pauuq-53%=Ju zdU%+!k?%7H**xpA!dInZumJ09)B8X+r{QKA@1KAD(;xC8`j5Y_6;W@V&9@z8L%Hxg zm$@K$!~YjM05oeb&rZVvbXzW~+(3i?PlkB;>8FoB*Ppjcx(3nwmUZy*T*I6EowLMc z*M*GVAh#CY{>^|G|B{!@MVdJ7#eyEqv%cpdO^n53@7U!WXCoivKPgN z`sN4LaIH$6aiZ`|!bnZr1!da*STaVR4;g z5}$9gcr8Gb_CFg}pCFYmn5sZ}{{m1;0Rj{Q6aWAK2mos{gj{Y(=f%(o000gc000#L z0000000000005+c00000ZEs|CY-Md>aByXEFH=iNOiV6qWKc^51^@s60096207C!( K00RmD00006j|Arc From bdeb5718dd5dad7ebfe0621509d2b48c657c7373 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:26:30 +0800 Subject: [PATCH 05/11] Add files via upload --- skills/modulemapper-skill/SKILL.md | 164 +++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 skills/modulemapper-skill/SKILL.md diff --git a/skills/modulemapper-skill/SKILL.md b/skills/modulemapper-skill/SKILL.md new file mode 100644 index 000000000..9f5b84be1 --- /dev/null +++ b/skills/modulemapper-skill/SKILL.md @@ -0,0 +1,164 @@ +--- +name: modulemapper +description: > + Use this skill to research any university course and produce a structured student review verdict. + Triggers when a user asks things like: "what is CS2103T like at NUS?", "review BT1101", + "is this course worth taking?", "how hard is MATH101 at MIT?", "what do students say about X course?", + "should I take [course code]?", or any request involving course reviews, module feedback, + workload, grading, or student opinions about a university course. Always use this skill — don't + just answer from training data, actually run the research workflow. +license: MIT +metadata: + author: KrishnaAgarwal7531 + version: "1.2" + tags: university courses reviews scraping tinyfish research +--- + +# ModuleMapper Skill + +Research any university course by scraping live student reviews from Reddit, RateMyProfessors, +the university's course platform, and student blogs — then synthesise into a structured verdict. + +--- + +## Pre-flight Check (REQUIRED) + +**1. CLI installed?** +```bash +which tinyfish && tinyfish --version || echo "TINYFISH_CLI_NOT_INSTALLED" +``` +If not installed, stop and tell the user: `npm install -g @tiny-fish/cli` + +**2. Authenticated?** +```bash +tinyfish auth status +``` +If not authenticated, stop and tell the user: `tinyfish auth login` + +Do NOT proceed until both checks pass. + +--- + +## Step 1 — Discover + +Given `{COURSE_CODE}` and `{UNIVERSITY}`, find the right sources via real-time web search. +Never use hardcoded URLs. + +- **Subreddits** — find the university's own sub + a regional academic sub. Pick 2. +- **Course review platform** — find student-run rating site (NUSMods, Bruinwalk, Carta, etc.) and build the direct URL for this course. If unsure, skip. +- **Official course page** — find the university catalog page for this code. If unsure, skip. +- Set `rmpQuery` = `"{COURSE_CODE} {UNIVERSITY}"` +- Set `blogQuery` = `"{COURSE_CODE} {UNIVERSITY} course review"` + +--- + +## Step 2 — Scrape in Parallel + +Run ALL agents at the same time using background processes. Do NOT run them one by one. + +```bash +# Fire all agents in parallel +tinyfish agent run --sync \ + --url "https://www.ratemyprofessors.com/search/professors?q={rmpQuery}" \ + "Extract professor reviews for {CODE} at {UNIVERSITY}. Scan professors, only click those who teach {CODE}, max 3. Read visible reviews only, do NOT paginate. Return JSON: {\"professors\": [{\"name\": \"...\", \"overallRating\": 4.2, \"difficultyRating\": 3.1, \"reviews\": [\"...\"]}]}" \ + > /tmp/mm_rmp.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.reddit.com/r/{subreddit1}/search/?q={CODE}&sort=relevance&t=all" \ + "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ + > /tmp/mm_reddit1.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.reddit.com/r/{subreddit2}/search/?q={CODE}&sort=relevance&t=all" \ + "Extract student reviews of {CODE} at {UNIVERSITY}. Click max 2 relevant posts only. Read post + top 5-8 comments. Return JSON: {\"reviews\": [\"...\"], \"workloadMentions\": [\"...\"], \"examTips\": [\"...\"], \"professorMentions\": [\"...\"], \"gradingInfo\": [\"...\"]}" \ + > /tmp/mm_reddit2.json 2>&1 & + +tinyfish agent run --sync \ + --url "https://www.google.com/search?q={blogQuery}" \ + "Find student blog reviews of {CODE} at {UNIVERSITY}. Click max 3 clearly relevant results. Read main content only. Return JSON: {\"reviews\": [\"...\"], \"source_urls\": [\"...\"]}" \ + > /tmp/mm_blogs.json 2>&1 & + +# If course platform URL was found in Step 1, also run: +tinyfish agent run --sync \ + --url "{courseplatformUrl}" \ + "Extract reviews and ratings for {CODE}. Read only what is visible on this page. Return JSON: {\"overallRating\": 4.1, \"workloadRating\": 3.5, \"difficultyRating\": 3.8, \"reviews\": [\"...\"]}" \ + > /tmp/mm_platform.json 2>&1 & + +# Wait for ALL agents to finish +wait + +# Read all results +RMP=$(cat /tmp/mm_rmp.json 2>/dev/null) +REDDIT1=$(cat /tmp/mm_reddit1.json 2>/dev/null) +REDDIT2=$(cat /tmp/mm_reddit2.json 2>/dev/null) +BLOGS=$(cat /tmp/mm_blogs.json 2>/dev/null) +PLATFORM=$(cat /tmp/mm_platform.json 2>/dev/null) +``` + +--- + +## Step 3 — Synthesise + +Take all the collected results and analyse them together. Produce a verdict with: + +- **Score** — 1 to 10 based on genuine student sentiment +- **Verdict** — one line e.g. "Generally recommended" or "Mixed reviews" +- **Summary** — 2-3 sentences capturing the overall experience +- **Difficulty** — 1 to 10 +- **Workload** — 1 to 10 with estimated hours per week +- **Exam info** — has final exam? how hard? +- **Average grade** — what most students get +- **Grading pattern** — bell curved? absolute? +- **Assessment breakdown** — exams, assignments, projects +- **Attendance** — does it affect grade? +- **What you'll learn** — 4 to 6 key outcomes +- **Tags** — e.g. "Heavy workload", "Great prof", "Bell curved", "Project heavy" +- **Best for** — who should take this +- **Not great if** — who should avoid it +- **Student reviews** — at least 6 real quotes from scraped data with source labels + +--- + +## Step 4 — Present + +Display the verdict clearly. Format it like this: + +``` +📊 {CODE} · {UNIVERSITY} +{Course Title} + +Score: {score}/10 — {verdict} + +{summary paragraph} + +───────────────────────── +Difficulty: {x}/10 +Workload: {x}/10 · {hoursPerWeek} +Avg Grade: {averageGrade} ({gradingPattern}) +Final Exam: {Yes/No} · {examDifficulty} +Attendance: {attendance} +Assessment: {assessment} +───────────────────────── + +What you'll learn: +• {outcome1} +• {outcome2} +• ... + +Tags: {tag1} · {tag2} · {tag3} + +✅ Best for: {bestFor} +❌ Not great if: {notGreatIf} + +Student Reviews: +"{review1}" — {source} +"{review2}" — {source} +... +``` + +--- + +## Notes +- Skip any agent that errors and note it +- Warn user if fewer than 2 sources succeed +- Works for any university worldwide From 2763bb46b8876142c4a1603d51087de24a2886fe Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:26:54 +0800 Subject: [PATCH 06/11] Delete skills/modulemapper-skill/README.md --- skills/modulemapper-skill/README.md | 45 ----------------------------- 1 file changed, 45 deletions(-) delete mode 100644 skills/modulemapper-skill/README.md diff --git a/skills/modulemapper-skill/README.md b/skills/modulemapper-skill/README.md deleted file mode 100644 index e0ec6dfdc..000000000 --- a/skills/modulemapper-skill/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# ModuleMapper Skill for Claude - -Research any university course using live student reviews — directly inside Claude. - -## What it does - -Ask Claude things like: -- *"What is BT1101 like at NUS?"* -- *"Is CS2103T worth taking?"* -- *"How hard is MATH101 at MIT?"* -- *"What do students say about CS50 at Harvard?"* - -Claude will automatically scrape **Reddit**, **RateMyProfessors**, the university's **course review platform**, the **official course page**, and **student blogs** in real-time using TinyFish — then synthesise everything into a structured verdict with score, difficulty, workload, student quotes, and more. - -## Requirements - -- A **TinyFish API key** — get one free (500 steps, no credit card) at [tinyfish.ai](https://agent.tinyfish.ai/api-keys) -- Set it as the environment variable `TINYFISH_API_KEY` - -## Install - -1. Download `modulemapper.skill` from the [Releases](../../releases) page -2. Go to **Claude.ai → Settings → Skills** -3. Upload the `.skill` file -4. Done — Claude will now use this skill automatically whenever you ask about a course - -## How it works - -The skill follows a 4-step pipeline: - -1. **Discover** — searches the web in real-time to find the right subreddits, course review platform, and official course page for any university -2. **Scrape** — runs multiple TinyFish web agents in parallel across all sources -3. **Synthesise** — analyses all raw student data and produces a structured verdict -4. **Present** — displays score, difficulty, workload, student quotes, tags, and more - -Works for **any university worldwide** — not limited to a hardcoded list. - -## Built with - -- [TinyFish Web Agent](https://tinyfish.ai) — parallel web scraping -- [ModuleMapper](https://github.com/YOUR_USERNAME/modulemapper) — the original web app this skill is based on - -## License - -MIT From fba5a4fc2d1b2de9b73aaa2f8240dd13aca9f9c7 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:27:08 +0800 Subject: [PATCH 07/11] Add files via upload --- skills/modulemapper-skill/README.md | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 skills/modulemapper-skill/README.md diff --git a/skills/modulemapper-skill/README.md b/skills/modulemapper-skill/README.md new file mode 100644 index 000000000..edcb652dd --- /dev/null +++ b/skills/modulemapper-skill/README.md @@ -0,0 +1,55 @@ +# ModuleMapper Skill for Claude + +Research any university course using live student reviews — directly inside Claude. + +## What it does + +Ask Claude things like: +- *"What is BT1101 like at NUS?"* +- *"Is CS2103T worth taking?"* +- *"How hard is MATH101 at MIT?"* +- *"What do students say about CS50 at Harvard?"* + +Claude will automatically scrape **Reddit**, **RateMyProfessors**, the university's **course review platform**, the **official course page**, and **student blogs** in real-time using TinyFish — then synthesise everything into a structured verdict with score, difficulty, workload, student quotes, and more. + +## Requirements + +- A **TinyFish API key** — get one free (500 steps, no credit card) at [tinyfish.ai](https://agent.tinyfish.ai/api-keys) +- Set it as the environment variable `TINYFISH_API_KEY` + +## Install + +### Option 1 — Skills CLI (recommended) + +```bash +npx skills add https://github.com/tinyfish-io/tinyfish-cookbook --skill modulemapper +``` + +### Option 2 — Manual + +1. Clone or download this repository +2. Copy the `modulemapper/` folder into your agent's skills directory: + - Claude Code: `~/.claude/skills/` + - Cursor: `.cursor/skills/` in your project + - Global (all agents): `~/.agents/skills/` +3. The skill is picked up automatically — no restart needed + +## How it works + +The skill follows a 4-step pipeline: + +1. **Discover** — searches the web in real-time to find the right subreddits, course review platform, and official course page for any university +2. **Scrape** — runs multiple TinyFish web agents in parallel across all sources +3. **Synthesise** — analyses all raw student data and produces a structured verdict +4. **Present** — displays score, difficulty, workload, student quotes, tags, and more + +Works for **any university worldwide** — not limited to a hardcoded list. + +## Built with + +- [TinyFish Web Agent](https://tinyfish.ai) — parallel web scraping +- [ModuleMapper](https://github.com/KrishnaAgarwal7531/tinyfish-projects/tree/main/modulemapper) — the original web app this skill is based on + +## License + +MIT From 391f36c8cd45d0aa87c2fe746531a6d931f3c224 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:29:39 +0800 Subject: [PATCH 08/11] Update route.ts --- modulemapper/src/app/api/scrape/route.ts | 314 ++++++++--------------- 1 file changed, 104 insertions(+), 210 deletions(-) diff --git a/modulemapper/src/app/api/scrape/route.ts b/modulemapper/src/app/api/scrape/route.ts index 2ff0e59a4..2d7873397 100644 --- a/modulemapper/src/app/api/scrape/route.ts +++ b/modulemapper/src/app/api/scrape/route.ts @@ -1,230 +1,124 @@ -import { NextRequest } from 'next/server' +import { NextRequest } from "next/server"; +import { TinyFish, EventType, RunStatus, BrowserProfile } from "@tiny-fish/sdk"; -export const runtime = 'nodejs' +const client = new TinyFish(); // Reads TINYFISH_API_KEY from environment -const TINYFISH_ENDPOINT = 'https://agent.tinyfish.ai/v1/automation/run-sse' -const TINYFISH_KEY = process.env.TINYFISH_API_KEY! - -interface AgentConfig { - id: string - source: string - url: string - goal: string -} - -function buildAgents(params: { - code: string - university: string - subreddits: string[] - courseplatformUrl: string | null - courseplatformName: string | null - officialUrl: string | null - rmpQuery: string - blogQuery: string -}): AgentConfig[] { - const agents: AgentConfig[] = [] - - // Rate My Professors — find professors for this course, extract ratings + reviews - agents.push({ - id: 'rmp', - source: 'Rate My Professor', - url: `https://www.ratemyprofessors.com/search/professors?q=${encodeURIComponent(params.rmpQuery)}`, - goal: `Extract professor reviews for ${params.code} at ${params.university}. - -You are on the search results page. Do this efficiently: -1. Look at the professors listed. Only click into professors who clearly teach ${params.code} or its department. -2. For each relevant professor (max 3), read their ratings and the written reviews visible on their profile page. Do NOT paginate or load more — just read what is immediately visible. -3. Return immediately as JSON: -{ - "professors": [ - { "name": "...", "overallRating": 4.2, "difficultyRating": 3.1, "reviews": ["review text", ...] } - ] -} - -Stay focused. Do not explore unrelated professors or pages.` - }) - - // Reddit — one agent per subreddit, max 2 - for (let i = 0; i < Math.min(params.subreddits.length, 2); i++) { - const sub = params.subreddits[i] - agents.push({ - id: `reddit_${sub}`, - source: `r/${sub}`, - url: `https://www.reddit.com/r/${sub}/search/?q=${encodeURIComponent(params.code)}&sort=relevance&t=all`, - goal: `Extract student reviews of ${params.code} at ${params.university} from this Reddit search page. - -You are already on the search results. Do this efficiently: -1. Scan the post titles on this page. Identify posts that are specifically about ${params.code} (reviews, advice, "is it worth it", experience posts). Ignore unrelated posts entirely. -2. Click into the 2 most relevant posts only. Read the post body and the top 5-8 comments. Do NOT scroll endlessly or load more comments. -3. Extract key info: workload, difficulty, grading, exam tips, professor mentions, overall recommendation. -4. Return immediately as JSON: -{ - "reviews": ["student quote or paraphrase with context", ...], - "workloadMentions": ["..."], - "examTips": ["..."], - "professorMentions": ["..."], - "gradingInfo": ["..."] -} - -Be precise. 2 posts maximum. Do not click anything unrelated.` - }) - } - - // Course platform (NUSMods, Bruinwalk, etc.) — just read what's on the page - if (params.courseplatformUrl && params.courseplatformName) { - agents.push({ - id: 'platform', - source: params.courseplatformName, - url: params.courseplatformUrl, - goal: `Extract course reviews and ratings for ${params.code} from this page. - -You are already on the course page. Read what is visible: -- Overall rating, workload rating, difficulty rating (numbers) -- All written student reviews shown on this page - -Do NOT navigate away. Do NOT click into individual reviews if they require separate page loads — just extract what is visible here. - -Return as JSON: -{ "overallRating": 4.1, "workloadRating": 3.5, "difficultyRating": 3.8, "reviews": ["...", ...] }` - }) - } - - // Official course page — just read the description, no navigation - if (params.officialUrl) { - agents.push({ - id: 'official', - source: 'Official course page', - url: params.officialUrl, - goal: `Extract the official course info for ${params.code} from this page. - -You are already on the page. Read only what is visible here — do NOT navigate elsewhere. -Extract: course title, description, learning outcomes, topics, prerequisites, assessment breakdown (exam %, CA %, project %). - -Return as JSON: -{ "title": "...", "description": "...", "learningOutcomes": ["..."], "topics": ["..."], "prerequisites": "...", "assessmentBreakdown": "..." }` - }) - } - - // Student blogs — Google search, try for up to 3 relevant articles - agents.push({ - id: 'blogs', - source: 'Student blogs', - url: `https://www.google.com/search?q=${encodeURIComponent(params.blogQuery)}`, - goal: `Find student blog reviews of ${params.code} at ${params.university}. - -You are on Google search results. Do this efficiently: -1. Scan the results. Click any result whose title/snippet clearly indicates it is a personal student review or experience post about ${params.code}. Try to find up to 3 such articles — if fewer exist, that is fine. -2. On each article, read only the main content. Extract the student's verdict, workload comments, exam tips, and recommendation. -3. Return as JSON: -{ - "reviews": ["detailed paraphrase of student experience and advice", ...], - "source_urls": ["url1", ...] -} - -If no results look relevant at all, return { "reviews": [], "source_urls": [] } immediately. Do not guess or click unrelated links.` - }) - - return agents +interface ScrapeRequest { + url: string; + goal: string; + useStealthMode?: boolean; } -async function runTinyFishAgent(agent: AgentConfig): Promise<{ source: string; raw: string; error?: string }> { +async function runAgent( + { url, goal, useStealthMode = false }: ScrapeRequest, + onProgress?: (message: string) => void, + onStreamingUrl?: (url: string) => void +): Promise<{ success: boolean; resultJson: unknown; error?: string }> { try { - const response = await fetch(TINYFISH_ENDPOINT, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': TINYFISH_KEY - }, - body: JSON.stringify({ - url: agent.url, - goal: agent.goal, - browser_profile: 'stealth' - }) - }) - - if (!response.ok) { - const errText = await response.text() - return { source: agent.source, raw: '', error: `HTTP ${response.status}: ${errText}` } - } - - const reader = response.body?.getReader() - if (!reader) return { source: agent.source, raw: '', error: 'No stream' } - - const decoder = new TextDecoder() - let buffer = '' - let finalResult = '' - - while (true) { - const { done, value } = await reader.read() - if (done) break - - buffer += decoder.decode(value, { stream: true }) - const lines = buffer.split('\n') - buffer = lines.pop() || '' - - for (const line of lines) { - const trimmed = line.trim() - if (!trimmed || !trimmed.startsWith('data:')) continue - const data = trimmed.slice(5).trim() - if (!data || data === '[DONE]') continue + const stream = await client.agent.stream({ + url, + goal, + browser_profile: useStealthMode ? BrowserProfile.STEALTH : BrowserProfile.LITE, + }); + + for await (const event of stream) { + // Forward streaming URL as soon as it's available + if (event.type === EventType.STREAMING_URL && onStreamingUrl) { + onStreamingUrl(event.streaming_url); + } - try { - const parsed = JSON.parse(data) - if (parsed.type === 'COMPLETE' && parsed.result) { - finalResult = typeof parsed.result === 'string' - ? parsed.result - : JSON.stringify(parsed.result) - } else if (parsed.type === 'COMPLETE' && parsed.status === 'COMPLETED') { - finalResult = finalResult || 'completed' - } - } catch { /* skip malformed lines */ } + // Forward progress messages + if (event.type === EventType.PROGRESS && onProgress) { + onProgress(event.purpose ?? ""); } - } - if (!finalResult) { - return { source: agent.source, raw: '', error: 'No result returned from agent' } + // Return result on completion + if (event.type === EventType.COMPLETE) { + if (event.status === RunStatus.COMPLETED) { + return { success: true, resultJson: event.result_json }; + } else { + return { + success: false, + resultJson: null, + error: `Run failed with status: ${event.status}`, + }; + } + } } - return { source: agent.source, raw: finalResult } - } catch (err) { - return { source: agent.source, raw: '', error: String(err) } + return { success: false, resultJson: null, error: "Stream ended without completion event" }; + } catch (error) { + const message = error instanceof Error ? error.message : "Unknown error"; + return { success: false, resultJson: null, error: message }; } } export async function POST(req: NextRequest) { - const body = await req.json() - const { code, university, subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery } = body - - const agents = buildAgents({ code, university, subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery }) - - const encoder = new TextEncoder() - - const stream = new ReadableStream({ - async start(controller) { - const send = (data: object) => { - controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)) + const encoder = new TextEncoder(); + + const sendEvent = (stream: TransformStreamDefaultController, data: object) => { + stream.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)); + }; + + const { readable, writable } = new TransformStream(); + const writer = writable.getWriter(); + + (async () => { + try { + const body: ScrapeRequest = await req.json(); + const { url, goal, useStealthMode } = body; + + if (!url || !goal) { + writer.getWriter().write( + encoder.encode( + `data: ${JSON.stringify({ type: "ERROR", error: "url and goal are required" })}\n\n` + ) + ); + writer.close(); + return; } - send({ type: 'agents', agents: agents.map(a => ({ id: a.id, source: a.source })) }) - - const promises = agents.map(async (agent) => { - send({ type: 'agent_start', id: agent.id, source: agent.source }) - const result = await runTinyFishAgent(agent) - send({ type: 'agent_done', id: agent.id, source: agent.source, raw: result.raw, error: result.error }) - return result - }) - - const results = await Promise.all(promises) - send({ type: 'all_done', results }) - controller.close() + const result = await runAgent( + { url, goal, useStealthMode }, + (message) => { + writer.write( + encoder.encode(`data: ${JSON.stringify({ type: "STATUS", message })}\n\n`) + ); + }, + (streamingUrl) => { + writer.write( + encoder.encode( + `data: ${JSON.stringify({ type: "STREAMING_URL", streamingUrl })}\n\n` + ) + ); + } + ); + + writer.write( + encoder.encode( + `data: ${JSON.stringify({ + type: "COMPLETE", + success: result.success, + resultJson: result.resultJson, + error: result.error, + })}\n\n` + ) + ); + } catch (error) { + const message = error instanceof Error ? error.message : "Unknown error"; + writer.write( + encoder.encode(`data: ${JSON.stringify({ type: "ERROR", error: message })}\n\n`) + ); + } finally { + writer.close(); } - }) + })(); - return new Response(stream, { + return new Response(readable, { headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive' - } - }) + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache", + Connection: "keep-alive", + }, + }); } From d61516ae4635ad9bb649e93c5bf1c5a824a894d1 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:31:32 +0800 Subject: [PATCH 09/11] Update package.json --- modulemapper/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modulemapper/package.json b/modulemapper/package.json index 508fab119..9261e770c 100644 --- a/modulemapper/package.json +++ b/modulemapper/package.json @@ -8,6 +8,7 @@ "start": "next start" }, "dependencies": { + "@tiny-fish/sdk": "^0.7.0", "next": "15.3.1", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -19,3 +20,4 @@ "typescript": "^5" } } + From 108b058f3723e1aed01ae703accd4fca6a7acbf5 Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:29:11 +0800 Subject: [PATCH 10/11] Delete modulemapper/.env.example --- modulemapper/.env.example | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 modulemapper/.env.example diff --git a/modulemapper/.env.example b/modulemapper/.env.example deleted file mode 100644 index 7d6f2b94f..000000000 --- a/modulemapper/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -TINYFISH_API_KEY=your_tinyfish_key_here -GROQ_API_KEY=your_groq_key_here From 3eeb59cbbbd086de95a5e8a4eeb64b94abb83b0b Mon Sep 17 00:00:00 2001 From: KrishnaAgarwal7531 <132636117+KrishnaAgarwal7531@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:29:29 +0800 Subject: [PATCH 11/11] Delete modulemapper directory --- modulemapper/.gitignore | 4 - modulemapper/next-env.d.ts | 5 - modulemapper/next.config.js | 3 - modulemapper/package-lock.json | 943 ------------------- modulemapper/package.json | 23 - modulemapper/readme.md | 139 --- modulemapper/src/app/api/discover/route.ts | 74 -- modulemapper/src/app/api/scrape/route.ts | 124 --- modulemapper/src/app/api/synthesise/route.ts | 96 -- modulemapper/src/app/globals.css | 54 -- modulemapper/src/app/layout.tsx | 20 - modulemapper/src/app/page.tsx | 374 -------- modulemapper/src/lib/types.ts | 44 - modulemapper/src/lib/universities.ts | 160 ---- modulemapper/tsconfig.json | 21 - modulemapper/tsconfig.tsbuildinfo | 1 - modulemapper/vercel.json | 3 - 17 files changed, 2088 deletions(-) delete mode 100644 modulemapper/.gitignore delete mode 100644 modulemapper/next-env.d.ts delete mode 100644 modulemapper/next.config.js delete mode 100644 modulemapper/package-lock.json delete mode 100644 modulemapper/package.json delete mode 100644 modulemapper/readme.md delete mode 100644 modulemapper/src/app/api/discover/route.ts delete mode 100644 modulemapper/src/app/api/scrape/route.ts delete mode 100644 modulemapper/src/app/api/synthesise/route.ts delete mode 100644 modulemapper/src/app/globals.css delete mode 100644 modulemapper/src/app/layout.tsx delete mode 100644 modulemapper/src/app/page.tsx delete mode 100644 modulemapper/src/lib/types.ts delete mode 100644 modulemapper/src/lib/universities.ts delete mode 100644 modulemapper/tsconfig.json delete mode 100644 modulemapper/tsconfig.tsbuildinfo delete mode 100644 modulemapper/vercel.json diff --git a/modulemapper/.gitignore b/modulemapper/.gitignore deleted file mode 100644 index 82e4bad80..000000000 --- a/modulemapper/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.env.local -.env -node_modules -.next diff --git a/modulemapper/next-env.d.ts b/modulemapper/next-env.d.ts deleted file mode 100644 index 1b3be0840..000000000 --- a/modulemapper/next-env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/modulemapper/next.config.js b/modulemapper/next.config.js deleted file mode 100644 index d10837f26..000000000 --- a/modulemapper/next.config.js +++ /dev/null @@ -1,3 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {} -module.exports = nextConfig diff --git a/modulemapper/package-lock.json b/modulemapper/package-lock.json deleted file mode 100644 index 04c99938a..000000000 --- a/modulemapper/package-lock.json +++ /dev/null @@ -1,943 +0,0 @@ -{ - "name": "modulemapper", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "modulemapper", - "version": "0.1.0", - "dependencies": { - "next": "15.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "typescript": "^5" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@next/env": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.0.tgz", - "integrity": "sha512-UcCO481cROsqJuszPPXJnb7GGuLq617ve4xuAyyNG4VSSocJNtMU5Fsx+Lp6mlN8c7W58aZLc5y6D/2xNmaK+w==", - "license": "MIT" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.0.tgz", - "integrity": "sha512-ZU8d7xxpX14uIaFC3nsr4L++5ZS/AkWDm1PzPO6gD9xWhFkOj2hzSbSIxoncsnlJXB1CbLOfGVN4Zk9tg83PUw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.0.tgz", - "integrity": "sha512-DQ3RiUoW2XC9FcSM4ffpfndq1EsLV0fj0/UY33i7eklW5akPUCo6OX2qkcLXZ3jyPdo4sf2flwAED3AAq3Om2Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.0.tgz", - "integrity": "sha512-M+vhTovRS2F//LMx9KtxbkWk627l5Q7AqXWWWrfIzNIaUFiz2/NkOFkxCFyNyGACi5YbA8aekzCLtbDyfF/v5Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.0.tgz", - "integrity": "sha512-Qn6vOuwaTCx3pNwygpSGtdIu0TfS1KiaYLYXLH5zq1scoTXdwYfdZtwvJTpB1WrLgiQE2Ne2kt8MZok3HlFqmg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.0.tgz", - "integrity": "sha512-yeNh9ofMqzOZ5yTOk+2rwncBzucc6a1lyqtg8xZv0rH5znyjxHOWsoUtSq4cUTeeBIiXXX51QOOe+VoCjdXJRw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.0.tgz", - "integrity": "sha512-t9IfNkHQs/uKgPoyEtU912MG6a1j7Had37cSUyLTKx9MnUpjj+ZDKw9OyqTI9OwIIv0wmkr1pkZy+3T5pxhJPg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.0.tgz", - "integrity": "sha512-WEAoHyG14t5sTavZa1c6BnOIEukll9iqFRTavqRVPfYmfegOAd5MaZfXgOGG6kGo1RduyGdTHD4+YZQSdsNZXg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.0.tgz", - "integrity": "sha512-J1YdKuJv9xcixzXR24Dv+4SaDKc2jj31IVUEMdO5xJivMTXuE6MAdIi4qPjSymHuFG8O5wbfWKnhJUcHHpj5CA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0" - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@types/node": { - "version": "20.19.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", - "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001781", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", - "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "optional": true - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", - "license": "MIT", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.0.tgz", - "integrity": "sha512-QKhzt6Y8rgLNlj30izdMbxAwjHMFANnLwDwZ+WQh5sMhyt4lEBqDK9QpvWHtIM4rINKPoJ8aiRZKg5ULSybVHw==", - "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details.", - "license": "MIT", - "dependencies": { - "@next/env": "15.1.0", - "@swc/counter": "0.1.3", - "@swc/helpers": "0.5.15", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.0", - "@next/swc-darwin-x64": "15.1.0", - "@next/swc-linux-arm64-gnu": "15.1.0", - "@next/swc-linux-arm64-musl": "15.1.0", - "@next/swc-linux-x64-gnu": "15.1.0", - "@next/swc-linux-x64-musl": "15.1.0", - "@next/swc-win32-arm64-msvc": "15.1.0", - "@next/swc-win32-x64-msvc": "15.1.0", - "sharp": "^0.33.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.4" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "license": "MIT", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - } - } -} diff --git a/modulemapper/package.json b/modulemapper/package.json deleted file mode 100644 index 9261e770c..000000000 --- a/modulemapper/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "modulemapper", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "@tiny-fish/sdk": "^0.7.0", - "next": "15.3.1", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "typescript": "^5" - } -} - diff --git a/modulemapper/readme.md b/modulemapper/readme.md deleted file mode 100644 index 9c97559ee..000000000 --- a/modulemapper/readme.md +++ /dev/null @@ -1,139 +0,0 @@ -# ModuleMapper - -**Real student reviews for any university course, instantly.** - -ModuleMapper lets you look up any course at any university and get a structured, AI-synthesised verdict based on live student reviews scraped from Reddit, RateMyProfessors, university course platforms, and student blogs — all in real time. - ---- - -## What it does - -Type in a course code (e.g. `BT1101`) and a university (e.g. `NUS`) and ModuleMapper will: - -1. **Discover** the right sources for that university in real-time — subreddits, course review platforms like NUSMods or Bruinwalk, the official course catalog page -2. **Scrape** all sources concurrently using parallel TinyFish web agents, streaming live progress back to you as it runs -3. **Synthesise** everything with an LLM into a structured verdict -4. **Display** a clean dashboard with score, difficulty, workload, student quotes, exam tips, grading patterns, and more - ---- - -## Architecture -``` -User Input (course code + university) - │ - ▼ -┌─────────────────────────────────────┐ -│ /api/discover │ -│ Groq LLM figures out in real-time: │ -│ - Which subreddits to search │ -│ - Course platform URL (NUSMods, │ -│ Bruinwalk, Carta, etc.) │ -│ - Official course catalog URL │ -└──────────────┬──────────────────────┘ - │ - ▼ -┌─────────────────────────────────────┐ -│ /api/scrape │ -│ Spawns N TinyFish agents in │ -│ parallel, streams SSE progress: │ -│ │ -│ ┌─────────────┐ ┌───────────────┐ │ -│ │ RateMyProf │ │ r/nus │ │ -│ └─────────────┘ └───────────────┘ │ -│ ┌─────────────┐ ┌───────────────┐ │ -│ │ NUSMods │ │ Student blogs │ │ -│ └─────────────┘ └───────────────┘ │ -└──────────────┬──────────────────────┘ - │ - ▼ -┌─────────────────────────────────────┐ -│ /api/synthesise │ -│ Groq LLM analyses all raw data │ -│ → structured JSON verdict │ -└──────────────┬──────────────────────┘ - │ - ▼ - Next.js Frontend - (score, reviews, tags, - difficulty, workload…) -``` - ---- - -## Tech Stack - -| Layer | Technology | -|---|---| -| Framework | Next.js 15 (App Router) | -| Language | TypeScript | -| Web scraping | TinyFish Web Agent API | -| LLM (discover + synthesise) | Groq — `llama-3.3-70b-versatile` | -| Streaming | Server-Sent Events (SSE) | -| Styling | Inline CSS with CSS variables | -| Deployment | Vercel | - ---- - -## How to run locally - -**1. Clone the repo** -```bash -git clone https://github.com/YOUR_USERNAME/modulemapper.git -cd modulemapper -``` - -**2. Install dependencies** -```bash -npm install -``` - -**3. Set up environment variables** - -Create a `.env.local` file: -``` -TINYFISH_API_KEY=your_tinyfish_key_here -GROQ_API_KEY=your_groq_key_here -``` - -- Get a TinyFish key (500 free steps, no credit card): https://agent.tinyfish.ai/api-keys -- Get a Groq key (free): https://console.groq.com - -**4. Run the dev server** -```bash -npm run dev -``` - -Open [http://localhost:3000](http://localhost:3000) - ---- - -## How to use - -1. Enter a **course code** — e.g. `BT1101`, `CS50`, `MATH101` -2. Enter a **university** — e.g. `NUS`, `Harvard`, `MIT` -3. Click **Analyse** -4. Watch the agents run live, then read your verdict - -Works for any university worldwide. - ---- - -## Environment Variables - -| Variable | Description | -|---|---| -| `TINYFISH_API_KEY` | TinyFish Web Agent API key for scraping | -| `GROQ_API_KEY` | Groq API key for LLM inference | - ---- - -## Claude Skill - -A Claude skill version of ModuleMapper is available — it does the same thing directly inside Claude without needing the web app. - -Install: download `modulemapper.skill` from [Releases](../../releases) and upload to **Claude.ai → Settings → Skills** - -Or via CLI: -```bash -npx skills add KrishnaAgarwal7531/skills- --skill modulemapper -``` diff --git a/modulemapper/src/app/api/discover/route.ts b/modulemapper/src/app/api/discover/route.ts deleted file mode 100644 index e60dce3e4..000000000 --- a/modulemapper/src/app/api/discover/route.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { NextRequest } from 'next/server' - -export const runtime = 'nodejs' - -const GROQ_API = 'https://api.groq.com/openai/v1/chat/completions' -const GROQ_KEY = process.env.GROQ_API_KEY! - -export async function GET(req: NextRequest) { - const code = req.nextUrl.searchParams.get('code')?.trim().toUpperCase() - const university = req.nextUrl.searchParams.get('university')?.trim() - - if (!code || !university) { - return Response.json({ error: 'Missing code or university' }, { status: 400 }) - } - - const prompt = `You are a university course research assistant. Given a university and course code, return the best sources to scrape for student reviews. - -University: ${university} -Course code: ${code} - -Return ONLY valid JSON (no markdown, no explanation): -{ - "title": "", - "subreddits": ["", ""], - "courseplatformUrl": "", - "courseplatformName": "", - "officialUrl": "", - "rmpQuery": "${code} ${university}", - "blogQuery": "${code} ${university} course review" -} - -Rules: -- Only include URLs you are confident are real and specific to this course. Use null if unsure — do not hallucinate URLs. -- subreddits[0] = university's own sub (e.g. "nus", "berkeley", "uoft"). subreddits[1] = best regional/general academic sub.` - - try { - const response = await fetch(GROQ_API, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${GROQ_KEY}` - }, - body: JSON.stringify({ - model: 'llama-3.3-70b-versatile', - messages: [{ role: 'user', content: prompt }], - temperature: 0.1, - max_tokens: 400 - }) - }) - - if (!response.ok) throw new Error('Groq failed') - - const data = await response.json() - const text = data.choices?.[0]?.message?.content || '' - const clean = text.replace(/```json|```/g, '').trim() - const parsed = JSON.parse(clean) - - return Response.json({ code, university, ...parsed }) - } catch { - // Safe fallback if LLM call fails - const uniSlug = university.toLowerCase().replace(/\s+/g, '') - return Response.json({ - code, - university, - title: code, - subreddits: [uniSlug, 'college'], - courseplatformUrl: null, - courseplatformName: null, - officialUrl: null, - rmpQuery: `${code} ${university}`, - blogQuery: `${code} ${university} course review` - }) - } -} diff --git a/modulemapper/src/app/api/scrape/route.ts b/modulemapper/src/app/api/scrape/route.ts deleted file mode 100644 index 2d7873397..000000000 --- a/modulemapper/src/app/api/scrape/route.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { NextRequest } from "next/server"; -import { TinyFish, EventType, RunStatus, BrowserProfile } from "@tiny-fish/sdk"; - -const client = new TinyFish(); // Reads TINYFISH_API_KEY from environment - -interface ScrapeRequest { - url: string; - goal: string; - useStealthMode?: boolean; -} - -async function runAgent( - { url, goal, useStealthMode = false }: ScrapeRequest, - onProgress?: (message: string) => void, - onStreamingUrl?: (url: string) => void -): Promise<{ success: boolean; resultJson: unknown; error?: string }> { - try { - const stream = await client.agent.stream({ - url, - goal, - browser_profile: useStealthMode ? BrowserProfile.STEALTH : BrowserProfile.LITE, - }); - - for await (const event of stream) { - // Forward streaming URL as soon as it's available - if (event.type === EventType.STREAMING_URL && onStreamingUrl) { - onStreamingUrl(event.streaming_url); - } - - // Forward progress messages - if (event.type === EventType.PROGRESS && onProgress) { - onProgress(event.purpose ?? ""); - } - - // Return result on completion - if (event.type === EventType.COMPLETE) { - if (event.status === RunStatus.COMPLETED) { - return { success: true, resultJson: event.result_json }; - } else { - return { - success: false, - resultJson: null, - error: `Run failed with status: ${event.status}`, - }; - } - } - } - - return { success: false, resultJson: null, error: "Stream ended without completion event" }; - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - return { success: false, resultJson: null, error: message }; - } -} - -export async function POST(req: NextRequest) { - const encoder = new TextEncoder(); - - const sendEvent = (stream: TransformStreamDefaultController, data: object) => { - stream.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)); - }; - - const { readable, writable } = new TransformStream(); - const writer = writable.getWriter(); - - (async () => { - try { - const body: ScrapeRequest = await req.json(); - const { url, goal, useStealthMode } = body; - - if (!url || !goal) { - writer.getWriter().write( - encoder.encode( - `data: ${JSON.stringify({ type: "ERROR", error: "url and goal are required" })}\n\n` - ) - ); - writer.close(); - return; - } - - const result = await runAgent( - { url, goal, useStealthMode }, - (message) => { - writer.write( - encoder.encode(`data: ${JSON.stringify({ type: "STATUS", message })}\n\n`) - ); - }, - (streamingUrl) => { - writer.write( - encoder.encode( - `data: ${JSON.stringify({ type: "STREAMING_URL", streamingUrl })}\n\n` - ) - ); - } - ); - - writer.write( - encoder.encode( - `data: ${JSON.stringify({ - type: "COMPLETE", - success: result.success, - resultJson: result.resultJson, - error: result.error, - })}\n\n` - ) - ); - } catch (error) { - const message = error instanceof Error ? error.message : "Unknown error"; - writer.write( - encoder.encode(`data: ${JSON.stringify({ type: "ERROR", error: message })}\n\n`) - ); - } finally { - writer.close(); - } - })(); - - return new Response(readable, { - headers: { - "Content-Type": "text/event-stream", - "Cache-Control": "no-cache", - Connection: "keep-alive", - }, - }); -} diff --git a/modulemapper/src/app/api/synthesise/route.ts b/modulemapper/src/app/api/synthesise/route.ts deleted file mode 100644 index c88aade6c..000000000 --- a/modulemapper/src/app/api/synthesise/route.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { NextRequest } from 'next/server' - -export const runtime = 'nodejs' - -const GROQ_API = 'https://api.groq.com/openai/v1/chat/completions' -const GROQ_KEY = process.env.GROQ_API_KEY! - -export async function POST(req: NextRequest) { - const { code, university, results } = await req.json() - - const rawDataText = results - .filter((r: { raw: string; error?: string }) => r.raw && !r.error) - .map((r: { source: string; raw: string }) => `=== SOURCE: ${r.source} ===\n${r.raw}`) - .join('\n\n') - - if (!rawDataText.trim()) { - return Response.json({ error: 'No data scraped' }, { status: 400 }) - } - - const prompt = `You are an expert at analysing student course reviews. Analyse the following scraped data about the course ${code} at ${university} and return a structured JSON verdict. - -The data may include Reddit posts with fields like "reviews", "workloadMentions", "examTips", "professorMentions", "gradingInfo" — use ALL of these fields when building your verdict. - -SCRAPED DATA: -${rawDataText.slice(0, 14000)} - -Return ONLY valid JSON (no markdown, no explanation) with this exact structure: -{ - "score": , - "verdict": , - "summary": <2-3 sentence AI-written paragraph summarising the course experience>, - "difficulty": , - "workload": , - "hoursPerWeek": , - "hasExam": , - "examDifficulty": , - "averageGrade": , - "gradingPattern": , - "assessment": , - "attendance": , - "whatYouLearn": , - "tags": [ - {"label": , "color": <"blue"|"green"|"amber"|"red">} - ], - "bestFor": , - "notGreatIf": , - "reviews": [ - { - "text": , - "source": , - "sentiment": <"positive"|"negative"|"mixed">, - "date": - } - ], - "sourceCounts": { - : - } -} - -Rules: -- score reflects genuine student sentiment (not just your opinion) -- Extract real student quotes for reviews, at least 8 if available -- whatYouLearn should come from the official course page if available -- tags: blue=general info, green=positive trait, amber=neutral/warning, red=negative -- If data is insufficient for a field, use sensible defaults or "Unknown"` - - const response = await fetch(GROQ_API, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${GROQ_KEY}` - }, - body: JSON.stringify({ - model: 'llama-3.3-70b-versatile', - messages: [{ role: 'user', content: prompt }], - temperature: 0.3, - max_tokens: 3000 - }) - }) - - if (!response.ok) { - const err = await response.text() - return Response.json({ error: `Groq error: ${err}` }, { status: 500 }) - } - - const data = await response.json() - const text = data.choices?.[0]?.message?.content || '' - - try { - const clean = text.replace(/```json|```/g, '').trim() - const parsed = JSON.parse(clean) - return Response.json(parsed) - } catch { - return Response.json({ error: 'Failed to parse Groq response', raw: text }, { status: 500 }) - } -} diff --git a/modulemapper/src/app/globals.css b/modulemapper/src/app/globals.css deleted file mode 100644 index 4cbcd8818..000000000 --- a/modulemapper/src/app/globals.css +++ /dev/null @@ -1,54 +0,0 @@ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -:root { - --blue: #185FA5; - --blue-light: #E6F1FB; - --blue-mid: #378ADD; - --blue-dark: #0C447C; - --green-light: #EAF3DE; - --green-dark: #27500A; - --amber-light: #FAEEDA; - --amber-dark: #633806; - --red-light: #FCEBEB; - --red-dark: #791F1F; - --gray-bg: #F7F8FA; - --gray-border: #E2E6EC; - --text-primary: #0F1923; - --text-secondary: #6B7685; - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 14px; -} - -body { - font-family: 'DM Sans', sans-serif; - background: var(--gray-bg); - color: var(--text-primary); - min-height: 100vh; -} - -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.35; } -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(8px); } - to { opacity: 1; transform: translateY(0); } -} - -@keyframes shimmer { - 0% { background-position: -600px 0; } - 100% { background-position: 600px 0; } -} - -.animate-in { - animation: fadeIn 0.4s ease forwards; -} - -.skeleton { - background: linear-gradient(90deg, #e8edf2 25%, #f0f4f8 50%, #e8edf2 75%); - background-size: 600px 100%; - animation: shimmer 1.4s infinite; - border-radius: var(--radius-sm); -} diff --git a/modulemapper/src/app/layout.tsx b/modulemapper/src/app/layout.tsx deleted file mode 100644 index 16300cf37..000000000 --- a/modulemapper/src/app/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { Metadata } from 'next' -import './globals.css' - -export const metadata: Metadata = { - title: 'ModuleMapper — Real student reviews, every university', - description: 'Paste any course code and university. Get real student reviews, workload reports, grading patterns, and professor feedback in one place.', -} - -export default function RootLayout({ children }: { children: React.ReactNode }) { - return ( - - - - - - - {children} - - ) -} diff --git a/modulemapper/src/app/page.tsx b/modulemapper/src/app/page.tsx deleted file mode 100644 index 98d5edd90..000000000 --- a/modulemapper/src/app/page.tsx +++ /dev/null @@ -1,374 +0,0 @@ -'use client' -import { useState, useRef, useEffect } from 'react' -import type { CourseVerdict, ReviewCard } from '@/lib/types' - -interface Agent { - id: string - source: string - status: 'waiting' | 'running' | 'done' | 'error' - statusText?: string -} - -type AppState = 'idle' | 'discovering' | 'scraping' | 'synthesising' | 'done' | 'error' - -export default function Home() { - const [code, setCode] = useState('') - const [university, setUniversity] = useState('') - const [appState, setAppState] = useState('idle') - const [agents, setAgents] = useState([]) - const [verdict, setVerdict] = useState(null) - const [error, setError] = useState('') - const [showAllReviews, setShowAllReviews] = useState(false) - const [discoveryData, setDiscoveryData] = useState | null>(null) - const abortRef = useRef(null) - - async function handleAnalyse() { - if (!code.trim() || !university.trim()) return - setError('') - setVerdict(null) - setAgents([]) - setShowAllReviews(false) - setAppState('discovering') - - try { - const discRes = await fetch(`/api/discover?code=${encodeURIComponent(code.trim().toUpperCase())}&university=${encodeURIComponent(university.trim())}`) - const disc = await discRes.json() - if (disc.error) throw new Error(disc.error) - setDiscoveryData(disc) - setAppState('scraping') - - abortRef.current = new AbortController() - const scrapeRes = await fetch('/api/scrape', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(disc), - signal: abortRef.current.signal - }) - - if (!scrapeRes.body) throw new Error('No stream') - const reader = scrapeRes.body.getReader() - const decoder = new TextDecoder() - const allResults: { source: string; raw: string }[] = [] - let buffer = '' - - while (true) { - const { done, value } = await reader.read() - if (done) break - buffer += decoder.decode(value, { stream: true }) - const lines = buffer.split('\n') - buffer = lines.pop() || '' - - for (const line of lines) { - const trimmed = line.trim() - if (!trimmed || !trimmed.startsWith('data:')) continue - const data = trimmed.slice(5).trim() - if (data === '[DONE]') continue - try { - const event = JSON.parse(data) - if (event.type === 'agents') { - setAgents(event.agents.map((a: { id: string; source: string }) => ({ ...a, status: 'waiting' }))) - } else if (event.type === 'agent_start') { - setAgents(prev => prev.map(a => a.id === event.id ? { ...a, status: 'running', statusText: 'Scraping...' } : a)) - } else if (event.type === 'agent_done') { - setAgents(prev => prev.map(a => a.id === event.id ? { ...a, status: event.error ? 'error' : 'done', statusText: event.error ? 'Error' : 'Done' } : a)) - if (event.raw) allResults.push({ source: event.source, raw: event.raw }) - } else if (event.type === 'all_done') { - break - } - } catch { /* skip malformed */ } - } - } - - setAppState('synthesising') - const synthRes = await fetch('/api/synthesise', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ code: code.trim().toUpperCase(), university: university.trim(), results: allResults }) - }) - const synth = await synthRes.json() - if (synth.error) throw new Error(synth.error) - setVerdict(synth) - setAppState('done') - } catch (err: unknown) { - if (err instanceof Error && err.name === 'AbortError') return - setError(err instanceof Error ? err.message : 'Something went wrong') - setAppState('error') - } - } - - const displayedReviews = verdict - ? showAllReviews ? verdict.reviews : verdict.reviews.slice(0, 4) - : [] - - return ( -
-
- -
-
- - ModuleMapper - -
-

- real student reviews · any university · any course -

-
- -
-
-
- - setCode(e.target.value)} - onKeyDown={e => e.key === 'Enter' && handleAnalyse()} - style={{ width: '100%', padding: '10px 14px', border: '0.5px solid var(--gray-border)', borderRadius: 'var(--radius-md)', fontSize: 14, background: 'var(--gray-bg)', color: 'var(--text-primary)', outline: 'none', fontFamily: "'DM Mono', monospace" }} - /> -
-
- - setUniversity(e.target.value)} - onKeyDown={e => e.key === 'Enter' && handleAnalyse()} - style={{ width: '100%', padding: '10px 14px', border: '0.5px solid var(--gray-border)', borderRadius: 'var(--radius-md)', fontSize: 14, background: 'var(--gray-bg)', color: 'var(--text-primary)', outline: 'none' }} - /> -
- -
-
- - {(appState === 'scraping' || appState === 'synthesising' || appState === 'done') && agents.length > 0 && ( -
- {agents.map(agent => ( -
-
- {agent.source} {agent.status === 'done' ? '· done' : agent.status === 'error' ? '· error' : agent.status === 'running' ? '· scraping...' : '· waiting'} -
- ))} - {appState === 'synthesising' && ( -
-
- Groq is synthesising verdict... -
- )} -
- )} - - {appState === 'discovering' && ( -
-
- Discovering sources for {university}... -
- )} - - {appState === 'error' && ( -
- {error} -
- )} - - {verdict && appState === 'done' && ( -
-
-

- {code.toUpperCase()} · {university} -

-

- {(discoveryData as { title?: string })?.title || `${code.toUpperCase()} Course Review`} -

- {verdict.sourceCounts && ( -
- {Object.entries(verdict.sourceCounts).map(([src, count]) => ( - - {src} - - ))} -
- )} -
- -
-
-
-
- {typeof verdict.score === 'number' ? verdict.score.toFixed(1) : verdict.score} -
-
-
{verdict.verdict}
-
Overall verdict out of 10
-
-
-

{verdict.summary}

-
- {verdict.tags?.map((tag, i) => { - const colors: Record = { - blue: { bg: 'var(--blue-light)', text: 'var(--blue-dark)' }, - green: { bg: 'var(--green-light)', text: 'var(--green-dark)' }, - amber: { bg: 'var(--amber-light)', text: 'var(--amber-dark)' }, - red: { bg: 'var(--red-light)', text: 'var(--red-dark)' } - } - const c = colors[tag.color] || colors.blue - return ( - - {tag.label} - - ) - })} -
-
- -
-
- - -
-

{verdict.hoursPerWeek}

-
-
- -
- {[ - { label: 'Final exam', val: verdict.hasExam ? 'Yes' : 'No', sub: verdict.examDifficulty }, - { label: 'Average grade', val: verdict.averageGrade, sub: verdict.gradingPattern }, - { label: 'Assessment', val: verdict.assessment, sub: '' }, - { label: 'Attendance', val: verdict.attendance, sub: '' } - ].map((s, i) => ( -
-
{s.label}
-
{s.val}
- {s.sub &&
{s.sub}
} -
- ))} -
- - {verdict.bestFor && ( -
-
-
Best for
-
{verdict.bestFor}
-
-
-
Not great if
-
{verdict.notGreatIf}
-
-
- )} - - {verdict.whatYouLearn && verdict.whatYouLearn.length > 0 && ( -
-

What you will learn

-
- {verdict.whatYouLearn.map((item, i) => ( -
-
- {item} -
- ))} -
-
- )} - -

Student reviews

-
- {displayedReviews.map((review: ReviewCard, i: number) => { - const sentColors: Record = { - positive: { bg: 'var(--green-light)', text: 'var(--green-dark)' }, - negative: { bg: 'var(--red-light)', text: 'var(--red-dark)' }, - mixed: { bg: 'var(--amber-light)', text: 'var(--amber-dark)' } - } - const sc = sentColors[review.sentiment] || sentColors.mixed - return ( -
-
- {review.source} - {review.sentiment} -
-

"{review.text}"

- {review.date &&

{review.date}

} -
- ) - })} -
- {verdict.reviews.length > 4 && ( - - )} -
- )} -
-
- ) -} - -function DonutChart({ value, label, color }: { value: number; label: string; color: string }) { - const canvasRef = useRef(null) - - useEffect(() => { - const canvas = canvasRef.current - if (!canvas) return - const ctx = canvas.getContext('2d') - if (!ctx) return - - const size = 90 - const cx = size / 2, cy = size / 2 - const r = 32, lineW = 10 - const pct = Math.min(Math.max(value, 0), 10) / 10 - - ctx.clearRect(0, 0, size, size) - ctx.beginPath() - ctx.arc(cx, cy, r, 0, Math.PI * 2) - ctx.strokeStyle = 'rgba(0,0,0,0.07)' - ctx.lineWidth = lineW - ctx.stroke() - - ctx.beginPath() - ctx.arc(cx, cy, r, -Math.PI / 2, -Math.PI / 2 + pct * Math.PI * 2) - ctx.strokeStyle = color - ctx.lineWidth = lineW - ctx.lineCap = 'round' - ctx.stroke() - - ctx.fillStyle = '#0F1923' - ctx.font = '500 16px DM Mono, monospace' - ctx.textAlign = 'center' - ctx.textBaseline = 'middle' - ctx.fillText(Math.round(value).toString(), cx, cy) - }, [value, color]) - - return ( -
- -
{label}
-
{Math.round(value)} / 10
-
- ) -} diff --git a/modulemapper/src/lib/types.ts b/modulemapper/src/lib/types.ts deleted file mode 100644 index 3cfe2d9c5..000000000 --- a/modulemapper/src/lib/types.ts +++ /dev/null @@ -1,44 +0,0 @@ -export interface DiscoveryResult { - subreddits: string[] - courseplatform: { name: string; url: string } | null - officialpage: string | null - rmp_query: string - blog_query: string -} - -export interface AgentResult { - source: string - url: string - reviews: string[] - raw_text: string - status: 'done' | 'error' | 'empty' -} - -export interface ReviewCard { - text: string - source: string - sentiment: 'positive' | 'negative' | 'mixed' - date: string -} - -export interface CourseVerdict { - score: number - verdict: string - summary: string - difficulty: number - workload: number - hoursPerWeek: string - hasExam: boolean - examDifficulty: string - averageGrade: string - gradingPattern: string - assessment: string - attendance: string - whatYouLearn: string[] - tags: { label: string; color: 'blue' | 'green' | 'amber' | 'red' }[] - bestFor: string - notGreatIf: string - reviews: ReviewCard[] - totalReviews: number - sourceCounts: Record -} diff --git a/modulemapper/src/lib/universities.ts b/modulemapper/src/lib/universities.ts deleted file mode 100644 index 960bc2cdb..000000000 --- a/modulemapper/src/lib/universities.ts +++ /dev/null @@ -1,160 +0,0 @@ -export interface UniversityProfile { - subreddits: string[] - courseplatform: { name: string; urlTemplate: string } | null - officialTemplate: string | null - country: string -} - -const UNIVERSITY_PROFILES: Record = { - 'nus': { - subreddits: ['nus', 'SGExams', 'singapore'], - courseplatform: { name: 'NUSMods', urlTemplate: 'https://nusmods.com/modules/{code}' }, - officialTemplate: 'https://nusmods.com/modules/{code}/information', - country: 'SG' - }, - 'national university of singapore': { - subreddits: ['nus', 'SGExams', 'singapore'], - courseplatform: { name: 'NUSMods', urlTemplate: 'https://nusmods.com/modules/{code}' }, - officialTemplate: 'https://nusmods.com/modules/{code}/information', - country: 'SG' - }, - 'ntu': { - subreddits: ['ntu', 'SGExams', 'singapore'], - courseplatform: { name: 'NTU Course Review', urlTemplate: 'https://www.ntu.edu.sg/education/undergraduate-programme/courses/{code}' }, - officialTemplate: null, - country: 'SG' - }, - 'nanyang technological university': { - subreddits: ['ntu', 'SGExams', 'singapore'], - courseplatform: null, - officialTemplate: null, - country: 'SG' - }, - 'harvard': { - subreddits: ['harvard', 'ApplyingToCollege', 'college'], - courseplatform: { name: 'Harvard Course Reviews', urlTemplate: 'https://www.harvardcrimson.com/topic/courses/' }, - officialTemplate: 'https://courses.harvard.edu/search?q={code}', - country: 'US' - }, - 'mit': { - subreddits: ['mit', 'ApplyingToCollege', 'college'], - courseplatform: { name: 'Courseroad', urlTemplate: 'https://courseroad.mit.edu/' }, - officialTemplate: 'https://student.mit.edu/catalog/search.cgi?search={code}', - country: 'US' - }, - 'stanford': { - subreddits: ['stanford', 'ApplyingToCollege', 'college'], - courseplatform: { name: 'Stanford Carta', urlTemplate: 'https://carta.stanford.edu/course/{code}' }, - officialTemplate: 'https://exploredegrees.stanford.edu/search/?q={code}', - country: 'US' - }, - 'oxford': { - subreddits: ['oxford', 'UniUK', 'uniuk'], - courseplatform: null, - officialTemplate: 'https://www.ox.ac.uk/admissions/undergraduate/courses/course-listing', - country: 'UK' - }, - 'cambridge': { - subreddits: ['cambridge', 'UniUK', 'uniuk'], - courseplatform: null, - officialTemplate: 'https://www.undergraduate.study.cam.ac.uk/courses', - country: 'UK' - }, - 'imperial': { - subreddits: ['imperialcollege', 'UniUK'], - courseplatform: null, - officialTemplate: null, - country: 'UK' - }, - 'ucl': { - subreddits: ['ucl', 'UniUK'], - courseplatform: null, - officialTemplate: null, - country: 'UK' - }, - 'toronto': { - subreddits: ['uoft', 'UofT'], - courseplatform: { name: 'UofT Course Evals', urlTemplate: 'https://course-evals.utoronto.ca/' }, - officialTemplate: 'https://artsci.calendar.utoronto.ca/search-courses?course_keyword={code}', - country: 'CA' - }, - 'university of toronto': { - subreddits: ['uoft', 'UofT'], - courseplatform: { name: 'UofT Course Evals', urlTemplate: 'https://course-evals.utoronto.ca/' }, - officialTemplate: 'https://artsci.calendar.utoronto.ca/search-courses?course_keyword={code}', - country: 'CA' - }, - 'melbourne': { - subreddits: ['unimelb', 'australia'], - courseplatform: null, - officialTemplate: 'https://handbook.unimelb.edu.au/search?query={code}', - country: 'AU' - }, - 'iit': { - subreddits: ['iit', 'JEENEETards', 'india'], - courseplatform: null, - officialTemplate: null, - country: 'IN' - }, - 'nyu': { - subreddits: ['nyu', 'college'], - courseplatform: null, - officialTemplate: 'https://courses.nyu.edu/search?query={code}', - country: 'US' - }, - 'ucla': { - subreddits: ['ucla', 'college'], - courseplatform: { name: 'Bruinwalk', urlTemplate: 'https://www.bruinwalk.com/search/?q={code}' }, - officialTemplate: 'https://registrar.ucla.edu/Academics/Course-Descriptions', - country: 'US' - }, - 'uc berkeley': { - subreddits: ['berkeley', 'college'], - courseplatform: { name: 'Berkeley Course Guide', urlTemplate: 'https://guide.berkeley.edu/courses/' }, - officialTemplate: 'https://classes.berkeley.edu/search/class/?q={code}', - country: 'US' - }, - 'smu': { - subreddits: ['smusingapore', 'SGExams', 'singapore'], - courseplatform: null, - officialTemplate: null, - country: 'SG' - }, -} - -export function getUniversityProfile(university: string, courseCode: string): { - subreddits: string[] - courseplatformUrl: string | null - courseplatformName: string | null - officialUrl: string | null - rmpQuery: string - blogQuery: string -} { - const key = university.toLowerCase().trim() - let profile: UniversityProfile | null = null - - for (const [k, v] of Object.entries(UNIVERSITY_PROFILES)) { - if (key.includes(k) || k.includes(key)) { - profile = v - break - } - } - - const uniSlug = university.toLowerCase().replace(/\s+/g, '') - const subreddits = profile?.subreddits ?? [uniSlug, 'college', 'university'] - - const courseplatformUrl = profile?.courseplatform - ? profile.courseplatform.urlTemplate.replace('{code}', courseCode) - : null - - const courseplatformName = profile?.courseplatform?.name ?? null - - const officialUrl = profile?.officialTemplate - ? profile.officialTemplate.replace('{code}', courseCode) - : null - - const rmpQuery = `${courseCode} ${university}` - const blogQuery = `${courseCode} ${university} course review` - - return { subreddits, courseplatformUrl, courseplatformName, officialUrl, rmpQuery, blogQuery } -} diff --git a/modulemapper/tsconfig.json b/modulemapper/tsconfig.json deleted file mode 100644 index fba2bf379..000000000 --- a/modulemapper/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [{ "name": "next" }], - "paths": { "@/*": ["./src/*"] } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/modulemapper/tsconfig.tsbuildinfo b/modulemapper/tsconfig.tsbuildinfo deleted file mode 100644 index a3aecec55..000000000 --- a/modulemapper/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/server/after/builtin-request-context.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/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/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/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/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/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/lib/revalidate.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/build/webpack/plugins/app-build-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/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/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/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/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/prefetch-rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/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/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.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/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/clean-async-snapshot-instance.d.ts","./node_modules/next/dist/server/app-render/clean-async-snapshot.external.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata-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/collect-segment-data.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/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/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/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/client/components/react-dev-overlay/types.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/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/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/types.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/cli/next-test.d.ts","./node_modules/next/dist/server/config-shared.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/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./src/lib/universities.ts","./src/app/api/discover/route.ts","./src/app/api/scrape/route.ts","./src/app/api/synthesise/route.ts","./src/lib/types.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.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/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./src/app/layout.tsx","./src/app/page.tsx"],"fileIdsList":[[95,141],[95,138,141],[95,140,141],[141],[95,141,146,174],[95,141,142,147,152,160,171,182],[95,141,142,143,152,160],[90,91,92,95,141],[95,141,144,183],[95,141,145,146,153,161],[95,141,146,171,179],[95,141,147,149,152,160],[95,140,141,148],[95,141,149,150],[95,141,151,152],[95,140,141,152],[95,141,152,153,154,171,182],[95,141,152,153,154,167,171,174],[95,141,149,152,155,160,171,182],[95,141,152,153,155,156,160,171,179,182],[95,141,155,157,171,179,182],[93,94,95,96,97,98,99,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],[95,141,152,158],[95,141,159,182,187],[95,141,149,152,160,171],[95,141,161],[95,141,162],[95,140,141,163],[95,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],[95,141,165],[95,141,166],[95,141,152,167,168],[95,141,167,169,183,185],[95,141,152,171,172,174],[95,141,173,174],[95,141,171,172],[95,141,174],[95,141,175],[95,138,141,171,176],[95,141,152,177,178],[95,141,177,178],[95,141,146,160,171,179],[95,141,180],[95,141,160,181],[95,141,155,166,182],[95,141,146,183],[95,141,171,184],[95,141,159,185],[95,141,186],[95,136,141],[95,136,141,152,154,163,171,174,182,185,187],[95,141,171,188],[95,141,192,193,194,195,197,401,414,426],[95,141,192,193,194,195,196,401,414,426],[95,141,192,193,194,196,197,401,414,426],[95,141,192,194,195,196,197,401,414,426],[95,141,192,193,195,196,197,401,414,426],[95,141,190,191],[95,141,192],[95,141,428],[95,141,430],[95,141,432,433,434,435],[95,141,437],[86,95,141,210,211,212,214,406],[86,95,141,200,216,225,226,227,228,353,406],[95,141,406],[95,141,211,236,305,344,360],[86,95,141],[95,141,385],[95,141,200,384,406],[95,141,289,305,333,469],[95,141,298,315,344,359],[95,141,261],[95,141,348],[95,141,347,348,349],[95,141,347],[86,89,95,141,155,198,207,208,211,215,226,229,230,282,287,335,345,355,401,406],[86,95,141,213,250,285,381,382,406,469],[95,141,213,469],[95,141,285,286,287,406,469],[95,141,469],[86,95,141,213,214,469],[95,141,208,346,352],[95,141,166,306,360],[95,141,306,360],[95,141,192,306],[95,141,192,283,306,307],[95,141,241,259,360,462],[95,141,341,457,458,459,460,461],[95,141,340],[95,141,340,341],[95,141,227,238,239,283],[95,141,240,241,283],[95,141,283],[87,95,141,192,451],[95,141,182,192],[95,141,192,213,248],[95,141,192,213],[95,141,246,251],[95,141,192,247,404],[95,141,155,189,192,193,194,195,196,197,401,412,413,426],[95,141,153,155,199,216,236,264,280,283,350,406,469],[95,141,207,351],[95,141,401],[85,95,141],[95,141,166,289,303,324,326,359,360],[95,141,166,289,303,323,324,325,359,360],[95,141,317,318,319,320,321,322],[95,141,319],[95,141,323],[95,141,192,247,306,404],[95,141,192,306,402,404],[95,141,192,306,404],[95,141,280,356],[95,141,356],[95,141,155,199,404],[95,141,311],[95,140,141,310],[95,141,199,222,233,235,265,283,298,299,300,302,335,359,362],[95,141,301],[95,141,233,241,283],[95,141,298,359],[95,141,298,307,308,309,311,312,313,314,315,316,327,328,329,330,331,332,359,360,469],[95,141,296],[95,141,155,166,199,200,216,221,233,235,236,237,241,269,280,281,282,335,355,401,406,469],[95,141,359],[95,140,141,199,211,235,282,300,315,355,357,358],[95,141,298],[95,140,141,221,265,291,292,293,294,295,296,297],[95,141,155,199,200,291,292,407],[95,141,199,211,280,282,283,300,355,359],[95,141,155,200,406],[95,141,155,171,199,200,362],[83,95,141,155,166,182,198,199,200,213,216,222,233,235,236,237,242,264,265,266,268,269,272,274,277,278,279,283,354,355,360,362,363,406],[95,141,155,171],[86,87,88,95,141,216,229,362,401,404,405,469],[95,141,155,171,182,231,383,385,386,387,469],[95,141,166,182,198,231,236,265,266,272,280,283,355,360,362,367,368,369,375,381,397,398],[95,141,207,208,229,282,346,355,406],[87,95,141,155,182,265,362,373,406],[95,141,288],[95,141,155,394,395,396],[95,141,362,406],[95,141,216,235,265,354,404],[95,141,155,166,272,280,362,369,375,377,381,397,400],[95,141,155,207,208,381,390],[86,95,141,242,354,392,406],[95,141,155,213,242,376,377,388,389,391,393,406],[89,95,141,233,234,235,401,404],[83,95,141,155,166,182,207,208,215,216,222,236,237,265,266,268,269,280,283,354,355,360,361,362,367,368,369,370,372,374,404],[95,141,155,171,208,362,375,394,399],[95,141,202,203,204,205,206],[95,141,273,363],[95,141,275],[95,141,273],[95,141,275,276],[95,141,155,199,216,221],[85,87,95,141,155,166,192,200,216,222,233,235,236,237,263,362,401,404],[95,141,155,166,182,199,223,227,265,361],[95,141,292],[95,141,293],[95,141,294],[95,141,218,219],[95,141,155,216,218,222],[95,141,217,219],[95,141,220],[95,141,218,231],[95,141,218,243],[95,141,218],[95,141,271,361,363],[95,141,270],[95,141,231,360,361],[95,141,267,361],[95,141,231,360],[95,141,335],[95,141,199,222,232,234,265,283,289,300,303,304,334,362],[95,141,241,252,255,256,257,258,259],[95,141,343],[95,141,211,234,235,283,298,311,315,336,337,338,339,341,342,345,354,359,406,407],[95,141,241],[95,141,263],[95,141,155,222,234,244,260,262,264,362,401,404],[95,141,241,252,253,254,255,256,257,258,259,402],[95,141,231],[95,141,355,367,407,408],[95,141,155,363,406],[95,141,155],[95,141,291,298],[95,141,290],[83,95,141,407],[95,141,291,364,406],[95,141,155,199,223,365,366,406,407,408],[95,141,192,238,240,283],[95,141,284],[87,95,141,192],[95,141,192,360],[89,95,141,192,235,237,401,404],[87,95,141,451,452],[95,141,192,251],[85,95,141,166,182,192,245,247,249,250,404],[95,141,199,213,360],[95,141,360,371],[85,95,141,153,155,166,192,251,285,401,402,403],[95,141,192,193,194,195,196,197,401,414],[95,141,192,423,424,425,426],[95,141,146],[95,141,378,379,380],[95,141,378],[85,95,141,155,157,166,189,192,193,194,195,196,197,198,200,269,323,400,404,414,426],[95,141,439],[95,141,441],[95,141,443],[95,141,445],[95,141,447,448,449],[95,141,453],[95,141,417,427,429,431,436,438,440,442,444,446,450,454,456,464,465,467,468,469,470],[95,141,455],[95,141,463],[95,141,247],[95,141,466],[95,140,141,314,360,365,367,407,408,409,410,411,414,415,416],[95,141,189],[95,141,171,189],[95,108,112,141,182],[95,108,141,171,182],[95,103,141],[95,105,108,141,179,182],[95,141,160,179],[95,103,141,189],[95,105,108,141,160,182],[95,100,101,104,107,141,152,171,182],[95,108,115,141],[95,100,106,141],[95,108,129,130,141],[95,104,108,141,174,182,189],[95,129,141,189],[95,102,103,141,189],[95,108,141],[95,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,141],[95,108,123,141],[95,108,115,116,141],[95,106,108,116,117,141],[95,107,141],[95,100,103,108,141],[95,108,112,116,117,141],[95,112,141],[95,106,108,111,141,182],[95,100,105,108,115,141],[95,141,171],[95,103,108,129,141,187,189],[95,141,417,418],[95,141,417],[95,141,471],[95,141,192,422]],"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":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"dd721e5707f241e4ef4ab36570d9e2a79f66aad63a339e3cbdbac7d9164d2431","impliedFormat":1},{"version":"24f8562308dd8ba6013120557fa7b44950b619610b2c6cb8784c79f11e3c4f90","impliedFormat":1},{"version":"3849a7f92d0e11b785f6ae7bedb25d9aad8d1234b3f1cf530a4e7404be26dd0a","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"631eff75b0e35d1b1b31081d55209abc43e16b49426546ab5a9b40bdd40b1f60","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":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","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":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"fad4e3c207fe23922d0b2d06b01acbfb9714c4f2685cf80fd384c8a100c82fd0","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":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"2e07abf27aa06353d46f4448c0bbac73431f6065eef7113128a5cd804d0c384d","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"3da0083607976261730c44908eab1b6262f727747ef3230a65ecd0153d9e8639","impliedFormat":1},{"version":"12f0fb50e28b9d48fe5b7580580efe7cc0bd38e4b8c02d21c175aa9a4fd839b0","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"12b8dfed70961bea1861e5d39e433580e71323abb5d33da6605182ec569db584","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"7e560f533aaf88cf9d3b427dcf6c112dd3f2ee26d610e2587583b6c354c753db","impliedFormat":1},{"version":"71e0082342008e4dfb43202df85ea0986ef8e003c921a1e49999d0234a3019da","impliedFormat":1},{"version":"27ab780875bcbb65e09da7496f2ca36288b0c541abaa75c311450a077d54ec15","impliedFormat":1},{"version":"a9af0e608929aaf9ce96bd7a7b99c9360636c31d73670e4af09a09950df97841","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"b6db56e4903e9c32e533b78ac85522de734b3d3a8541bf24d256058d464bf04b","impliedFormat":1},{"version":"24daa0366f837d22c94a5c0bad5bf1fd0f6b29e1fae92dc47c3072c3fdb2fbd5","impliedFormat":1},{"version":"b68c4ed987ef5693d3dccd85222d60769463aca404f2ffca1c4c42781dce388e","impliedFormat":1},{"version":"cfb5b5d514eb4ad0ee25f313b197f3baa493eee31f27613facd71efb68206720","impliedFormat":1},{"version":"65f43099ded6073336e697512d9b80f2d4fec3182b7b2316abf712e84104db00","impliedFormat":1},{"version":"f040772329d757ecd38479991101ef7bc9bf8d8f4dd8ee5d96fe00aa264f2a2b","impliedFormat":1},{"version":"9715fe982fccf375c88ac4d3cc8f6a126a7b7596be8d60190a0c7d22b45b4be4","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"1fe24e25a00c7dd689cb8c0fb4f1048b4a6d1c50f76aaca2ca5c6cdb44e01442","impliedFormat":1},{"version":"672f293c53a07b8c1c1940797cd5c7984482a0df3dd9c1f14aaee8d3474c2d83","impliedFormat":1},{"version":"0a66cb2511fa8e3e0e6ba9c09923f664a0a00896f486e6f09fc11ff806a12b0c","impliedFormat":1},{"version":"d703f98676a44f90d63b3ffc791faac42c2af0dd2b4a312f4afdb5db471df3de","impliedFormat":1},{"version":"57d6ac03382e30e9213641ff4f18cf9402bb246b77c13c8e848c0b1ca2b7ef92","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"57e47d02e88abef89d214cdf52b478104dc17997015746e288cbb580beaef266","impliedFormat":1},{"version":"04a2d0bd8166f057cc980608bd5898bfc91198636af3c1eb6cb4eb5e8652fbea","impliedFormat":1},{"version":"376c21ad92ca004531807ea4498f90a740fd04598b45a19335a865408180eddd","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"48d37b90a04e753a925228f50304d02c4f95d57bf682f8bb688621c3cd9d32ec","impliedFormat":1},{"version":"361e2b13c6765d7f85bb7600b48fde782b90c7c41105b7dab1f6e7871071ba20","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"0cfe1d0b90d24f5c105db5a2117192d082f7d048801d22a9ea5c62fae07b80a0","impliedFormat":1},{"version":"ef61792acbfa8c27c9bd113f02731e66229f7d3a169e3c1993b508134f1a58e0","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"3ccf230b00deed31582c84b968cb3a977dae3b3446107d7aa790efaa079c06ac","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"5c2e5ca7d53236bbf483a81ae283e2695e291fe69490cd139b33fa9e71838a69","impliedFormat":1},{"version":"a73bee51e3820392023252c36348e62dd72e6bae30a345166e9c78360f1aba7e","impliedFormat":1},{"version":"6ea68b3b7d342d1716cc4293813410d3f09ff1d1ca4be14c42e6d51e810962e1","impliedFormat":1},{"version":"c319e82ac16a5a5da9e28dfdefdad72cebb5e1e67cbdcc63cce8ae86be1e454f","impliedFormat":1},{"version":"a23185bc5ef590c287c28a91baf280367b50ae4ea40327366ad01f6f4a8edbc5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"0c7c947ff881c4274c0800deaa0086971e0bfe51f89a33bd3048eaa3792d4876","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","affectsGlobalScope":true,"impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"a020158a317c07774393974d26723af551e569f1ba4d6524e8e245f10e11b976","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"15b36126e0089bfef173ab61329e8286ce74af5e809d8a72edcafd0cc049057f","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d07cbc787a997d83f7bde3877fec5fb5b12ce8c1b7047eb792996ed9726b4dde","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"8bba776476c48b0e319d243f353190f24096057acede3c2f620fee17ff885dba","impliedFormat":1},{"version":"a3abe92070fbd33714bd837806030b39cfb1f8283a98c7c1f55fffeea388809e","impliedFormat":1},{"version":"ceb6696b98a72f2dae802260c5b0940ea338de65edd372ff9e13ab0a410c3a88","impliedFormat":1},{"version":"2cd914e04d403bdc7263074c63168335d44ce9367e8a74f6896c77d4d26a1038","impliedFormat":1},{"version":"ac60bbee0d4235643cc52b57768b22de8c257c12bd8c2039860540cab1fa1d82","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"208c9af9429dd3c76f5927b971263174aaa4bc7621ddec63f163640cbd3c473c","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"45490817629431853543adcb91c0673c25af52a456479588b6486daba34f68bb","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"9f31420a5040dbfb49ab94bcaaa5103a9a464e607cabe288958f53303f1da32e","impliedFormat":1},{"version":"56013416784a6b754f3855f8f2bf6ce132320679b8a435389aca0361bce4df6b","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"9c066f3b46cf016e5d072b464821c5b21cc9adcc44743de0f6c75e2509a357ab","impliedFormat":1},{"version":"002eae065e6960458bda3cf695e578b0d1e2785523476f8a9170b103c709cd4f","impliedFormat":1},{"version":"c51641ab4bfa31b7a50a0ca37edff67f56fab3149881024345b13f2b48b7d2de","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"52abbd5035a97ebfb4240ec8ade2741229a7c26450c84eb73490dc5ea048b911","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4360ad4de54de2d5c642c4375d5eab0e7fe94ebe8adca907e6c186bbef75a54d","impliedFormat":1},{"version":"c338dff3233675f87a3869417aaea8b8bf590505106d38907dc1d0144f6402ef","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"9c9cae45dc94c2192c7d25f80649414fa13c425d0399a2c7cb2b979e4e50af42","impliedFormat":1},{"version":"068f063c2420b20f8845afadb38a14c640aed6bb01063df224edb24af92b4550","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"b8719d4483ebef35e9cb67cd5677b7e0103cf2ed8973df6aba6fdd02896ddc6e","impliedFormat":1},{"version":"643672ce383e1c58ea665a92c5481f8441edbd3e91db36e535abccbc9035adeb","impliedFormat":1},{"version":"6dd9bcf10678b889842d467706836a0ab42e6c58711e33918ed127073807ee65","impliedFormat":1},{"version":"8fa022ea514ce0ea78ac9b7092a9f97f08ead20c839c779891019e110fce8307","impliedFormat":1},{"version":"c93235337600b786fd7d0ff9c71a00f37ca65c4d63e5d695fc75153be2690f09","impliedFormat":1},{"version":"10179c817a384983f6925f778a2dac2c9427817f7d79e27d3e9b1c8d0564f1f4","impliedFormat":1},{"version":"ce791f6ea807560f08065d1af6014581eeb54a05abd73294777a281b6dfd73c2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"c0a666b005521f52e2db0b685d659d7ee9b0b60bc0d347dfc5e826c7957bdb83","impliedFormat":1},{"version":"807d38d00ce6ab9395380c0f64e52f2f158cc804ac22745d8f05f0efdec87c33","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"e17cd049a1448de4944800399daa4a64c5db8657cc9be7ef46be66e2a2cd0e7c","impliedFormat":1},{"version":"d05fb434f4ba073aed74b6c62eff1723c835de2a963dbb091e000a2decb5a691","impliedFormat":1},{"version":"10e6166be454ddb8c81000019ce1069b476b478c316e7c25965a91904ec5c1e3","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"4d4927cbee21750904af7acf940c5e3c491b4d5ebc676530211e389dd375607a","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"703989a003790524b4e34a1758941d05c121d5d352bccca55a5cfb0c76bca592","impliedFormat":1},{"version":"a58abf1f5c8feb335475097abeddd32fd71c4dc2065a3d28cf15cacabad9654a","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"671aeae7130038566a8d00affeb1b3e3b131edf93cbcfff6f55ed68f1ca4c1b3","impliedFormat":1},{"version":"f0f05149debcf31b3a717ce8dd16e0323a789905cb9e27239167b604153b8885","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"955c69dde189d5f47a886ed454ff50c69d4d8aaec3a454c9ab9c3551db727861","impliedFormat":1},{"version":"cec8b16ff98600e4f6777d1e1d4ddf815a5556a9c59bc08cc16db4fd4ae2cf00","impliedFormat":1},{"version":"9e21f8e2c0cfea713a4a372f284b60089c0841eb90bf3610539d89dbcd12d65a","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"c226288bda11cee97850f0149cc4ff5a244d42ed3f5a9f6e9b02f1162bf1e3f4","impliedFormat":1},{"version":"210a4ec6fd58f6c0358e68f69501a74aef547c82deb920c1dec7fa04f737915a","impliedFormat":1},{"version":"8eea4cc42d04d26bcbcaf209366956e9f7abaf56b0601c101016bb773730c5fe","impliedFormat":1},{"version":"f5319e38724c54dff74ee734950926a745c203dcce00bb0343cb08fbb2f6b546","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"e71e103fb212e015394def7f1379706fce637fec9f91aa88410a73b7c5cbd4e3","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"794998dc1c5a19ce77a75086fe829fb9c92f2fd07b5631c7d5e0d04fd9bc540c","impliedFormat":1},{"version":"2b0b12d0ee52373b1e7b09226eae8fbf6a2043916b7c19e2c39b15243f32bde2","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"0427df5c06fafc5fe126d14b9becd24160a288deff40e838bfbd92a35f8d0d00","impliedFormat":1},{"version":"bdc5fd605a6d315ded648abf2c691a22d0b0c774b78c15512c40ddf138e51950","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"6cd4b0986c638d92f7204d1407b1cb3e0a79d7a2d23b0f141c1a0829540ce7ef","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"d58265e159fc3cb30aa8878ba5e986a314b1759c824ff66d777b9fe42117231a","impliedFormat":1},{"version":"ff8fccaae640b0bb364340216dcc7423e55b6bb182ca2334837fee38636ad32e","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"59ee66cf96b093b18c90a8f6dbb3f0e3b65c758fba7b8b980af9f2726c32c1a2","impliedFormat":1},{"version":"c590195790d7fa35b4abed577a605d283b8336b9e01fa9bf4ae4be49855940f9","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"026a43d8239b8f12d2fc4fa5a7acbc2ad06dd989d8c71286d791d9f57ca22b78","impliedFormat":1},{"version":"3bc8605900fd1668f6d93ce8e14386478b6caa6fda41be633ee0fe4d0c716e62","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"6dcf60530c25194a9ee0962230e874ff29d34c59605d8e069a49928759a17e0a","impliedFormat":1},{"version":"7cd657e359eac7829db5f02c856993e8945ffccc71999cdfb4ab3bf801a1bbc6","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"29c2aa0712786a4a504fce3acd50928f086027276f7490965cb467d2ce638bae","impliedFormat":1},{"version":"f14e63395b54caecc486f00a39953ab00b7e4d428a4e2c38325154b08eb5dcc2","impliedFormat":1},{"version":"e749bbd37dadf82c9833278780527c717226e1e2c9bc7b2576c8ec1c40ec5647","impliedFormat":1},{"version":"46e4e179b295f08d0bd0176fe44cf6c89558c9091d3cb3894f9eaaa42ea1add1","impliedFormat":1},{"version":"1101ceda2dfd8e0c7ae87cda8053533a187ecc58c5ef72074afb97d2bf4daa08","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"29164fb428c851bc35b632761daad3ae075993a0bf9c43e9e3bc6468b32d9aa5","impliedFormat":1},{"version":"3c01539405051bffccacffd617254c8d0f665cdce00ec568c6f66ccb712b734f","impliedFormat":1},{"version":"ef9021bdfe54f4df005d0b81170bd2da9bfd86ef552cde2a049ba85c9649658f","impliedFormat":1},{"version":"17a1a0d1c492d73017c6e9a8feb79e9c8a2d41ef08b0fe51debc093a0b2e9459","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"96e1caae9b78cde35c62fee46c1ec9fa5f12c16bc1e2ab08d48e5921e29a6958","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"9e0327857503a958348d9e8e9dd57ed155a1e6ec0071eb5eb946fe06ccdf7680","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"01aa917531e116485beca44a14970834687b857757159769c16b228eb1e49c5f","impliedFormat":1},{"version":"397f568f996f8ffcf12d9156342552b0da42f6571eadba6bce61c99e1651977d","impliedFormat":1},{"version":"e2fd426f3cbc5bbff7860378784037c8fa9c1644785eed83c47c902b99b6cda9","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"a52674bc98da7979607e0f44d4c015c59c1b1d264c83fc50ec79ff2cfea06723","impliedFormat":1},{"version":"bcca16e60015db8bbf6bd117e88c5f7269337aebb05fc2b0701ae658a458c9c3","impliedFormat":1},{"version":"5e1246644fab20200cdc7c66348f3c861772669e945f2888ef58b461b81e1cd8","impliedFormat":1},{"version":"eb39550e2485298d91099e8ab2a1f7b32777d9a5ba34e9028ea8df2e64891172","impliedFormat":1},{"version":"e108f38a04a607f9386d68a4c6f3fdae1b712960f11f6482c6f1769bab056c2e","impliedFormat":1},{"version":"a3128a84a9568762a2996df79717d92154d18dd894681fc0ab3a098fa7f8ee3b","affectsGlobalScope":true,"impliedFormat":1},{"version":"347791f3792f436950396dd6171d6450234358001ae7c94ca209f1406566ccbf","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"714d8ebb298c7acc9bd1f34bd479c57d12b73371078a0c5a1883a68b8f1b9389","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"14cf3683955f914b4695e92c93aae5f3fe1e60f3321d712605164bfe53b34334","impliedFormat":1},{"version":"f11d0dcaa4a1cba6d6513b04ceb31a262f223f56e18b289c0ba3133b4d3cd9a6","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"b95a6f019095dd1d48fd04965b50dfd63e5743a6e75478343c46d2582a5132bf","impliedFormat":99},{"version":"c2008605e78208cfa9cd70bd29856b72dda7ad89df5dc895920f8e10bcb9cd0a","impliedFormat":99},{"version":"b97cb5616d2ab82a98ec9ada7b9e9cabb1f5da880ec50ea2b8dc5baa4cbf3c16","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"00b0f43b3770f66aa1e105327980c0ff17a868d0e5d9f5689f15f8d6bf4fb1f4","affectsGlobalScope":true,"impliedFormat":1},"2437cce1e0849541450f7d6b650378eecfb0a9d5bcdb937e1847ae0eece384b6","ebc82fbe351ae2cf05c6416e9c16a07319b812dfe26c5ac4e23830e3bbf171eb","2389c9637b9b150ef53f21332df2513c78bda89e1839eac01eac58291ff0b439","ac7249258edc87e40eac45bb92623ed5afb002426b8935d6adb628edaee393e6","90e6a853545dbeafc01e7b8922a57dbd7231c641108ef7e111eba1b792ba1d06",{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"51bf55bb6eb80f11b3aa59fb0a9571565a7ea304a19381f6da5630f4b2e206c4","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"02f8ef78d46c5b27f108dbb56709daa0aff625c20247abb0e6bb67cd73439f9f","impliedFormat":1},{"version":"b7fff2d004c5879cae335db8f954eb1d61242d9f2d28515e67902032723caeab","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"bb0cd7862b72f5eba39909c9889d566e198fcaddf7207c16737d0c2246112678","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"6812502cc640de74782ce9121592ae3765deb1c5c8e795b179736b308dd65e90","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"2b664c3cc544d0e35276e1fb2d4989f7d4b4027ffc64da34ec83a6ccf2e5c528","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"bad68fd0401eb90fe7da408565c8aee9c7a7021c2577aec92fa1382e8876071a","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"fec01479923e169fb52bd4f668dbeef1d7a7ea6e6d491e15617b46f2cacfa37d","impliedFormat":1},{"version":"8a8fb3097ba52f0ae6530ec6ab34e43e316506eb1d9aa29420a4b1e92a81442d","impliedFormat":1},{"version":"44e09c831fefb6fe59b8e65ad8f68a7ecc0e708d152cfcbe7ba6d6080c31c61e","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"b10bc147143031b250dc36815fd835543f67278245bf2d0a46dca765f215124e","impliedFormat":1},{"version":"87affad8e2243635d3a191fa72ef896842748d812e973b7510a55c6200b3c2a4","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"1e4c6ac595b6d734c056ac285b9ee50d27a2c7afe7d15bd14ed16210e71593b0","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"3c7b3aecd652169787b3c512d8f274a3511c475f84dcd6cead164e40cad64480","impliedFormat":1},{"version":"9a01f12466488eccd8d9eafc8fecb9926c175a4bf4a8f73a07c3bcf8b3363282","impliedFormat":1},{"version":"b80f624162276f24a4ec78b8e86fbee80ca255938e12f8b58e7a8f1a6937120b","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"272a7e7dbe05e8aaba1662ef1a16bbd57975cc352648b24e7a61b7798f3a0ad7","affectsGlobalScope":true,"impliedFormat":1},{"version":"a1219ee18b9282b4c6a31f1f0bcc9255b425e99363268ba6752a932cf76662f0","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"1d63055b690a582006435ddd3aa9c03aac16a696fac77ce2ed808f3e5a06efab","impliedFormat":1},"5c0a2669dbbab61abd3f444aa1bd6df6b0f78e8699d68c6a71f0813eaa6851be","df820e7ebf61fd57ac58aa133da1204e9b5064e8745c99c6df1900bc449728f4"],"root":[[418,422],472,473],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true,"target":4},"referencedMap":[[403,1],[138,2],[139,2],[140,3],[95,4],[141,5],[142,6],[143,7],[90,1],[93,8],[91,1],[92,1],[144,9],[145,10],[146,11],[147,12],[148,13],[149,14],[150,14],[151,15],[152,16],[153,17],[154,18],[96,1],[94,1],[155,19],[156,20],[157,21],[189,22],[158,23],[159,24],[160,25],[161,26],[162,27],[163,28],[164,29],[165,30],[166,31],[167,32],[168,32],[169,33],[170,1],[171,34],[173,35],[172,36],[174,37],[175,38],[176,39],[177,40],[178,41],[179,42],[180,43],[181,44],[182,45],[183,46],[184,47],[185,48],[186,49],[97,1],[98,1],[99,1],[137,50],[187,51],[188,52],[196,53],[197,54],[195,55],[193,56],[194,57],[190,1],[192,58],[306,59],[191,1],[429,60],[431,61],[436,62],[438,63],[213,64],[354,65],[382,66],[287,1],[228,1],[211,1],[345,67],[366,68],[212,1],[384,69],[385,70],[334,71],[342,72],[262,73],[349,74],[350,75],[348,76],[347,1],[346,77],[383,78],[214,79],[286,1],[288,80],[230,1],[233,81],[215,82],[237,81],[266,81],[88,81],[353,83],[405,1],[227,1],[312,84],[313,85],[307,86],[459,1],[315,1],[316,86],[308,87],[463,88],[462,89],[458,1],[387,1],[341,90],[340,1],[457,91],[309,59],[240,92],[238,93],[460,1],[461,1],[239,94],[452,95],[455,96],[249,97],[248,98],[247,99],[466,59],[246,100],[290,1],[410,1],[413,1],[412,59],[414,101],[84,1],[351,102],[352,103],[376,1],[226,104],[198,1],[86,105],[328,59],[327,106],[326,107],[317,1],[318,1],[325,1],[320,1],[323,108],[319,1],[321,109],[324,110],[322,109],[210,1],[224,1],[225,81],[430,111],[439,112],[443,113],[357,114],[356,1],[83,1],[415,115],[200,116],[310,117],[311,118],[303,119],[295,1],[301,1],[302,120],[332,121],[296,122],[333,123],[330,124],[329,1],[331,1],[283,125],[358,126],[359,127],[297,128],[298,129],[293,130],[337,131],[199,132],[369,133],[280,134],[223,135],[406,136],[85,66],[388,137],[399,138],[386,1],[398,139],[89,1],[374,140],[269,1],[289,141],[370,1],[217,1],[397,142],[229,1],[363,143],[355,144],[396,1],[390,145],[216,1],[391,146],[393,147],[394,148],[377,1],[395,135],[236,149],[375,150],[400,151],[201,1],[204,1],[202,1],[206,1],[203,1],[205,1],[207,152],[209,1],[274,153],[273,1],[279,154],[275,155],[278,156],[277,156],[276,155],[222,157],[264,158],[362,159],[416,1],[447,160],[449,161],[300,1],[448,162],[360,126],[314,126],[208,1],[265,163],[219,164],[220,165],[221,166],[232,167],[336,167],[243,167],[267,168],[244,168],[231,169],[218,1],[272,170],[271,171],[270,172],[268,173],[361,174],[305,175],[335,176],[304,177],[344,178],[343,179],[339,180],[261,181],[263,182],[260,183],[234,184],[282,1],[435,1],[281,185],[338,1],[364,186],[294,187],[292,188],[291,189],[408,190],[411,1],[407,191],[365,191],[433,1],[432,1],[434,1],[409,1],[367,192],[258,59],[428,1],[241,193],[250,1],[285,194],[235,1],[441,59],[451,195],[257,59],[445,86],[256,196],[402,197],[255,195],[87,1],[453,198],[253,59],[254,59],[245,1],[284,1],[252,199],[251,200],[242,201],[299,31],[368,31],[392,1],[372,202],[371,1],[437,1],[259,59],[404,203],[423,59],[426,204],[427,205],[424,59],[425,1],[389,206],[381,207],[380,1],[379,208],[378,1],[401,209],[440,210],[442,211],[444,212],[446,213],[450,214],[454,215],[471,216],[456,217],[464,218],[465,219],[467,220],[417,221],[470,104],[469,1],[468,222],[373,223],[81,1],[82,1],[13,1],[14,1],[16,1],[15,1],[2,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[23,1],[24,1],[3,1],[25,1],[26,1],[4,1],[27,1],[31,1],[28,1],[29,1],[30,1],[32,1],[33,1],[34,1],[5,1],[35,1],[36,1],[37,1],[38,1],[6,1],[42,1],[39,1],[40,1],[41,1],[43,1],[7,1],[44,1],[49,1],[50,1],[45,1],[46,1],[47,1],[48,1],[8,1],[54,1],[51,1],[52,1],[53,1],[55,1],[9,1],[56,1],[57,1],[58,1],[60,1],[59,1],[61,1],[62,1],[10,1],[63,1],[64,1],[65,1],[11,1],[66,1],[67,1],[68,1],[69,1],[70,1],[1,1],[71,1],[72,1],[12,1],[76,1],[74,1],[79,1],[78,1],[73,1],[77,1],[75,1],[80,1],[115,224],[125,225],[114,224],[135,226],[106,227],[105,228],[134,222],[128,229],[133,230],[108,231],[122,232],[107,233],[131,234],[103,235],[102,222],[132,236],[104,237],[109,238],[110,1],[113,238],[100,1],[136,239],[126,240],[117,241],[118,242],[120,243],[116,244],[119,245],[129,222],[111,246],[112,247],[121,248],[101,249],[124,240],[123,238],[127,1],[130,250],[419,251],[420,252],[421,252],[472,253],[473,254],[422,1],[418,1]],"affectedFilesPendingEmit":[419,420,421,472,473,422,418],"version":"5.9.3"} \ No newline at end of file diff --git a/modulemapper/vercel.json b/modulemapper/vercel.json deleted file mode 100644 index f92a3f8a9..000000000 --- a/modulemapper/vercel.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "framework": "nextjs" -}