From 2ae9718de35c10687b48c2464e5485f1d10467cb Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 12:31:38 -0700 Subject: [PATCH 01/62] how does routers keep getting undeleted --- .../src/server/api/routers/poly.ts | 244 ------------------ 1 file changed, 244 deletions(-) delete mode 100644 kanban-dashboard/src/server/api/routers/poly.ts diff --git a/kanban-dashboard/src/server/api/routers/poly.ts b/kanban-dashboard/src/server/api/routers/poly.ts deleted file mode 100644 index 349b9dd..0000000 --- a/kanban-dashboard/src/server/api/routers/poly.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { type UUID } from "crypto"; -import { z } from "zod"; -import { CompleteStatus, type FlowchartData } from "~/dashboard/store/types"; -import { type Course, CourseType } from "~/dashboard/store/types"; - -import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; - -const quarters: FlowchartData = { - entities: { - user: {}, - task: {}, - status: { - "c41ba2a3-5068-4a8f-b8b0-568ca295ef56": { - id: "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - title: "Fall 1", - taskIds: [], - }, - "49237786-3411-4ab5-974e-3b0078643bab": { - id: "49237786-3411-4ab5-974e-3b0078643bab", - title: "Winter 1", - taskIds: [], - }, - "c40bfef2-31c2-4228-a8cc-22b52974fbc7": { - id: "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - title: "Spring 1", - taskIds: [], - }, - - "c41ba2a3-5068-4a8f-b8b5-568ca295ef56": { - id: "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - title: "Fall 2", - taskIds: [], - }, - "49237786-3411-4ab5-9745-3b0078643bab": { - id: "49237786-3411-4ab5-974e-3b0078643bab", - title: "Winter 2", - taskIds: [], - }, - "c40bfef2-31c2-4228-a8c5-22b52974fbc7": { - id: "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - title: "Spring 2", - taskIds: [], - }, - - "c41ba2a3-5068-4a8f-b8b6-568ca295ef56": { - id: "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - title: "Fall 3", - taskIds: [], - }, - "49237786-3411-4ab5-9746-3b0078643bab": { - id: "49237786-3411-4ab5-974e-3b0078643bab", - title: "Winter 3", - taskIds: [], - }, - "c40bfef2-31c2-4228-a8c6-22b52974fbc7": { - id: "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - title: "Spring 3", - taskIds: [], - }, - - "c41ba2a3-5068-4a8f-b8b7-568ca295ef56": { - id: "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - title: "Fall 4", - taskIds: [], - }, - "49237786-3411-4ab5-9747-3b0078643bab": { - id: "49237786-3411-4ab5-974e-3b0078643bab", - title: "Winter 4", - taskIds: [], - }, - "c40bfef2-31c2-4228-a8c7-22b52974fbc7": { - id: "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - title: "Spring 4", - taskIds: [], - }, - }, - tag: {}, - comment: {}, - }, - ids: { - user: [], - task: [], - status: [ - "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - "49237786-3411-4ab5-974e-3b0078643bab", - "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b5-568ca295ef56", - "49237786-3411-4ab5-9745-3b0078643bab", - "c40bfef2-31c2-4228-a8c5-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b6-568ca295ef56", - "49237786-3411-4ab5-9746-3b0078643bab", - "c40bfef2-31c2-4228-a8c6-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b7-568ca295ef56", - "49237786-3411-4ab5-9747-3b0078643bab", - "c40bfef2-31c2-4228-a8c7-22b52974fbc7", - ], - tag: [], - comment: [], - }, -}; - -const statuses: UUID[] = [ - "c41ba2a3-5068-4a8f-b8b0-568ca295ef56", - "49237786-3411-4ab5-974e-3b0078643bab", - "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - "c40bfef2-31c2-4228-a8cc-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b5-568ca295ef56", - "c40bfef2-31c2-4228-a8c6-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b7-568ca295ef56", - "c41ba2a3-5068-4a8f-b8b6-568ca295ef56", - "49237786-3411-4ab5-9746-3b0078643bab", - "c40bfef2-31c2-4228-a8c6-22b52974fbc7", - "c41ba2a3-5068-4a8f-b8b7-568ca295ef56", - "49237786-3411-4ab5-9747-3b0078643bab", - "c40bfef2-31c2-4228-a8c7-22b52974fbc7", -]; - -const courseType_arr = Object.values(CourseType); -const completeStatus_arr = Object.values(CompleteStatus); - -const courses = [ - { - title: "CSC 101", - description: "Intro to Computer Science", - units: 4, - }, - { - title: "CSC 102", - description: "Data Structures and Algorithms", - units: 4, - }, - { - title: "CSC 202", - description: "Discrete Structures", - units: 4, - }, - { - title: "CSC 225", - description: "Introduction to Computer Organization", - units: 4, - }, - { - title: "CSC 248", - description: "Introduction to Database Systems", - units: 4, - }, - { - title: "CSC 307", - description: "Systems Programming", - units: 4, - }, - { - title: "CSC 357", - description: "Design & Analysis of Algorithms", - units: 4, - }, - { - title: "CSC 453", - description: "Operating Systems", - units: 4, - }, - { - title: "CSC 491", - description: "Senior Project Lab I", - units: 4, - }, - { - title: "CSC 492", - description: "Senior Project Lab II", - units: 4, - }, - { - title: "CSC 497", - description: "Research Senior Project I", - units: 4, - }, - { - title: "CPE 102", - description: "Introduction to Computer Science II", - units: 4, - }, - { - title: "CPE 103", - description: "Object-Oriented Design", - units: 4, - }, - { - title: "CPE 357", - description: "Introduction to Software Engineering", - units: 4, - }, - { - title: "MATH 141", - description: "Calculus I", - units: 4, - }, - { - title: "MATH 142", - description: "Calculus II", - units: 4, - }, - { - title: "MATH 206", - description: "Statistical Methods for Engineers", - units: 4, - }, - { - title: "MATH 244", - description: "Applied Linear Models", - units: 4, - }, -] as Partial[]; - -const generateQuarterSchedules = () => { - return [...courses, ...courses].map((course) => { - const courseType = - courseType_arr[Math.round(Math.random() * courseType_arr.length)]; - const completeStatus = - completeStatus_arr[Math.round(Math.random() * completeStatus_arr.length)]; - const status = statuses[Math.round(Math.random() * statuses.length)]; - return { - ...course, - courseType, - completeStatus, - status, - }; - }); -}; - -export const polyRouter = createTRPCRouter({ - hello: publicProcedure - .input(z.object({ text: z.string() })) - .query(({ input }) => { - return { - greeting: `Hello ${input.text}`, - }; - }), - quarters: publicProcedure.query(() => { - return quarters; - }), - courses: publicProcedure.query(() => { - return generateQuarterSchedules(); - }), -}); From e40afd45503a074fcf636b207a24ed130b0dc9f3 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 12:35:12 -0700 Subject: [PATCH 02/62] npm run lint --fix --- .../src/components/buttons/index.tsx | 8 ++++---- .../src/dashboard/CourseAssignment.tsx | 4 ++-- kanban-dashboard/src/dashboard/CourseCard.tsx | 6 +++--- .../src/dashboard/CourseDetails.tsx | 2 +- kanban-dashboard/src/dashboard/CurrentUser.tsx | 2 +- .../src/dashboard/FlowchartSelectingMenu.tsx | 4 ++-- kanban-dashboard/src/dashboard/Quarter.tsx | 4 ++-- kanban-dashboard/src/dashboard/UsersMenu.tsx | 2 +- kanban-dashboard/src/dashboard/state.tsx | 4 ++-- kanban-dashboard/src/pages/_app.tsx | 2 +- kanban-dashboard/src/scraping/catalog.ts | 18 +++++++++--------- kanban-dashboard/src/scraping/registrar.ts | 2 +- kanban-dashboard/src/scraping/scrape.ts | 2 +- .../src/scraping/sections_fetch.ts | 16 ++++++++-------- kanban-dashboard/src/server/api/root.ts | 6 +++--- 15 files changed, 41 insertions(+), 41 deletions(-) diff --git a/kanban-dashboard/src/components/buttons/index.tsx b/kanban-dashboard/src/components/buttons/index.tsx index ab9a9d2..1712a3f 100644 --- a/kanban-dashboard/src/components/buttons/index.tsx +++ b/kanban-dashboard/src/components/buttons/index.tsx @@ -1,6 +1,6 @@ -import React, { ReactNode, HTMLAttributes } from "react"; +import React, { type ReactNode, type HTMLAttributes } from "react"; import IconButton, { - IconButtonProps as MuiIconButtonProps, + type IconButtonProps as MuiIconButtonProps, } from "@material-ui/core/IconButton"; import AddIcon from "@material-ui/icons/Add"; import MoreHorizIcon from "@material-ui/icons/MoreHoriz"; @@ -8,8 +8,8 @@ import DeleteIcon from "@material-ui/icons/DeleteForever"; import EditIcon from "@material-ui/icons/Edit"; import CloseIcon from "@material-ui/icons/Close"; import CheckIcon from "@material-ui/icons/Check"; -import { OverridableComponent } from "@material-ui/core/OverridableComponent"; -import { SvgIconTypeMap } from "@material-ui/core/SvgIcon/SvgIcon"; +import { type OverridableComponent } from "@material-ui/core/OverridableComponent"; +import { type SvgIconTypeMap } from "@material-ui/core/SvgIcon/SvgIcon"; import Grid from "@material-ui/core/Grid"; import Button from "@material-ui/core/Button"; diff --git a/kanban-dashboard/src/dashboard/CourseAssignment.tsx b/kanban-dashboard/src/dashboard/CourseAssignment.tsx index 3d287ef..6dc13df 100644 --- a/kanban-dashboard/src/dashboard/CourseAssignment.tsx +++ b/kanban-dashboard/src/dashboard/CourseAssignment.tsx @@ -1,4 +1,4 @@ -import React, { ChangeEvent, forwardRef } from "react"; +import React, { type ChangeEvent, forwardRef } from "react"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; @@ -6,7 +6,7 @@ import { TextButton } from "../components/buttons"; import { hooks } from "./store"; import { useCourseAssignmentStyles } from "./styles"; -import { Course } from "./store/types"; +import { type Course } from "./store/types"; export interface Props { id: string; diff --git a/kanban-dashboard/src/dashboard/CourseCard.tsx b/kanban-dashboard/src/dashboard/CourseCard.tsx index e2b57f9..1d6919e 100644 --- a/kanban-dashboard/src/dashboard/CourseCard.tsx +++ b/kanban-dashboard/src/dashboard/CourseCard.tsx @@ -1,13 +1,13 @@ import React, { useMemo, useEffect, useState } from "react"; import Typography from "@material-ui/core/Typography"; import Paper from "@material-ui/core/Paper"; -import { Draggable, DraggableProvided } from "react-beautiful-dnd"; +import { Draggable, type DraggableProvided } from "react-beautiful-dnd"; import { useCardStyles } from "./styles"; import CompleteIcon from "../components/icons/complete"; import InProgressIcon from "../components/icons/in-progress"; import IncompleteIcon from "../components/icons/incomplete"; import { FlowchartState } from "~/dashboard/state"; -import { RequirementTypeSchema, RequirementType } from "~/scraping/catalog"; +import { RequirementTypeSchema, type RequirementType } from "~/scraping/catalog"; import { api } from "~/utils/api"; export interface Props { @@ -34,7 +34,7 @@ export default function CourseCard({ requirement, index }: Props) { icon: () => , }, }; - let [completeStatus, setCompleteStatus] = + const [completeStatus, setCompleteStatus] = useState("incomplete"); const { data: currentQuarter } = api.currentQuarterId.useQuery(undefined, { staleTime: Infinity, // don't refresh until the user refreshes diff --git a/kanban-dashboard/src/dashboard/CourseDetails.tsx b/kanban-dashboard/src/dashboard/CourseDetails.tsx index 5a21f27..cbb26d1 100644 --- a/kanban-dashboard/src/dashboard/CourseDetails.tsx +++ b/kanban-dashboard/src/dashboard/CourseDetails.tsx @@ -13,7 +13,7 @@ import CourseAssignment from "./CourseAssignment"; import { useCourseDetailsStyles } from "./styles"; import { useCurrentUserId } from "./CurrentUser"; import { useUser } from "./store/hooks"; -import { Course, User } from "./store/types"; +import { type Course, type User } from "./store/types"; export interface Props { id: string; diff --git a/kanban-dashboard/src/dashboard/CurrentUser.tsx b/kanban-dashboard/src/dashboard/CurrentUser.tsx index abf1226..78ad194 100644 --- a/kanban-dashboard/src/dashboard/CurrentUser.tsx +++ b/kanban-dashboard/src/dashboard/CurrentUser.tsx @@ -1,5 +1,5 @@ import React, { - ReactNode, + type ReactNode, createContext, useContext, useState, diff --git a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx index 300c9a1..e66c4e2 100644 --- a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx +++ b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx @@ -1,4 +1,4 @@ -import React, { MouseEventHandler, useState } from "react"; +import React, { type MouseEventHandler, useState } from "react"; import { makeStyles } from "@material-ui/core/styles"; import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; @@ -235,7 +235,7 @@ export default function FlowchartSelectingMenu() { select value={newFlowchartConcentration} onChange={(e) => - setNewFlowchartConcentration(e.target.value as string) + setNewFlowchartConcentration(e.target.value ) } > {/* Add your concentration options here */} diff --git a/kanban-dashboard/src/dashboard/Quarter.tsx b/kanban-dashboard/src/dashboard/Quarter.tsx index 119d8fb..f845216 100644 --- a/kanban-dashboard/src/dashboard/Quarter.tsx +++ b/kanban-dashboard/src/dashboard/Quarter.tsx @@ -1,12 +1,12 @@ import React, { useContext } from "react"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; -import { Droppable, DroppableProvided } from "react-beautiful-dnd"; +import { Droppable, type DroppableProvided } from "react-beautiful-dnd"; import CourseCard from "./CourseCard"; import { useLaneStyles } from "./styles"; import { FlowchartState } from "~/dashboard/state"; import { api } from "~/utils/api"; -import { Quarter } from "~/server/api/root"; +import { type Quarter } from "~/server/api/root"; import { TERM_SEASON } from "~/scraping/registrar"; export interface Props { diff --git a/kanban-dashboard/src/dashboard/UsersMenu.tsx b/kanban-dashboard/src/dashboard/UsersMenu.tsx index 31d7ade..bbb57dc 100644 --- a/kanban-dashboard/src/dashboard/UsersMenu.tsx +++ b/kanban-dashboard/src/dashboard/UsersMenu.tsx @@ -13,7 +13,7 @@ import { hooks } from "./store"; import { useCurrentUserId, useSetCurrentUserId } from "./CurrentUser"; import { ConfirmationButtons, EditButton } from "../components/buttons"; import { useUserItemStyles, useUserEditorStyles } from "./styles"; -import { User } from "./store/types"; +import { type User } from "./store/types"; export default function UsersMenu() { const ids = hooks.useUserIds(); diff --git a/kanban-dashboard/src/dashboard/state.tsx b/kanban-dashboard/src/dashboard/state.tsx index 99c2091..60028f6 100644 --- a/kanban-dashboard/src/dashboard/state.tsx +++ b/kanban-dashboard/src/dashboard/state.tsx @@ -3,10 +3,10 @@ import React, { useEffect, createContext, useContext, - FC, + type FC, } from "react"; -import { Requirement, type Degree } from "~/server/api/root"; +import { type Requirement, type Degree } from "~/server/api/root"; import { api } from "~/utils/api"; type Setter = React.Dispatch>; diff --git a/kanban-dashboard/src/pages/_app.tsx b/kanban-dashboard/src/pages/_app.tsx index da8e41a..372204b 100644 --- a/kanban-dashboard/src/pages/_app.tsx +++ b/kanban-dashboard/src/pages/_app.tsx @@ -1,6 +1,6 @@ import React from "react"; import Head from "next/head"; -import { AppType } from "next/app"; +import { type AppType } from "next/app"; import { ThemeProvider } from "@material-ui/core/styles"; import CssBaseline from "@material-ui/core/CssBaseline"; import "../dashboard/overrides.css"; diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index aceeac8..6821b0f 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -204,12 +204,12 @@ export const scrapeDegreeRequirements = async ( console.warn("Parsing table of unrecognized kind:", table_desc); } - var cur_section: string | null = null; + let cur_section: string | null = null; // within a select from the following block // see comment at top of file which explains these flags - var in_sftf = false; - var sftf_sep = null; - var prev_was_or = false; + let in_sftf = false; + let sftf_sep = null; + let prev_was_or = false; const rows = $(table).find("tr"); for (let i = 0; i < rows.length; i++) { const tr = rows[i]; @@ -263,7 +263,7 @@ export const scrapeDegreeRequirements = async ( console.error("unrecognized comment:", comment); } } else { - let course_elem = $(tr).find("td.codecol a[title]"); + const course_elem = $(tr).find("td.codecol a[title]"); let course: any; // TODO: type this const is_and = course_elem.length > 1; if (is_and) { @@ -275,12 +275,12 @@ export const scrapeDegreeRequirements = async ( $(tr) ); } - let course_codes: string[] = []; + const course_codes: string[] = []; $(course_elem).each((_i, c) => { course_codes.push($(c).text().trim()); }); - let course_titles = []; - let titles = $(tr).find("td:not([class])"); + const course_titles = []; + const titles = $(tr).find("td:not([class])"); $(titles) .contents() .each((i, t) => { @@ -357,7 +357,7 @@ export const scrapeDegreeRequirements = async ( const title = $(tr).find("td:not([class])").text().trim(); // TODO: more accurate units when in or/and block const unitsStr = $(tr).find("td.hourscol").text().trim() || 0; - let units = parseInt(unitsStr); + const units = parseInt(unitsStr); const code = course; const courseObj = RequirementCourseSchema.parse({ title, diff --git a/kanban-dashboard/src/scraping/registrar.ts b/kanban-dashboard/src/scraping/registrar.ts index c6ca3a4..5180599 100644 --- a/kanban-dashboard/src/scraping/registrar.ts +++ b/kanban-dashboard/src/scraping/registrar.ts @@ -81,7 +81,7 @@ export const scrapeCurrentQuarter = async () => { if (!currentQuarterCode) { let timeUntilClosestStartDate = Infinity; for (let i = 1; i < quarters.length; i++) { - let timeUntilStartDate = Math.abs(quarters[i].startDate - today); + const timeUntilStartDate = Math.abs(quarters[i].startDate - today); const startsAfterToday = quarters[i].startDate > today; if (timeUntilStartDate < timeUntilClosestStartDate && startsAfterToday) { timeUntilClosestStartDate = timeUntilStartDate; diff --git a/kanban-dashboard/src/scraping/scrape.ts b/kanban-dashboard/src/scraping/scrape.ts index 1cbcb50..fb35699 100644 --- a/kanban-dashboard/src/scraping/scrape.ts +++ b/kanban-dashboard/src/scraping/scrape.ts @@ -2,7 +2,7 @@ import cheerio from "cheerio"; const COURSE_INFO_RE = /([A-Z]+)\s+(\d+)\. (.*)$/; const URL = "https://catalog.calpoly.edu/coursesaz/csc/"; -let page = await fetch(URL).then((res) => res.text()); +const page = await fetch(URL).then((res) => res.text()); const $ = cheerio.load(page); const courses = $(".courseblock"); diff --git a/kanban-dashboard/src/scraping/sections_fetch.ts b/kanban-dashboard/src/scraping/sections_fetch.ts index 5a0e6be..50aa789 100644 --- a/kanban-dashboard/src/scraping/sections_fetch.ts +++ b/kanban-dashboard/src/scraping/sections_fetch.ts @@ -24,10 +24,10 @@ const initialFetch = await fetch(URL, { .then((res) => { if (res.status === 302) { console.log("redirected"); - let cookies = res.headers.get("set-cookie"); + const cookies = res.headers.get("set-cookie"); // NOTE: actually going to newURL is not necessary. // The only thing stopping us from getting another 302 is the cookies - let newURL = res.headers.get("location"); + const newURL = res.headers.get("location"); return fetch(newURL, { method: "GET", headers: { Cookie: cookies }, @@ -40,8 +40,8 @@ const initialFetch = await fetch(URL, { const cookies = initialFetch.headers.get("set-cookie"); let ICHiddens = await initialFetch.text().then((page) => { const $ = cheerio.load(page); - let hiddens = $("#win0divPSHIDDENFIELDS").find("input"); - let ics = new Map(); + const hiddens = $("#win0divPSHIDDENFIELDS").find("input"); + const ics = new Map(); hiddens.each((i, elem) => { ics.set($(elem).attr("name"), $(elem).attr("value")); }); @@ -146,12 +146,12 @@ const searchResultsPage = await fetch(URL, { const $ = cheerio.load(page); const courses = $("div[id*=win0divSSR_CLSRSLT_WRK_GROUPBOX2\\$]"); courses.each((i, elem) => { - let name = $(elem).find(".PAGROUPBOXLABELLEVEL1").text().trim(); + const name = $(elem).find(".PAGROUPBOXLABELLEVEL1").text().trim(); console.log(name); - let sections = $(elem).find("span[title=Class\\ Nbr]"); + const sections = $(elem).find("span[title=Class\\ Nbr]"); sections.each((i, elem) => { - let action = $(elem).find("a").attr("id"); - let num = $(elem).text(); + const action = $(elem).find("a").attr("id"); + const num = $(elem).text(); console.log(num); }); }); diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index e5f577e..136137d 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -15,7 +15,7 @@ export type { import { z } from "zod"; import { TERM_NUMBER, - Term, + type Term, TermNum, scrapeCurrentQuarter, termCode, @@ -70,8 +70,8 @@ export const appRouter = createTRPCRouter({ .input(z.object({ startYear: z.number().gte(2000) })) .output(z.array(QuarterSchema)) .query(({ input: { startYear } }) => { - let termNum = TERM_NUMBER.fall; - let quarters = []; + const termNum = TERM_NUMBER.fall; + const quarters = []; let calYear = startYear; let schoolYear = 0; From 1edb17c31123a3585274a61cfe2401dca63fad30 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 12:36:15 -0700 Subject: [PATCH 03/62] fix reimport in MenuBar --- kanban-dashboard/src/dashboard/Menubar.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index 6b938e5..9ca8ef2 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -7,8 +7,6 @@ import IconButton from "@material-ui/core/IconButton"; import FlowchartsIcon from "@material-ui/icons/Apps"; import AccountCircle from "@material-ui/icons/AccountCircle"; import Drawer from "@material-ui/core/Drawer"; -import { Select, MenuItem, InputLabel } from "@material-ui/core"; -import FlowchartSelectingMenu from "./FlowchartSelectingMenu"; import FlowchartSelectingMenu from "./FlowchartSelectingMenu"; import { useCurrentUsername } from "./CurrentUser"; From d8c6656b7fe511250fe7c6a46e695b40efccd36e Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 12:52:02 -0700 Subject: [PATCH 04/62] remove warnings for unused variables that start with '_' --- kanban-dashboard/.eslintrc.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kanban-dashboard/.eslintrc.cjs b/kanban-dashboard/.eslintrc.cjs index 8b7a0e8..92eb7b9 100644 --- a/kanban-dashboard/.eslintrc.cjs +++ b/kanban-dashboard/.eslintrc.cjs @@ -28,7 +28,7 @@ const config = { fixStyle: "inline-type-imports", }, ], - "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }], }, }; From 49285db8f007c4c0903fb44e280f61aecb475ec5 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:03:13 -0700 Subject: [PATCH 05/62] remove unused files --- kanban-dashboard/src/dashboard/UsersMenu.tsx | 134 ------------------- kanban-dashboard/src/scraping/polyflows.ts | 78 ----------- kanban-dashboard/src/scraping/sections.ts | 48 ------- 3 files changed, 260 deletions(-) delete mode 100644 kanban-dashboard/src/dashboard/UsersMenu.tsx delete mode 100644 kanban-dashboard/src/scraping/polyflows.ts delete mode 100644 kanban-dashboard/src/scraping/sections.ts diff --git a/kanban-dashboard/src/dashboard/UsersMenu.tsx b/kanban-dashboard/src/dashboard/UsersMenu.tsx deleted file mode 100644 index bbb57dc..0000000 --- a/kanban-dashboard/src/dashboard/UsersMenu.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import React, { Fragment, useState } from "react"; -import List from "@material-ui/core/List"; -import ListItem from "@material-ui/core/ListItem"; -import ListItemText from "@material-ui/core/ListItemText"; -import ListItemAvatar from "@material-ui/core/ListItemAvatar"; -import Button from "@material-ui/core/Button"; -import IconButton from "@material-ui/core/IconButton"; -import CurrentUserIcon from "@material-ui/icons/AccountCircle"; -import NonCurrentUserIcon from "@material-ui/icons/RadioButtonUnchecked"; -import TextField from "@material-ui/core/TextField"; - -import { hooks } from "./store"; -import { useCurrentUserId, useSetCurrentUserId } from "./CurrentUser"; -import { ConfirmationButtons, EditButton } from "../components/buttons"; -import { useUserItemStyles, useUserEditorStyles } from "./styles"; -import { type User } from "./store/types"; - -export default function UsersMenu() { - const ids = hooks.useUserIds(); - const createUser = hooks.useCreateUser(); - - const [isEditorOpen, setIsEditorOpen] = useState(false); - const openEditor = () => setIsEditorOpen(true); - const closeEditor = () => setIsEditorOpen(false); - const submitNewUser = (username: string) => { - createUser({ username }); - closeEditor(); - }; - - return ( - - {/* - {isEditorOpen - ? - : - } - */} - {ids.map((id) => ( - - - - ))} - - ); -} - -export interface UserItemProps { - id: string; -} -export function UserItem({ id }: UserItemProps) { - const user = hooks.useUser(id) as User; - const currentUserId = useCurrentUserId(); - const setCurrentUserId = useSetCurrentUserId(); - const updateUser = hooks.useUpdateUser(); - const [isEditing, setIsEditing] = useState(false); - const classNames = useUserItemStyles(); - - const isCurrentUser = user.id === currentUserId; - const openEditor = () => setIsEditing(true); - const closeEditor = () => setIsEditing(false); - const handleClick = () => setCurrentUserId(user.id); - const handleUpdateUsername = (username: string) => { - updateUser(id, { username }); - closeEditor(); - }; - - const icon = isCurrentUser ? : ; - - const username = isEditing ? ( - - ) : ( - user.username - ); - - return ( - - - - {icon} - - - - {username} - - - - - - ); -} - -export interface UserEditorFormProps { - username?: string; - onSubmit: (username: string) => void; - onCancel: () => void; -} -export function UserEditorForm({ - username: initialUsername = "", - onSubmit, - onCancel, -}: UserEditorFormProps) { - const [value, setValue] = useState(initialUsername); - const classNames = useUserEditorStyles(); - - const handleSubmit = () => { - if (value) { - onSubmit(value); - setValue(""); - } - }; - - const handleCancel = () => { - onCancel(); - setValue(""); - }; - - return ( -
- setValue(e.target.value)} - /> - - -
- ); -} diff --git a/kanban-dashboard/src/scraping/polyflows.ts b/kanban-dashboard/src/scraping/polyflows.ts deleted file mode 100644 index 18603d1..0000000 --- a/kanban-dashboard/src/scraping/polyflows.ts +++ /dev/null @@ -1,78 +0,0 @@ -const DOMAIN = "https://polyflowbuilder.duncanapple.io"; - -const getSCookie = async () => { - return fetch(DOMAIN).then( - (res) => res.headers.get("set-cookie").split(";")[0] - ); -}; - -const createHeaders = (s) => { - const headers = new Headers(); - // encode cookies properly - headers.append("Cookie", s); - return headers; -}; - -const login = async (s) => { - require("dotenv").config(); - const email = process.env.POLYFLOWBUILDER_EMAIL; - const password = process.env.POLYFLOWBUILDER_PWORD; - - const formData = new URLSearchParams(); - formData.append("email", email); - formData.append("password", password); - - const headers = createHeaders(s); - headers.set("Content-Type", "application/x-www-form-urlencoded"); - - return fetch(DOMAIN + "/login", { - method: "POST", - body: formData, - headers, - }).then((res) => console.assert(res.status === 200, "Login failed")); -}; - -const getFlow = async (catologYear, major) => { - const s = await getSCookie(); - - await login(s); - - const headers = createHeaders(s); - headers.set("Content-Type", "application/json"); - - const defaultFlow = await fetch(DOMAIN + "/api/util/getDefaultFlow", { - method: "POST", - headers, - body: JSON.stringify({ - flowCatalogYear: catologYear, - flowMajor: major, - flowConcentration: "", - options: { fgoRemoveGE: false }, - }), - redirect: "follow", - }); - // assert defaultFLow response content type is json - if (defaultFlow.headers.get("content-type").includes("html")) { - console.log("sent back html"); - } else if (defaultFlow.headers.get("content-type").includes("json")) { - console.log(await defaultFlow.json()); - } -}; - -const fetchAllOptions = async () => { - const s = await getSCookie(); - const headers = createHeaders(s); - await login(s); - - return fetch(DOMAIN + "/api/data/getAvailableFlowchartMetadata", { - method: "GET", - headers, - }); -}; - -(async () => { - // await getFlow("2021-2022", "52CSCBSU"); - await fetchAllOptions() - .then((res) => res.json()) - .then(console.log); -})(); diff --git a/kanban-dashboard/src/scraping/sections.ts b/kanban-dashboard/src/scraping/sections.ts deleted file mode 100644 index d231b2d..0000000 --- a/kanban-dashboard/src/scraping/sections.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { log } from "console"; -import puppeteer from "puppeteer"; - -const URL = - "https://cmsweb.pscs.calpoly.edu/psc/CSLOPRD/EMPLOYEE/SA/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"; - -const browser = await puppeteer.launch({ headless: false }); - -const page = await browser.newPage(); -await page.goto(URL); - -await page.evaluate(() => { - submitAction_win0(document.win0, "DERIVED_CLSRCH_SSR_EXPAND_COLLAPS$149$$1"); -}); - -const institutionSelect = await page.$("#CLASS_SRCH_WRK2_INSTITUTION\\$31\\$"); -await institutionSelect.evaluate((select) => { - addchg_win0(select); - submitAction_win0(select.form, select.id); -}); -// await institutionSelect.select("SLCMP"); - -// const additionalCriteriaButton = await page.$("#DERIVED_CLSRCH_SSR_EXPAND_COLLAPS\\$149\\$\\$1"); -// await additionalCriteriaButton.click(); - -// const subjectSelect = await page.$("#SSR_CLSRCH_WRK_SUBJECT_SRCH\\$0"); -// await subjectSelect.select("CSC"); -// await subjectSelect.evaluate(select => select.value="CSC") - -// const campusSelect = await page.waitForSelector("#SSR_CLSRCH_WRK_CAMPUS\\$14"); -// await campusSelect.select("MAIN"); - -// const termInput = await page.$("#SLO_SS_DERIVED_STRM"); -// await termInput.type("2234"); -// await termInput.evaluate((term) => term.value = "2234"); - -// const searchButton = await page.$("#CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH") -// await searchButton.click() - -// await page.waitForSelector('.PAPAGETITLE:contains("Search Results")') -// await page.waitForResponse(); -// while (true) { -// continue; -// } -browser.disconnect(); - -// await page.screenshot({ path: "./ss.png" }); -// await browser.close(); From bd7b990597063de7fc2134a6b2e7550fd14d8ea7 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:03:32 -0700 Subject: [PATCH 06/62] disable eslint for incomplete scraping files --- kanban-dashboard/src/scraping/scrape.ts | 4 +++- kanban-dashboard/src/scraping/sections_fetch.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/kanban-dashboard/src/scraping/scrape.ts b/kanban-dashboard/src/scraping/scrape.ts index fb35699..4f0a154 100644 --- a/kanban-dashboard/src/scraping/scrape.ts +++ b/kanban-dashboard/src/scraping/scrape.ts @@ -1,3 +1,5 @@ +/* eslint-disable */ +// TODO: remove eslint-disable once this code is being used import cheerio from "cheerio"; const COURSE_INFO_RE = /([A-Z]+)\s+(\d+)\. (.*)$/; @@ -14,7 +16,7 @@ courses.each((i, course) => { .text() .replace(units_str, "") .trim(); - const [_, major, num, name] = title_str.match(COURSE_INFO_RE); + const [_matched, major, num, name] = title_str.match(COURSE_INFO_RE) ?? []; let units = null; const units_num = units_str.replace(" units", ""); if (units_num.includes("-")) { diff --git a/kanban-dashboard/src/scraping/sections_fetch.ts b/kanban-dashboard/src/scraping/sections_fetch.ts index 50aa789..bb35e7e 100644 --- a/kanban-dashboard/src/scraping/sections_fetch.ts +++ b/kanban-dashboard/src/scraping/sections_fetch.ts @@ -1,10 +1,12 @@ +/* eslint-disable */ +// TODO: remove eslint-disable once this code is being used import assert from "assert"; import * as cheerio from "cheerio/lib/slim"; const URL = "https://cmsweb.pscs.calpoly.edu/psc/CSLOPRD/EMPLOYEE/SA/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"; -const assertNotPageNoLongerAvailable = async (body) => { +const assertNotPageNoLongerAvailable = async (body: string) => { assert(!body.includes("This page is no longer available.")); return body; }; From ea45c3c83adb20040054c771cb3837d502406312 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:14:23 -0700 Subject: [PATCH 07/62] remove unused imports --- .github/workflows/lint.yml | 2 +- kanban-dashboard/.eslintrc.cjs | 14 ++++++++++++-- kanban-dashboard/package.json | 1 + kanban-dashboard/src/components/icons/complete.tsx | 2 +- .../src/components/icons/in-progress.tsx | 2 +- .../src/components/icons/incomplete.tsx | 2 +- .../src/dashboard/CourseAssignment.tsx | 2 +- kanban-dashboard/src/dashboard/CourseCard.tsx | 2 +- .../src/dashboard/CourseEditorForm.tsx | 1 - kanban-dashboard/src/dashboard/Flowchart.tsx | 11 +---------- .../src/dashboard/FlowchartSelectingMenu.tsx | 6 +----- kanban-dashboard/src/dashboard/Menubar.tsx | 2 -- kanban-dashboard/src/dashboard/Quarter.tsx | 1 - kanban-dashboard/src/dashboard/styles.ts | 1 - kanban-dashboard/src/server/api/root.ts | 2 -- 15 files changed, 21 insertions(+), 30 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0a2d596..c5f7e49 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v3 - name: Install eslint - run: npm install eslint eslint-plugin-react@latest @typescript-eslint/eslint-plugin eslint-config-next + run: npm install eslint eslint-plugin-react@latest @typescript-eslint/eslint-plugin eslint-config-next eslint-plugin-unused-imports - name: Install tsc run: npm install typescript - name: Install prettier diff --git a/kanban-dashboard/.eslintrc.cjs b/kanban-dashboard/.eslintrc.cjs index 92eb7b9..399448d 100644 --- a/kanban-dashboard/.eslintrc.cjs +++ b/kanban-dashboard/.eslintrc.cjs @@ -18,7 +18,7 @@ const config = { parserOptions: { project: path.join(__dirname, "tsconfig.json"), }, - plugins: ["@typescript-eslint"], + plugins: ["@typescript-eslint", "unused-imports"], extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], rules: { "@typescript-eslint/consistent-type-imports": [ @@ -28,7 +28,17 @@ const config = { fixStyle: "inline-type-imports", }, ], - "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }], + "@typescript-eslint/no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + vars: "all", + varsIgnorePattern: "^_", + args: "after-used", + argsIgnorePattern: "^_", + }, + ], }, }; diff --git a/kanban-dashboard/package.json b/kanban-dashboard/package.json index 6f2349e..9e954a1 100644 --- a/kanban-dashboard/package.json +++ b/kanban-dashboard/package.json @@ -50,6 +50,7 @@ "@typescript-eslint/eslint-plugin": "^5.59.6", "eslint": "^8.40.0", "eslint-plugin-react": "^7.32.2", + "eslint-plugin-unused-imports": "^2.0.0", "prettier": "^2.8.8", "typescript": "5.0.4" } diff --git a/kanban-dashboard/src/components/icons/complete.tsx b/kanban-dashboard/src/components/icons/complete.tsx index f373b21..eb76aa8 100644 --- a/kanban-dashboard/src/components/icons/complete.tsx +++ b/kanban-dashboard/src/components/icons/complete.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from "react"; +import React from "react"; export default function CompleteIcon() { return ( diff --git a/kanban-dashboard/src/components/icons/in-progress.tsx b/kanban-dashboard/src/components/icons/in-progress.tsx index fee24a1..e4afb0b 100644 --- a/kanban-dashboard/src/components/icons/in-progress.tsx +++ b/kanban-dashboard/src/components/icons/in-progress.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from "react"; +import React from "react"; export default function InProgressIcon() { return ( diff --git a/kanban-dashboard/src/components/icons/incomplete.tsx b/kanban-dashboard/src/components/icons/incomplete.tsx index a5abe81..b9bc614 100644 --- a/kanban-dashboard/src/components/icons/incomplete.tsx +++ b/kanban-dashboard/src/components/icons/incomplete.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from "react"; +import React from "react"; export default function Incomplete() { return ( diff --git a/kanban-dashboard/src/dashboard/CourseAssignment.tsx b/kanban-dashboard/src/dashboard/CourseAssignment.tsx index 6dc13df..b36be31 100644 --- a/kanban-dashboard/src/dashboard/CourseAssignment.tsx +++ b/kanban-dashboard/src/dashboard/CourseAssignment.tsx @@ -1,4 +1,4 @@ -import React, { type ChangeEvent, forwardRef } from "react"; +import React, { type ChangeEvent } from "react"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; diff --git a/kanban-dashboard/src/dashboard/CourseCard.tsx b/kanban-dashboard/src/dashboard/CourseCard.tsx index 1d6919e..b297302 100644 --- a/kanban-dashboard/src/dashboard/CourseCard.tsx +++ b/kanban-dashboard/src/dashboard/CourseCard.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import Typography from "@material-ui/core/Typography"; import Paper from "@material-ui/core/Paper"; import { Draggable, type DraggableProvided } from "react-beautiful-dnd"; diff --git a/kanban-dashboard/src/dashboard/CourseEditorForm.tsx b/kanban-dashboard/src/dashboard/CourseEditorForm.tsx index 18dfad8..4a7af59 100644 --- a/kanban-dashboard/src/dashboard/CourseEditorForm.tsx +++ b/kanban-dashboard/src/dashboard/CourseEditorForm.tsx @@ -2,7 +2,6 @@ import React, { useState } from "react"; import TextField from "@material-ui/core/TextField"; import { ConfirmationButtons } from "../components/buttons"; -import { TextareaAutosize } from "@material-ui/core"; export interface Props { title?: string; diff --git a/kanban-dashboard/src/dashboard/Flowchart.tsx b/kanban-dashboard/src/dashboard/Flowchart.tsx index 345ed48..fc1df1b 100644 --- a/kanban-dashboard/src/dashboard/Flowchart.tsx +++ b/kanban-dashboard/src/dashboard/Flowchart.tsx @@ -1,20 +1,11 @@ -import React, { useCallback, useEffect, useState } from "react"; -import Paper from "@material-ui/core/Paper"; -import Dialog from "@material-ui/core/Dialog"; +import React from "react"; import { DragDropContext, type DropResult, - Droppable, - type DroppableProvided, // @ts-ignore } from "react-beautiful-dnd"; -import AddIcon from "@material-ui/icons/Add"; import { useBoardStyles } from "./styles"; import Quarter from "./Quarter"; -import { Fab } from "@material-ui/core"; -import CourseEditorForm from "./CourseEditorForm"; -import { useCurrentUserId } from "./CurrentUser"; -import { handleCloseModal } from "../helpers/shared"; import { FlowchartState, useMoveRequirement } from "~/dashboard/state"; import { api } from "~/utils/api"; diff --git a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx index e66c4e2..571348a 100644 --- a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx +++ b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx @@ -8,7 +8,6 @@ import IconButton from "@material-ui/core/IconButton"; import DeleteIcon from "@material-ui/icons/Delete"; import AddIcon from "@material-ui/icons/Add"; import StarIcon from "@material-ui/icons/Star"; -import StarBorderIcon from "@material-ui/icons/StarBorder"; import DuplicateIcon from "@material-ui/icons/FileCopy"; import FavoriteIcon from "@material-ui/icons/Favorite"; import MoreVertIcon from "@material-ui/icons/MoreVert"; @@ -19,14 +18,11 @@ import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; import TextField from "@material-ui/core/TextField"; -import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; -import InputLabel from "@material-ui/core/InputLabel"; -import FormControl from "@material-ui/core/FormControl"; import Menu from "@material-ui/core/Menu"; import Fade from "@material-ui/core/Fade"; import { yellow } from "@material-ui/core/colors"; -import { DialogContentText, OutlinedInput } from "@material-ui/core"; +import { DialogContentText } from "@material-ui/core"; const useStyles = makeStyles((theme) => ({ root: { diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index 9ca8ef2..5936b67 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -1,10 +1,8 @@ import React, { Fragment } from "react"; -import Link from "next/link"; import MuiAppBar from "@material-ui/core/AppBar"; import Toolbar from "@material-ui/core/Toolbar"; import Typography from "@material-ui/core/Typography"; import IconButton from "@material-ui/core/IconButton"; -import FlowchartsIcon from "@material-ui/icons/Apps"; import AccountCircle from "@material-ui/icons/AccountCircle"; import Drawer from "@material-ui/core/Drawer"; diff --git a/kanban-dashboard/src/dashboard/Quarter.tsx b/kanban-dashboard/src/dashboard/Quarter.tsx index f845216..e9d3176 100644 --- a/kanban-dashboard/src/dashboard/Quarter.tsx +++ b/kanban-dashboard/src/dashboard/Quarter.tsx @@ -5,7 +5,6 @@ import { Droppable, type DroppableProvided } from "react-beautiful-dnd"; import CourseCard from "./CourseCard"; import { useLaneStyles } from "./styles"; import { FlowchartState } from "~/dashboard/state"; -import { api } from "~/utils/api"; import { type Quarter } from "~/server/api/root"; import { TERM_SEASON } from "~/scraping/registrar"; diff --git a/kanban-dashboard/src/dashboard/styles.ts b/kanban-dashboard/src/dashboard/styles.ts index fec23fe..bb59e20 100644 --- a/kanban-dashboard/src/dashboard/styles.ts +++ b/kanban-dashboard/src/dashboard/styles.ts @@ -1,5 +1,4 @@ import { makeStyles } from "@material-ui/core/styles"; -import { BorderBottom } from "@material-ui/icons"; export const useDashboardStyles = makeStyles((theme) => ({ root: { diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 136137d..613b0eb 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -3,7 +3,6 @@ import { scrapeDegrees, scrapeDegreeRequirements, type RequirementCourse, - type Degree, DegreeSchema, RequirementTypeSchema, } from "~/scraping/catalog"; @@ -16,7 +15,6 @@ import { z } from "zod"; import { TERM_NUMBER, type Term, - TermNum, scrapeCurrentQuarter, termCode, } from "~/scraping/registrar"; From 4f087cedbbe6d85aa0bef4b19420734be98bc770 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:21:02 -0700 Subject: [PATCH 08/62] add key to course card iter --- kanban-dashboard/src/dashboard/Quarter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kanban-dashboard/src/dashboard/Quarter.tsx b/kanban-dashboard/src/dashboard/Quarter.tsx index e9d3176..db47810 100644 --- a/kanban-dashboard/src/dashboard/Quarter.tsx +++ b/kanban-dashboard/src/dashboard/Quarter.tsx @@ -39,7 +39,7 @@ export default function Quarter({ quarter }: Props) { className={classNames.tasks} > {quarterRequirements.map((requirement, index) => ( - + ))} ); From 8404cbfc56f4d800ca5b194eef87065123370841 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:21:23 -0700 Subject: [PATCH 09/62] remove unused CourseDetails and Comment files --- kanban-dashboard/src/dashboard/Comment.tsx | 50 ------- .../src/dashboard/CourseDetails.tsx | 140 ------------------ 2 files changed, 190 deletions(-) delete mode 100644 kanban-dashboard/src/dashboard/Comment.tsx delete mode 100644 kanban-dashboard/src/dashboard/CourseDetails.tsx diff --git a/kanban-dashboard/src/dashboard/Comment.tsx b/kanban-dashboard/src/dashboard/Comment.tsx deleted file mode 100644 index fff17e3..0000000 --- a/kanban-dashboard/src/dashboard/Comment.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react"; - -import { Comment as CommentView } from "../components/comment"; -import { hooks, emptyArray } from "./store"; -import { useCurrentUserId } from "./CurrentUser"; - -export interface Props { - id: string; - taskId?: string; - parentCommentId?: string; -} -export default function Comment({ id }: Props) { - const comment = hooks.useComment(id); - const createChildComment = hooks.useCreateChildComment(); - const username = hooks.useCommentUsername(id); - const currentUserId = useCurrentUserId(); - - if (!comment) { - return null; - } - - const { value, childCommentIds } = comment; - - const handleSubmitReply = (value: string, ts: Date) => { - createChildComment({ - value, - parentCommentId: id, - creatorId: currentUserId, - ts, - }); - }; - - const childCommentsElement = ( - <> - {(childCommentIds || emptyArray).map((childId) => ( - - ))} - - ); - - return ( - - ); -} diff --git a/kanban-dashboard/src/dashboard/CourseDetails.tsx b/kanban-dashboard/src/dashboard/CourseDetails.tsx deleted file mode 100644 index cbb26d1..0000000 --- a/kanban-dashboard/src/dashboard/CourseDetails.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import React, { useState } from "react"; -import Dialog from "@material-ui/core/Dialog"; -import Typography from "@material-ui/core/Typography"; -import TextField from "@material-ui/core/TextField"; -import Button from "@material-ui/core/Button"; - -import { EditButton, CloseButton, TextButton } from "../components/buttons"; -import { NewComment } from "../components/comment"; - -import { hooks } from "./store"; -import Comment from "./Comment"; -import CourseAssignment from "./CourseAssignment"; -import { useCourseDetailsStyles } from "./styles"; -import { useCurrentUserId } from "./CurrentUser"; -import { useUser } from "./store/hooks"; -import { type Course, type User } from "./store/types"; - -export interface Props { - id: string; - isOpen?: boolean; - close: () => void; -} -export default function CourseDetails({ id, isOpen, close }: Props) { - const { title, rootCommentIds, creatorId } = hooks.useCourse(id) as Course; - const updateCourse = hooks.useUpdateCourse(); - const createComment = hooks.useCreateRootComment(); - const currentUserId = useCurrentUserId(); - const creator = useUser(creatorId); - - // - // edit title - // - const [isTitleEditable, setIsTitleEditable] = useState(false); - const enableTitleEditing = () => setIsTitleEditable(true); - const disableTitleEditing = () => setIsTitleEditable(false); - const [editedTitle, setEditedTitle] = useState(title); - const editedCleanedTitle = editedTitle.trim(); - const handleClickCancelEditing = () => { - disableTitleEditing(); - setEditedTitle(title); - }; - const handleClickDoneEditing = () => { - if (editedCleanedTitle) { - updateCourse(id, { title: editedTitle }); - disableTitleEditing(); - } - }; - - // - // comments - // - const [isCommentFormShown, setIsCommentFormShown] = useState(false); - const showCommentForm = () => setIsCommentFormShown(true); - const hideCommentForm = () => setIsCommentFormShown(false); - const handleSubmitComment = (value: string) => { - createComment({ - value, - taskId: id, - creatorId: currentUserId, - ts: new Date(), - }); - hideCommentForm(); - }; - - const classNames = useCourseDetailsStyles(); - - return ( - -
-
-
- {!isTitleEditable && ( - - {title} - - )} - - {isTitleEditable && ( - <> - setEditedTitle(e.target.value)} - placeholder="Title" - /> - -
- - -
- - )} -
- - - -
- -
- - Created by {(creator as User).username} - -
- -
- Assigned to: - -
- -
- - {rootCommentIds?.length ? "Comments:" : "No comments yet..."} - - - {isCommentFormShown ? ( - - ) : ( - Leave a comment - )} - - {rootCommentIds?.map((commentId) => ( - - ))} -
-
-
- ); -} From 235c998a4466247f5b774e594bb5c71b4b020c4c Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:35:40 -0700 Subject: [PATCH 10/62] remove ts-ignores --- kanban-dashboard/src/dashboard/Flowchart.tsx | 1 - kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx | 1 - kanban-dashboard/src/dashboard/Menubar.tsx | 1 - kanban-dashboard/src/server/db.ts | 1 - 4 files changed, 4 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Flowchart.tsx b/kanban-dashboard/src/dashboard/Flowchart.tsx index fc1df1b..0fb0b71 100644 --- a/kanban-dashboard/src/dashboard/Flowchart.tsx +++ b/kanban-dashboard/src/dashboard/Flowchart.tsx @@ -2,7 +2,6 @@ import React from "react"; import { DragDropContext, type DropResult, - // @ts-ignore } from "react-beautiful-dnd"; import { useBoardStyles } from "./styles"; import Quarter from "./Quarter"; diff --git a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx index 571348a..a09069a 100644 --- a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx +++ b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx @@ -83,7 +83,6 @@ export default function FlowchartSelectingMenu() { ); const [anchorEl, setAnchorEl] = useState(null as HTMLAnchorElement | null); - // @ts-ignore const handleClick: MouseEventHandler = (event: Event) => { setAnchorEl(event.currentTarget as HTMLAnchorElement); }; diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index 5936b67..74f429b 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -27,7 +27,6 @@ export default function Menubar({ projectsUrlPath }: MenubarProps) { const open = Boolean(anchorEl); const currentUsername = useCurrentUsername(); - // @ts-ignore const handleMenu = (event) => { setAnchorEl(event.currentTarget); }; diff --git a/kanban-dashboard/src/server/db.ts b/kanban-dashboard/src/server/db.ts index bb2d14e..861093d 100644 --- a/kanban-dashboard/src/server/db.ts +++ b/kanban-dashboard/src/server/db.ts @@ -1,4 +1,3 @@ -// @ts-ignore import { PrismaClient } from "@prisma/client"; import { env } from "~/env.mjs"; From f290d568ee1c3c74e90d1ceeda98f47a6bc31f5a Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:54:05 -0700 Subject: [PATCH 11/62] remove unused variables --- kanban-dashboard/src/dashboard/Dashboard.tsx | 8 +++----- kanban-dashboard/src/dashboard/Menubar.tsx | 6 ++---- kanban-dashboard/src/dashboard/state.tsx | 3 +-- kanban-dashboard/src/dashboard/styles.ts | 4 +--- kanban-dashboard/src/pages/index.tsx | 2 +- kanban-dashboard/src/scraping/catalog.ts | 20 +++++--------------- kanban-dashboard/src/server/api/root.ts | 11 +++-------- 7 files changed, 16 insertions(+), 38 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Dashboard.tsx b/kanban-dashboard/src/dashboard/Dashboard.tsx index bc8b0e4..a3d5129 100644 --- a/kanban-dashboard/src/dashboard/Dashboard.tsx +++ b/kanban-dashboard/src/dashboard/Dashboard.tsx @@ -3,16 +3,14 @@ import Flowchart from "./Flowchart"; import { useDashboardStyles } from "./styles"; import { FlowchartStateProvider } from "~/dashboard/state"; -export interface Props { - projectsUrlPath: string; -} +export interface Props {} -export default function Dashboard({ projectsUrlPath }: Props) { +export default function Dashboard({}: Props) { const classNames = useDashboardStyles(); return (
- +
diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index 74f429b..48a9f1e 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -16,11 +16,9 @@ import { Select, MenuItem, InputLabel } from "@material-ui/core"; import { FlowchartState } from "~/dashboard/state"; import { api } from "~/utils/api"; -export interface MenubarProps { - projectsUrlPath: string; -} +export interface MenubarProps {} -export default function Menubar({ projectsUrlPath }: MenubarProps) { +export default function Menubar({}: MenubarProps) { const { setDegree, startYear } = React.useContext(FlowchartState); const classes = useMenubarStyles(); const [anchorEl, setAnchorEl] = React.useState(null); diff --git a/kanban-dashboard/src/dashboard/state.tsx b/kanban-dashboard/src/dashboard/state.tsx index 60028f6..f05bbb0 100644 --- a/kanban-dashboard/src/dashboard/state.tsx +++ b/kanban-dashboard/src/dashboard/state.tsx @@ -36,11 +36,10 @@ export const FlowchartStateProvider: FC<{ children: React.ReactNode }> = ({ // default to current year // TODO: create way to select start year const [startYear, setStartYear] = useState(new Date().getFullYear()); - const trpcClient = api.useContext(); useEffect(() => { console.log("updating requirements!"); }, [requirements]); - const requirementsQuery = api.degreeRequirements.useQuery( + const _requirementsQuery = api.degreeRequirements.useQuery( { degree, startYear }, { enabled: false, onSuccess: (data) => setRequirements(data) } ); diff --git a/kanban-dashboard/src/dashboard/styles.ts b/kanban-dashboard/src/dashboard/styles.ts index bb59e20..949134f 100644 --- a/kanban-dashboard/src/dashboard/styles.ts +++ b/kanban-dashboard/src/dashboard/styles.ts @@ -1,6 +1,6 @@ import { makeStyles } from "@material-ui/core/styles"; -export const useDashboardStyles = makeStyles((theme) => ({ +export const useDashboardStyles = makeStyles((_theme) => ({ root: { height: "100vh", display: "flex", @@ -238,8 +238,6 @@ export const useCourseDetailsStyles = makeStyles((theme) => ({ }, })); -export const useCommentStyles = makeStyles((theme) => ({})); - export const useCourseAssignmentStyles = makeStyles((theme) => ({ container: { display: "flex", diff --git a/kanban-dashboard/src/pages/index.tsx b/kanban-dashboard/src/pages/index.tsx index 6e191e5..cbea0c4 100644 --- a/kanban-dashboard/src/pages/index.tsx +++ b/kanban-dashboard/src/pages/index.tsx @@ -1,5 +1,5 @@ import { Dashboard } from "../dashboard"; export default function DashboardPage() { - return ; + return ; } diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 6821b0f..7ac4cdf 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -24,7 +24,7 @@ export const scrapeCollegesAndDepartments = async () => { const list = $("#textcontainer.page_content"); const colleges: College[] = []; - list.find("p").each((i, elem) => { + list.find("p").each((_i, elem) => { const collegeName = $(elem).text().trim(); const collegePath = $(elem).find("a").attr("href"); assert(collegePath, "collegePath is null"); @@ -33,7 +33,7 @@ export const scrapeCollegesAndDepartments = async () => { $(elem) .next("ul") .find("li>a") - .each((i, elem) => { + .each((_i, elem) => { departmentList.push( DepartmentSchema.parse({ name: $(elem).text().trim(), @@ -65,24 +65,14 @@ export const scrapeSubjects = async () => { const URL = "https://catalog.calpoly.edu/coursesaz/"; const $ = cheerio.load(await fetch(URL).then((res) => res.text())); const subjects: Subject[] = []; - $("a.sitemaplink").each((i, elem) => { + $("a.sitemaplink").each((_i, elem) => { const txt = $(elem).text(); - const [matched, subject, code] = txt.match(subjectRE) ?? []; + const [_matched, subject, code] = txt.match(subjectRE) ?? []; subjects.push(SubjectSchema.parse({ subject, code })); }); return subjects; }; -function toTitleCase(str) { - return str - .toLowerCase() - .split(" ") - .map((word) => { - return word.charAt(0).toUpperCase() + word.slice(1); - }) - .join(" "); -} - export const BACHELOR_DEGREE_KINDS = [ "BA", "BFA", @@ -109,7 +99,7 @@ export type RequirementType = z.infer; export const RequirementCourseCodeSchema = z.string(); -export const RequirementOneOfSchema = z.object({ +export const RequirementOneOfSchema: z.ZodType = z.object({ kind: z.literal("oneof"), oneof: z.array( RequirementCourseCodeSchema.or(z.lazy(() => RequirementAllOfSchema)) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 613b0eb..2f7cabd 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -25,12 +25,6 @@ const YearSchema = z .number() .gte(0, { message: "year < 0" }) .lt(4, { message: "year >= 4" }); -const TermNumSchema = z.union([ - z.literal(2), - z.literal(4), - z.literal(6), - z.literal(8), -]); const SchoolYearTermSchema = z.union([ z.literal(2), z.literal(4), @@ -68,7 +62,6 @@ export const appRouter = createTRPCRouter({ .input(z.object({ startYear: z.number().gte(2000) })) .output(z.array(QuarterSchema)) .query(({ input: { startYear } }) => { - const termNum = TERM_NUMBER.fall; const quarters = []; let calYear = startYear; @@ -76,7 +69,9 @@ export const appRouter = createTRPCRouter({ const q = (termSeason: Term) => ({ id: termCode(calYear, termSeason), - termNum: TERM_NUMBER[termSeason], + termNum: TERM_NUMBER[termSeason] as z.infer< + typeof SchoolYearTermSchema + >, year: schoolYear, }); while (schoolYear < 4) { From 0e45b0c8cf7779f4f551c7d484b8286afddf40f5 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:59:10 -0700 Subject: [PATCH 12/62] remove unused course assignment file --- .../src/dashboard/CourseAssignment.tsx | 76 ------------------- 1 file changed, 76 deletions(-) delete mode 100644 kanban-dashboard/src/dashboard/CourseAssignment.tsx diff --git a/kanban-dashboard/src/dashboard/CourseAssignment.tsx b/kanban-dashboard/src/dashboard/CourseAssignment.tsx deleted file mode 100644 index b36be31..0000000 --- a/kanban-dashboard/src/dashboard/CourseAssignment.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { type ChangeEvent } from "react"; -import Select from "@material-ui/core/Select"; -import MenuItem from "@material-ui/core/MenuItem"; - -import { TextButton } from "../components/buttons"; - -import { hooks } from "./store"; -import { useCourseAssignmentStyles } from "./styles"; -import { type Course } from "./store/types"; - -export interface Props { - id: string; -} - -export default function CourseAssignment({ id }: Props) { - const userIds = hooks.useUserIds(); - const { assigneeId } = hooks.useCourse(id) as Course; - const assignCourse = hooks.useAssignCourse(); - const unassignCourse = hooks.useUnassignCourse(); - - const handleUnassignment = () => { - unassignCourse(id, assigneeId as string); - }; - - const handleChange = ( - e: ChangeEvent<{ name?: string | undefined; value: unknown }> - ) => { - const userId = (e.target as HTMLSelectElement).value; - - userId ? assignCourse(id, userId) : handleUnassignment(); - }; - - const classNames = useCourseAssignmentStyles(); - - return ( -
- - - {assigneeId && ( -
- Unassign -
- )} -
- ); -} - -export interface AssignableUsernameProps { - id: string; -} -function AssignableUsername({ id }: AssignableUsernameProps) { - const user = hooks.useUser(id); - if (!user) { - return null; - } - - return {user.username}; -} From f5d918e76f356c2342d4a04fc9832db326b0f22d Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 13:59:20 -0700 Subject: [PATCH 13/62] fix typing in coursecard --- kanban-dashboard/src/dashboard/CourseCard.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kanban-dashboard/src/dashboard/CourseCard.tsx b/kanban-dashboard/src/dashboard/CourseCard.tsx index b297302..8c5d795 100644 --- a/kanban-dashboard/src/dashboard/CourseCard.tsx +++ b/kanban-dashboard/src/dashboard/CourseCard.tsx @@ -8,10 +8,11 @@ import InProgressIcon from "../components/icons/in-progress"; import IncompleteIcon from "../components/icons/incomplete"; import { FlowchartState } from "~/dashboard/state"; import { RequirementTypeSchema, type RequirementType } from "~/scraping/catalog"; +import { type Requirement } from "~/server/api/root"; import { api } from "~/utils/api"; export interface Props { - requirement: Course; +requirement: Requirement; index: number; } From 7c7f34f2bd476c1b66730711abe00e0eb0e4b3b2 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 14:00:38 -0700 Subject: [PATCH 14/62] fixup! remove unused CourseDetails and Comment files --- kanban-dashboard/src/dashboard/CourseCard.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kanban-dashboard/src/dashboard/CourseCard.tsx b/kanban-dashboard/src/dashboard/CourseCard.tsx index 8c5d795..f259d7f 100644 --- a/kanban-dashboard/src/dashboard/CourseCard.tsx +++ b/kanban-dashboard/src/dashboard/CourseCard.tsx @@ -7,12 +7,15 @@ import CompleteIcon from "../components/icons/complete"; import InProgressIcon from "../components/icons/in-progress"; import IncompleteIcon from "../components/icons/incomplete"; import { FlowchartState } from "~/dashboard/state"; -import { RequirementTypeSchema, type RequirementType } from "~/scraping/catalog"; +import { + RequirementTypeSchema, + type RequirementType, +} from "~/scraping/catalog"; import { type Requirement } from "~/server/api/root"; import { api } from "~/utils/api"; export interface Props { -requirement: Requirement; + requirement: Requirement; index: number; } @@ -52,7 +55,6 @@ export default function CourseCard({ requirement, index }: Props) { throw new Error("unreachable"); } }, [currentQuarter, requirement.quarterId]); - const { setRequirements } = React.useContext(FlowchartState); const courseTypeClass = (courseType: RequirementType) => { switch (courseType) { From 94193213bab563b51a60a034dcb63e7bbe291524 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 14:02:45 -0700 Subject: [PATCH 15/62] add provided.placeholder to Quarter again --- kanban-dashboard/src/dashboard/Quarter.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/kanban-dashboard/src/dashboard/Quarter.tsx b/kanban-dashboard/src/dashboard/Quarter.tsx index db47810..d0901d0 100644 --- a/kanban-dashboard/src/dashboard/Quarter.tsx +++ b/kanban-dashboard/src/dashboard/Quarter.tsx @@ -41,6 +41,7 @@ export default function Quarter({ quarter }: Props) { {quarterRequirements.map((requirement, index) => ( ))} + {provided.placeholder}
); }} From abbc94b361698511877719b66a7c9dba9775dc4f Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 14:08:04 -0700 Subject: [PATCH 16/62] gitignore package-lock --- kanban-dashboard/.gitignore | 2 + kanban-dashboard/package-lock.json | 9279 ---------------------------- 2 files changed, 2 insertions(+), 9279 deletions(-) delete mode 100644 kanban-dashboard/package-lock.json diff --git a/kanban-dashboard/.gitignore b/kanban-dashboard/.gitignore index 2971a0b..a76f866 100644 --- a/kanban-dashboard/.gitignore +++ b/kanban-dashboard/.gitignore @@ -40,3 +40,5 @@ yarn-error.log* # typescript *.tsbuildinfo +package-lock.json +pnpm-lock.yaml diff --git a/kanban-dashboard/package-lock.json b/kanban-dashboard/package-lock.json deleted file mode 100644 index 56e7f03..0000000 --- a/kanban-dashboard/package-lock.json +++ /dev/null @@ -1,9279 +0,0 @@ -{ - "name": "dashboard-testing", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "dashboard-testing", - "version": "0.1.0", - "hasInstallScript": true, - "dependencies": { - "@material-ui/core": "^4.12.4", - "@material-ui/icons": "^4.11.3", - "@prisma/client": "^4.11.0", - "@t3-oss/env-nextjs": "^0.2.1", - "@tanstack/react-query": "^4.28.0", - "@trpc/client": "^10.18.0", - "@trpc/next": "^10.18.0", - "@trpc/react-query": "^10.18.0", - "@trpc/server": "^10.18.0", - "@types/eslint": "^8.21.3", - "@types/pdfjs-dist": "^2.10.378", - "@types/react-beautiful-dnd": "^13.1.4", - "cheerio": "1.0.0-rc.12", - "eslint-config-next": "^13.4.2", - "moment": "^2.29.4", - "next": "^13.4.2", - "normalized-reducer": "^0.5.1", - "pdfjs-dist": "^3.6.172", - "prisma": "^4.14.0", - "react": "18.2.0", - "react-beautiful-dnd": "^13.1.1", - "react-dom": "18.2.0", - "react-redux": "^8.0.5", - "redux-devtools-extension": "^2.13.9", - "redux-saga": "^1.2.3", - "superjson": "1.12.2", - "uuid": "^9.0.0", - "zod": "^3.21.4" - }, - "devDependencies": { - "@types/node": "20.1.4", - "@types/react": "^18.2.6", - "@types/uuid": "^9.0.1", - "@typescript-eslint/eslint-plugin": "^5.59.6", - "eslint": "^8.40.0", - "eslint-plugin-react": "^7.32.2", - "prettier": "^2.8.8", - "typescript": "5.0.4" - } - }, - "../scraping": { - "extraneous": true, - "dependencies": { - "cheerio": "^1.0.0-rc.12", - "dotenv": "^16.0.3", - "puppeteer": "^20.0.0", - "zod": "^3.21.4" - }, - "devDependencies": { - "@types/node": "^20.1.0", - "prisma": "^4.13.0", - "ts-node": "^10.9.1", - "typescript": "^5.0.4" - } - }, - "node_modules/@babel/runtime": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", - "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@material-ui/core": { - "version": "4.12.4", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", - "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", - "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.11.5", - "@material-ui/system": "^4.12.2", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.3", - "@types/react-transition-group": "^4.2.0", - "clsx": "^1.0.4", - "hoist-non-react-statics": "^3.3.2", - "popper.js": "1.16.1-lts", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0", - "react-transition-group": "^4.4.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, - "peerDependencies": { - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/icons": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", - "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", - "dependencies": { - "@babel/runtime": "^7.4.4" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "@material-ui/core": "^4.0.0", - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/styles": { - "version": "4.11.5", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", - "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", - "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@emotion/hash": "^0.8.0", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.3", - "clsx": "^1.0.4", - "csstype": "^2.5.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.5.1", - "jss-plugin-camel-case": "^10.5.1", - "jss-plugin-default-unit": "^10.5.1", - "jss-plugin-global": "^10.5.1", - "jss-plugin-nested": "^10.5.1", - "jss-plugin-props-sort": "^10.5.1", - "jss-plugin-rule-value-function": "^10.5.1", - "jss-plugin-vendor-prefixer": "^10.5.1", - "prop-types": "^15.7.2" - }, - "engines": { - "node": ">=8.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, - "peerDependencies": { - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/system": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", - "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.3", - "csstype": "^2.5.2", - "prop-types": "^15.7.2" - }, - "engines": { - "node": ">=8.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, - "peerDependencies": { - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/types": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", - "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", - "peerDependencies": { - "@types/react": "*" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/utils": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", - "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", - "dependencies": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/@next/env": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", - "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" - }, - "node_modules/@next/eslint-plugin-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.3.tgz", - "integrity": "sha512-5B0uOnh7wyUY9vNNdIA6NUvWozhrZaTMZOzdirYAefqD0ZBK5C/h3+KMYdCKrR7JrXGvVpWnHtv54b3dCzwICA==", - "dependencies": { - "glob": "7.1.7" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", - "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", - "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", - "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", - "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", - "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", - "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", - "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", - "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", - "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgr/utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.0.tgz", - "integrity": "sha512-2OCURAmRtdlL8iUDTypMrrxfwe8frXTeXaxGsVOaYtc/wrUyk8Z/0OBetM7cdlsy7ZFWlMX72VogKeh+A4Xcjw==", - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.2.12", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@pkgr/utils/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/@prisma/client": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.14.1.tgz", - "integrity": "sha512-TZIswkeX1ccsHG/eN2kICzg/csXll0osK3EHu1QKd8VJ3XLcXozbNELKkCNfsCUvKJAwPdDtFCzF+O+raIVldw==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/engines": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.14.1.tgz", - "integrity": "sha512-APqFddPVHYmWNKqc+5J5SqrLFfOghKOLZxobmguDUacxOwdEutLsbXPVhNnpFDmuQWQFbXmrTTPoRrrF6B1MWA==", - "hasInstallScript": true - }, - "node_modules/@prisma/engines-version": { - "version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c.tgz", - "integrity": "sha512-3jum8/YSudeSN0zGW5qkpz+wAN2V/NYCQ+BPjvHYDfWatLWlQkqy99toX0GysDeaUoBIJg1vaz2yKqiA3CFcQw==" - }, - "node_modules/@redux-saga/core": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.2.3.tgz", - "integrity": "sha512-U1JO6ncFBAklFTwoQ3mjAeQZ6QGutsJzwNBjgVLSWDpZTRhobUzuVDS1qH3SKGJD8fvqoaYOjp6XJ3gCmeZWgA==", - "dependencies": { - "@babel/runtime": "^7.6.3", - "@redux-saga/deferred": "^1.2.1", - "@redux-saga/delay-p": "^1.2.1", - "@redux-saga/is": "^1.1.3", - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1", - "redux": "^4.0.4", - "typescript-tuple": "^2.2.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/redux-saga" - } - }, - "node_modules/@redux-saga/deferred": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz", - "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==" - }, - "node_modules/@redux-saga/delay-p": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz", - "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==", - "dependencies": { - "@redux-saga/symbols": "^1.1.3" - } - }, - "node_modules/@redux-saga/is": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz", - "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==", - "dependencies": { - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1" - } - }, - "node_modules/@redux-saga/symbols": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz", - "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==" - }, - "node_modules/@redux-saga/types": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz", - "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==" - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" - }, - "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@swc/helpers/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/@t3-oss/env-core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@t3-oss/env-core/-/env-core-0.2.2.tgz", - "integrity": "sha512-Jiuph14/L3L9EDaU0O0YiLeaKUcWA9c3mWYuKem8+L64i3Iwz+IbKdl5Jp4cx+JbOsS/aptwGZplnxSHhm2gMQ==", - "peerDependencies": { - "zod": "^3.0.0" - } - }, - "node_modules/@t3-oss/env-nextjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@t3-oss/env-nextjs/-/env-nextjs-0.2.2.tgz", - "integrity": "sha512-9LnVpTkf/8WkggyVN6Liz9Ma9a7fLzV00b5BngWj3HI3iWDfddsWaqCf/H0f46Bgu29NubP3Bwajf1JieVrxFA==", - "dependencies": { - "@t3-oss/env-core": "0.2.2" - }, - "peerDependencies": { - "zod": "^3.0.0" - } - }, - "node_modules/@tanstack/query-core": { - "version": "4.29.7", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.7.tgz", - "integrity": "sha512-GXG4b5hV2Loir+h2G+RXhJdoZhJLnrBWsuLB2r0qBRyhWuXq9w/dWxzvpP89H0UARlH6Mr9DiVj4SMtpkF/aUA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "4.29.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.7.tgz", - "integrity": "sha512-ijBWEzAIo09fB1yd22slRZzprrZ5zMdWYzBnCg5qiXuFbH78uGN1qtGz8+Ed4MuhaPaYSD+hykn+QEKtQviEtg==", - "dependencies": { - "@tanstack/query-core": "4.29.7", - "use-sync-external-store": "^1.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@trpc/client": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.26.0.tgz", - "integrity": "sha512-ojHxQFIE97rBEGPK8p1ijbzo0T1IdEBoJ9fFSgWWL9FMuEEA/DNQ9s0uuiOrDKhCCdTFT1unfRharoJhB2/O2w==", - "peerDependencies": { - "@trpc/server": "10.26.0" - } - }, - "node_modules/@trpc/next": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/next/-/next-10.26.0.tgz", - "integrity": "sha512-p328crXBH6C228LKxjqbpDEXdLmy4+LdgsZuYK3oFMqaJEmCT22b+zcQ9IvQrcPfDxhKOpJym0QpuDNaWpG2qg==", - "dependencies": { - "react-ssr-prepass": "^1.5.0" - }, - "peerDependencies": { - "@tanstack/react-query": "^4.18.0", - "@trpc/client": "10.26.0", - "@trpc/react-query": "10.26.0", - "@trpc/server": "10.26.0", - "next": "*", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@trpc/react-query": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.26.0.tgz", - "integrity": "sha512-n+enpalaCZhd3A/mbZmXeydRZHsAJo7mzc2ncgHn5S+C3SrfOM897uQdbHdj02Li25ULxzP1O92w+vZzmFbgkA==", - "peerDependencies": { - "@tanstack/react-query": "^4.18.0", - "@trpc/client": "10.26.0", - "@trpc/server": "10.26.0", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@trpc/server": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.26.0.tgz", - "integrity": "sha512-+Wt0NFAeflVSNiUnHIDNN3C8jP7XIRmYrcgJ6IsAnm0lK4p/FkpCpeu1aig5qxrgZx30PHNDLZ/3FttVSEW2aQ==" - }, - "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "license": "MIT", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "license": "MIT" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, - "node_modules/@types/node": { - "version": "20.1.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.4.tgz", - "integrity": "sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q==", - "dev": true - }, - "node_modules/@types/pdfjs-dist": { - "version": "2.10.378", - "resolved": "https://registry.npmjs.org/@types/pdfjs-dist/-/pdfjs-dist-2.10.378.tgz", - "integrity": "sha512-TRdIPqdsvKmPla44kVy4jv5Nt5vjMfVjbIEke1CRULIrwKNRC4lIiZvNYDJvbUMNCFPNIUcOKhXTyMJrX18IMA==", - "deprecated": "This is a stub types definition. pdfjs-dist provides its own type definitions, so you do not need this installed.", - "dependencies": { - "pdfjs-dist": "*" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" - }, - "node_modules/@types/react": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.7.tgz", - "integrity": "sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-beautiful-dnd": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.4.tgz", - "integrity": "sha512-4bIBdzOr0aavN+88q3C7Pgz+xkb7tz3whORYrmSj77wfVEMfiWiooIwVWFR7KM2e+uGTe5BVrXqSfb0aHeflJA==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-redux": { - "version": "7.1.25", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", - "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", - "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react/node_modules/csstype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", - "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==" - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, - "node_modules/@types/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz", - "integrity": "sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/type-utils": "5.59.6", - "@typescript-eslint/utils": "5.59.6", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", - "integrity": "sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==", - "dependencies": { - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz", - "integrity": "sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==", - "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz", - "integrity": "sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.6", - "@typescript-eslint/utils": "5.59.6", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.6.tgz", - "integrity": "sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz", - "integrity": "sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==", - "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.6.tgz", - "integrity": "sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz", - "integrity": "sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==", - "dependencies": { - "@typescript-eslint/types": "5.59.6", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.1.tgz", - "integrity": "sha512-sCXXUhA+cljomZ3ZAwb8i1p3oOlkABzPy08ZDAoGcYuvtBPlQ1Ytde129ArXyHWDhfeewq7rlx9F+cUx2SSlkg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c= sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==" - }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dependencies": { - "run-applescript": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001482", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz", - "integrity": "sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ==", - "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/canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "optional": true, - "engines": { - "node": ">=10" - } - }, - "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==" - }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true - }, - "node_modules/copy-anything": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.4.tgz", - "integrity": "sha512-MaQ9FwzlZ/KLeVCLhzI3rZw0EhrIryfZa3AyT4agVybR0DjlkDHA8898lamLD6kfkf9MMn8D+zDAUR4+GxaymQ==", - "dependencies": { - "is-what": "^4.1.8" - }, - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-box-model": { - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "tiny-invariant": "^1.0.6" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-vendor": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", - "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", - "dependencies": { - "@babel/runtime": "^7.8.3", - "is-in-browser": "^1.0.2" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true - }, - "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", - "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/dom-helpers/node_modules/csstype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", - "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==" - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/enhanced-resolve": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", - "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.3.tgz", - "integrity": "sha512-1lXwdFi29fKxzeugof/TUE7lpHyJQt5+U4LaUHyvQfHjvsWO77vFNicJv5sX6k0VDVSbnfz0lw+avxI+CinbMg==", - "dependencies": { - "@next/eslint-plugin-next": "13.4.3", - "@rushstack/eslint-patch": "^1.1.3", - "@typescript-eslint/parser": "^5.42.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.31.7", - "eslint-plugin-react-hooks": "^4.5.0" - }, - "peerDependencies": { - "eslint": "^7.23.0 || ^8.0.0", - "typescript": ">=3.3.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", - "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "get-tsconfig": "^4.5.0", - "globby": "^13.1.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.5" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/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==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-glob/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/fast-glob/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz", - "integrity": "sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==", - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-in-browser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-what": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.9.tgz", - "integrity": "sha512-I3FU0rkVvwhgLLEs6iITwZ/JaLXe7tQcHyzupXky8jigt1vu4KM0UOqDr963j36JRvJ835EATVIm6MnGz/i1/g==", - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/jss": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", - "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "csstype": "^3.0.2", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/jss" - } - }, - "node_modules/jss-plugin-camel-case": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", - "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "hyphenate-style-name": "^1.0.3", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-default-unit": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", - "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-global": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", - "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-nested": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", - "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "node_modules/jss-plugin-props-sort": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", - "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "node_modules/jss-plugin-rule-value-function": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", - "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "node_modules/jss-plugin-vendor-prefixer": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", - "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.8", - "jss": "10.10.0" - } - }, - "node_modules/jss/node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "optional": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "optional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/memoize-one": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", - "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", - "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", - "dependencies": { - "@next/env": "13.4.3", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "zod": "3.21.4" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=16.8.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.3", - "@next/swc-darwin-x64": "13.4.3", - "@next/swc-linux-arm64-gnu": "13.4.3", - "@next/swc-linux-arm64-musl": "13.4.3", - "@next/swc-linux-x64-gnu": "13.4.3", - "@next/swc-linux-x64-musl": "13.4.3", - "@next/swc-win32-arm64-msvc": "13.4.3", - "@next/swc-win32-ia32-msvc": "13.4.3", - "@next/swc-win32-x64-msvc": "13.4.3" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "optional": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalized-reducer": { - "version": "0.5.1", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dependencies": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dependencies": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path2d-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pdfjs-dist": { - "version": "3.6.172", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.6.172.tgz", - "integrity": "sha512-bfOhCg+S9DXh/ImWhWYTOiq3aVMFSCvzGiBzsIJtdMC71kVWDBw7UXr32xh0y56qc5wMVylIeqV3hBaRsu+e+w==", - "dependencies": { - "path2d-polyfill": "^2.0.1", - "web-streams-polyfill": "^3.2.1" - }, - "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "canvas": "^2.11.2" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/popper.js": { - "version": "1.16.1-lts", - "license": "MIT" - }, - "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prisma": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.14.1.tgz", - "integrity": "sha512-z6hxzTMYqT9SIKlzD08dhzsLUpxjFKKsLpp5/kBDnSqiOjtUyyl/dC5tzxLcOa3jkEHQ8+RpB/fE3w8bgNP51g==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines": "4.14.1" - }, - "bin": { - "prisma": "build/index.js", - "prisma2": "build/index.js" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/raf-schd": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz", - "integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==" - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-beautiful-dnd": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", - "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", - "dependencies": { - "@babel/runtime": "^7.9.2", - "css-box-model": "^1.2.0", - "memoize-one": "^5.1.1", - "raf-schd": "^4.0.2", - "react-redux": "^7.2.0", - "redux": "^4.0.4", - "use-memo-one": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8.5 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-beautiful-dnd/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/react-beautiful-dnd/node_modules/react-redux": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", - "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", - "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "peerDependencies": { - "react": "^16.8.3 || ^17 || ^18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "license": "MIT" - }, - "node_modules/react-redux": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", - "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-ssr-prepass": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz", - "integrity": "sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "dependencies": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, - "node_modules/redux-devtools-extension": { - "version": "2.13.9", - "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz", - "integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==", - "deprecated": "Package moved to @redux-devtools/extension.", - "peerDependencies": { - "redux": "^3.1.0 || ^4.0.0" - } - }, - "node_modules/redux-saga": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.2.3.tgz", - "integrity": "sha512-HDe0wTR5nhd8Xr5xjGzoyTbdAw6rjy1GDplFt3JKtKN8/MnkQSRqK/n6aQQhpw5NI4ekDVOaW+w4sdxPBaCoTQ==", - "dependencies": { - "@redux-saga/core": "^1.2.3" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/run-applescript/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/run-applescript/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/run-applescript/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-applescript/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "optional": true - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/superjson": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.12.2.tgz", - "integrity": "sha512-ugvUo9/WmvWOjstornQhsN/sR9mnGtWGYeTxFuqLb4AiT4QdUavjGFRALCPKWWnAiUJ4HTpytj5e0t5HoMRkXg==", - "dependencies": { - "copy-anything": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "optional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "optional": true - }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/typescript-compare": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", - "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", - "dependencies": { - "typescript-logic": "^0.0.0" - } - }, - "node_modules/typescript-logic": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", - "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" - }, - "node_modules/typescript-tuple": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", - "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", - "dependencies": { - "typescript-compare": "^0.0.2" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/use-memo-one": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", - "integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ==", - "peerDependencies": { - "react": "^16.8.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "optional": true - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "optional": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "optional": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - }, - "dependencies": { - "@babel/runtime": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", - "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", - "optional": true, - "requires": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - } - }, - "@material-ui/core": { - "version": "4.12.4", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", - "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", - "requires": { - "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.11.5", - "@material-ui/system": "^4.12.2", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.3", - "@types/react-transition-group": "^4.2.0", - "clsx": "^1.0.4", - "hoist-non-react-statics": "^3.3.2", - "popper.js": "1.16.1-lts", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0", - "react-transition-group": "^4.4.0" - } - }, - "@material-ui/icons": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", - "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", - "requires": { - "@babel/runtime": "^7.4.4" - } - }, - "@material-ui/styles": { - "version": "4.11.5", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", - "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", - "requires": { - "@babel/runtime": "^7.4.4", - "@emotion/hash": "^0.8.0", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.3", - "clsx": "^1.0.4", - "csstype": "^2.5.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.5.1", - "jss-plugin-camel-case": "^10.5.1", - "jss-plugin-default-unit": "^10.5.1", - "jss-plugin-global": "^10.5.1", - "jss-plugin-nested": "^10.5.1", - "jss-plugin-props-sort": "^10.5.1", - "jss-plugin-rule-value-function": "^10.5.1", - "jss-plugin-vendor-prefixer": "^10.5.1", - "prop-types": "^15.7.2" - } - }, - "@material-ui/system": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", - "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", - "requires": { - "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.3", - "csstype": "^2.5.2", - "prop-types": "^15.7.2" - } - }, - "@material-ui/types": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", - "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" - }, - "@material-ui/utils": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", - "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", - "requires": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - } - }, - "@next/env": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", - "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" - }, - "@next/eslint-plugin-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.3.tgz", - "integrity": "sha512-5B0uOnh7wyUY9vNNdIA6NUvWozhrZaTMZOzdirYAefqD0ZBK5C/h3+KMYdCKrR7JrXGvVpWnHtv54b3dCzwICA==", - "requires": { - "glob": "7.1.7" - } - }, - "@next/swc-darwin-arm64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", - "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", - "optional": true - }, - "@next/swc-darwin-x64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", - "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", - "optional": true - }, - "@next/swc-linux-arm64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", - "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", - "optional": true - }, - "@next/swc-linux-arm64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", - "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", - "optional": true - }, - "@next/swc-linux-x64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", - "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", - "optional": true - }, - "@next/swc-linux-x64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", - "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", - "optional": true - }, - "@next/swc-win32-arm64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", - "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", - "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", - "optional": true - }, - "@next/swc-win32-x64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", - "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", - "optional": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgr/utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.0.tgz", - "integrity": "sha512-2OCURAmRtdlL8iUDTypMrrxfwe8frXTeXaxGsVOaYtc/wrUyk8Z/0OBetM7cdlsy7ZFWlMX72VogKeh+A4Xcjw==", - "requires": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.2.12", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.5.0" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "@prisma/client": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.14.1.tgz", - "integrity": "sha512-TZIswkeX1ccsHG/eN2kICzg/csXll0osK3EHu1QKd8VJ3XLcXozbNELKkCNfsCUvKJAwPdDtFCzF+O+raIVldw==", - "requires": { - "@prisma/engines-version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c" - } - }, - "@prisma/engines": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.14.1.tgz", - "integrity": "sha512-APqFddPVHYmWNKqc+5J5SqrLFfOghKOLZxobmguDUacxOwdEutLsbXPVhNnpFDmuQWQFbXmrTTPoRrrF6B1MWA==" - }, - "@prisma/engines-version": { - "version": "4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.14.0-67.d9a4c5988f480fa576d43970d5a23641aa77bc9c.tgz", - "integrity": "sha512-3jum8/YSudeSN0zGW5qkpz+wAN2V/NYCQ+BPjvHYDfWatLWlQkqy99toX0GysDeaUoBIJg1vaz2yKqiA3CFcQw==" - }, - "@redux-saga/core": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.2.3.tgz", - "integrity": "sha512-U1JO6ncFBAklFTwoQ3mjAeQZ6QGutsJzwNBjgVLSWDpZTRhobUzuVDS1qH3SKGJD8fvqoaYOjp6XJ3gCmeZWgA==", - "requires": { - "@babel/runtime": "^7.6.3", - "@redux-saga/deferred": "^1.2.1", - "@redux-saga/delay-p": "^1.2.1", - "@redux-saga/is": "^1.1.3", - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1", - "redux": "^4.0.4", - "typescript-tuple": "^2.2.1" - } - }, - "@redux-saga/deferred": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz", - "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==" - }, - "@redux-saga/delay-p": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz", - "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==", - "requires": { - "@redux-saga/symbols": "^1.1.3" - } - }, - "@redux-saga/is": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz", - "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==", - "requires": { - "@redux-saga/symbols": "^1.1.3", - "@redux-saga/types": "^1.2.1" - } - }, - "@redux-saga/symbols": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz", - "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==" - }, - "@redux-saga/types": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz", - "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==" - }, - "@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" - }, - "@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "requires": { - "tslib": "^2.4.0" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "@t3-oss/env-core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@t3-oss/env-core/-/env-core-0.2.2.tgz", - "integrity": "sha512-Jiuph14/L3L9EDaU0O0YiLeaKUcWA9c3mWYuKem8+L64i3Iwz+IbKdl5Jp4cx+JbOsS/aptwGZplnxSHhm2gMQ==" - }, - "@t3-oss/env-nextjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@t3-oss/env-nextjs/-/env-nextjs-0.2.2.tgz", - "integrity": "sha512-9LnVpTkf/8WkggyVN6Liz9Ma9a7fLzV00b5BngWj3HI3iWDfddsWaqCf/H0f46Bgu29NubP3Bwajf1JieVrxFA==", - "requires": { - "@t3-oss/env-core": "0.2.2" - } - }, - "@tanstack/query-core": { - "version": "4.29.7", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.7.tgz", - "integrity": "sha512-GXG4b5hV2Loir+h2G+RXhJdoZhJLnrBWsuLB2r0qBRyhWuXq9w/dWxzvpP89H0UARlH6Mr9DiVj4SMtpkF/aUA==" - }, - "@tanstack/react-query": { - "version": "4.29.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.7.tgz", - "integrity": "sha512-ijBWEzAIo09fB1yd22slRZzprrZ5zMdWYzBnCg5qiXuFbH78uGN1qtGz8+Ed4MuhaPaYSD+hykn+QEKtQviEtg==", - "requires": { - "@tanstack/query-core": "4.29.7", - "use-sync-external-store": "^1.2.0" - } - }, - "@trpc/client": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.26.0.tgz", - "integrity": "sha512-ojHxQFIE97rBEGPK8p1ijbzo0T1IdEBoJ9fFSgWWL9FMuEEA/DNQ9s0uuiOrDKhCCdTFT1unfRharoJhB2/O2w==" - }, - "@trpc/next": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/next/-/next-10.26.0.tgz", - "integrity": "sha512-p328crXBH6C228LKxjqbpDEXdLmy4+LdgsZuYK3oFMqaJEmCT22b+zcQ9IvQrcPfDxhKOpJym0QpuDNaWpG2qg==", - "requires": { - "react-ssr-prepass": "^1.5.0" - } - }, - "@trpc/react-query": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.26.0.tgz", - "integrity": "sha512-n+enpalaCZhd3A/mbZmXeydRZHsAJo7mzc2ncgHn5S+C3SrfOM897uQdbHdj02Li25ULxzP1O92w+vZzmFbgkA==" - }, - "@trpc/server": { - "version": "10.26.0", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.26.0.tgz", - "integrity": "sha512-+Wt0NFAeflVSNiUnHIDNN3C8jP7XIRmYrcgJ6IsAnm0lK4p/FkpCpeu1aig5qxrgZx30PHNDLZ/3FttVSEW2aQ==" - }, - "@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" - }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "@types/json-schema": { - "version": "7.0.11" - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, - "@types/node": { - "version": "20.1.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.4.tgz", - "integrity": "sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q==", - "dev": true - }, - "@types/pdfjs-dist": { - "version": "2.10.378", - "resolved": "https://registry.npmjs.org/@types/pdfjs-dist/-/pdfjs-dist-2.10.378.tgz", - "integrity": "sha512-TRdIPqdsvKmPla44kVy4jv5Nt5vjMfVjbIEke1CRULIrwKNRC4lIiZvNYDJvbUMNCFPNIUcOKhXTyMJrX18IMA==", - "requires": { - "pdfjs-dist": "*" - } - }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" - }, - "@types/react": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.7.tgz", - "integrity": "sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - }, - "dependencies": { - "csstype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", - "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==" - } - } - }, - "@types/react-beautiful-dnd": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.4.tgz", - "integrity": "sha512-4bIBdzOr0aavN+88q3C7Pgz+xkb7tz3whORYrmSj77wfVEMfiWiooIwVWFR7KM2e+uGTe5BVrXqSfb0aHeflJA==", - "requires": { - "@types/react": "*" - } - }, - "@types/react-redux": { - "version": "7.1.25", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz", - "integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==", - "requires": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "@types/react-transition-group": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", - "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, - "@types/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz", - "integrity": "sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/type-utils": "5.59.6", - "@typescript-eslint/utils": "5.59.6", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", - "integrity": "sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==", - "requires": { - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz", - "integrity": "sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==", - "requires": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz", - "integrity": "sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.59.6", - "@typescript-eslint/utils": "5.59.6", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.6.tgz", - "integrity": "sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==" - }, - "@typescript-eslint/typescript-estree": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz", - "integrity": "sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==", - "requires": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.6.tgz", - "integrity": "sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz", - "integrity": "sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==", - "requires": { - "@typescript-eslint/types": "5.59.6", - "eslint-visitor-keys": "^3.3.0" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "devOptional": true - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true - }, - "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "requires": { - "deep-equal": "^2.0.5" - } - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "axe-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.1.tgz", - "integrity": "sha512-sCXXUhA+cljomZ3ZAwb8i1p3oOlkABzPy08ZDAoGcYuvtBPlQ1Ytde129ArXyHWDhfeewq7rlx9F+cUx2SSlkg==" - }, - "axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "requires": { - "deep-equal": "^2.0.5" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c= sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==" - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "requires": { - "big-integer": "^1.6.44" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "requires": { - "run-applescript": "^5.0.0" - } - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001482", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz", - "integrity": "sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ==" - }, - "canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", - "optional": true, - "requires": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" - } - }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "optional": true - }, - "client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true - }, - "copy-anything": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.4.tgz", - "integrity": "sha512-MaQ9FwzlZ/KLeVCLhzI3rZw0EhrIryfZa3AyT4agVybR0DjlkDHA8898lamLD6kfkf9MMn8D+zDAUR4+GxaymQ==", - "requires": { - "is-what": "^4.1.8" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-box-model": { - "version": "1.2.1", - "requires": { - "tiny-invariant": "^1.0.6" - } - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-vendor": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", - "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", - "requires": { - "@babel/runtime": "^7.8.3", - "is-in-browser": "^1.0.2" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" - }, - "csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "optional": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "requires": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - } - }, - "default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "requires": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - } - }, - "define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==" - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "optional": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-helpers": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", - "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - }, - "dependencies": { - "csstype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", - "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==" - } - } - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "enhanced-resolve": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", - "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - } - }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "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==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "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==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "eslint-config-next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.3.tgz", - "integrity": "sha512-1lXwdFi29fKxzeugof/TUE7lpHyJQt5+U4LaUHyvQfHjvsWO77vFNicJv5sX6k0VDVSbnfz0lw+avxI+CinbMg==", - "requires": { - "@next/eslint-plugin-next": "13.4.3", - "@rushstack/eslint-patch": "^1.1.3", - "@typescript-eslint/parser": "^5.42.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.31.7", - "eslint-plugin-react-hooks": "^4.5.0" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-import-resolver-typescript": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", - "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", - "requires": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "get-tsconfig": "^4.5.0", - "globby": "^13.1.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.5" - }, - "dependencies": { - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" - } - } - }, - "eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "requires": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==" - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "dependencies": { - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - } - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "optional": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - } - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-tsconfig": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz", - "integrity": "sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==" - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "requires": { - "react-is": "^16.7.0" - } - }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==" - }, - "hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "optional": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-in-browser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" - }, - "is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "requires": { - "is-docker": "^3.0.0" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "is-what": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.9.tgz", - "integrity": "sha512-I3FU0rkVvwhgLLEs6iITwZ/JaLXe7tQcHyzupXky8jigt1vu4KM0UOqDr963j36JRvJ835EATVIm6MnGz/i1/g==" - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - }, - "dependencies": { - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - } - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "jss": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", - "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", - "requires": { - "@babel/runtime": "^7.3.1", - "csstype": "^3.0.2", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" - }, - "dependencies": { - "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - } - } - }, - "jss-plugin-camel-case": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", - "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", - "requires": { - "@babel/runtime": "^7.3.1", - "hyphenate-style-name": "^1.0.3", - "jss": "10.10.0" - } - }, - "jss-plugin-default-unit": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", - "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-global": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", - "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-nested": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", - "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "jss-plugin-props-sort": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", - "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" - } - }, - "jss-plugin-rule-value-function": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", - "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", - "requires": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" - } - }, - "jss-plugin-vendor-prefixer": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", - "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", - "requires": { - "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.8", - "jss": "10.10.0" - } - }, - "jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "optional": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "optional": true - } - } - }, - "memoize-one": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", - "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==" - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "optional": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "optional": true - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "optional": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "optional": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true - }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "optional": true - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", - "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", - "requires": { - "@next/env": "13.4.3", - "@next/swc-darwin-arm64": "13.4.3", - "@next/swc-darwin-x64": "13.4.3", - "@next/swc-linux-arm64-gnu": "13.4.3", - "@next/swc-linux-arm64-musl": "13.4.3", - "@next/swc-linux-x64-gnu": "13.4.3", - "@next/swc-linux-x64-musl": "13.4.3", - "@next/swc-win32-arm64-msvc": "13.4.3", - "@next/swc-win32-ia32-msvc": "13.4.3", - "@next/swc-win32-x64-msvc": "13.4.3", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "zod": "3.21.4" - } - }, - "node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "optional": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, - "requires": { - "abbrev": "1" - } - }, - "normalized-reducer": { - "version": "0.5.1" - }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "requires": { - "path-key": "^4.0.0" - }, - "dependencies": { - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==" - } - } - }, - "npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "requires": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "requires": { - "mimic-fn": "^4.0.0" - } - }, - "open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "requires": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "requires": { - "entities": "^4.4.0" - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "path2d-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==" - }, - "pdfjs-dist": { - "version": "3.6.172", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.6.172.tgz", - "integrity": "sha512-bfOhCg+S9DXh/ImWhWYTOiq3aVMFSCvzGiBzsIJtdMC71kVWDBw7UXr32xh0y56qc5wMVylIeqV3hBaRsu+e+w==", - "requires": { - "canvas": "^2.11.2", - "path2d-polyfill": "^2.0.1", - "web-streams-polyfill": "^3.2.1" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "popper.js": { - "version": "1.16.1-lts" - }, - "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "prisma": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.14.1.tgz", - "integrity": "sha512-z6hxzTMYqT9SIKlzD08dhzsLUpxjFKKsLpp5/kBDnSqiOjtUyyl/dC5tzxLcOa3jkEHQ8+RpB/fE3w8bgNP51g==", - "requires": { - "@prisma/engines": "4.14.1" - } - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "raf-schd": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz", - "integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==" - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-beautiful-dnd": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", - "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", - "requires": { - "@babel/runtime": "^7.9.2", - "css-box-model": "^1.2.0", - "memoize-one": "^5.1.1", - "raf-schd": "^4.0.2", - "react-redux": "^7.2.0", - "redux": "^4.0.4", - "use-memo-one": "^1.1.1" - }, - "dependencies": { - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "react-redux": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", - "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", - "requires": { - "@babel/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - } - } - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-is": { - "version": "16.13.1" - }, - "react-redux": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", - "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", - "requires": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "dependencies": { - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "react-ssr-prepass": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz", - "integrity": "sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==" - }, - "react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "optional": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, - "redux-devtools-extension": { - "version": "2.13.9", - "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz", - "integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A==" - }, - "redux-saga": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.2.3.tgz", - "integrity": "sha512-HDe0wTR5nhd8Xr5xjGzoyTbdAw6rjy1GDplFt3JKtKN8/MnkQSRqK/n6aQQhpw5NI4ekDVOaW+w4sdxPBaCoTQ==", - "requires": { - "@redux-saga/core": "^1.2.3" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "requires": { - "execa": "^5.0.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - } - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "optional": true - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "optional": true - }, - "simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "optional": true, - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "requires": { - "internal-slot": "^1.0.4" - } - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "optional": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "optional": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "optional": true - } - } - }, - "string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "devOptional": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "requires": { - "client-only": "0.0.1" - } - }, - "superjson": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.12.2.tgz", - "integrity": "sha512-ugvUo9/WmvWOjstornQhsN/sR9mnGtWGYeTxFuqLb4AiT4QdUavjGFRALCPKWWnAiUJ4HTpytj5e0t5HoMRkXg==", - "requires": { - "copy-anything": "^3.0.2" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, - "synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "requires": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" - }, - "tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "optional": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "optional": true - }, - "tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true - }, - "typescript-compare": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", - "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", - "requires": { - "typescript-logic": "^0.0.0" - } - }, - "typescript-logic": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", - "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" - }, - "typescript-tuple": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", - "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", - "requires": { - "typescript-compare": "^0.0.2" - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "use-memo-one": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", - "integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ==" - }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "optional": true - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "optional": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "optional": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - }, - "zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" - } - } -} From 8c0d67b47cbcf85d15e37178fa0e422d72385eae Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 29 May 2023 14:13:57 -0700 Subject: [PATCH 17/62] run prettier --- kanban-dashboard/src/dashboard/Flowchart.tsx | 5 +---- kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx | 4 +--- kanban-dashboard/src/dashboard/Quarter.tsx | 8 ++++++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Flowchart.tsx b/kanban-dashboard/src/dashboard/Flowchart.tsx index 0fb0b71..72c2386 100644 --- a/kanban-dashboard/src/dashboard/Flowchart.tsx +++ b/kanban-dashboard/src/dashboard/Flowchart.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - DragDropContext, - type DropResult, -} from "react-beautiful-dnd"; +import { DragDropContext, type DropResult } from "react-beautiful-dnd"; import { useBoardStyles } from "./styles"; import Quarter from "./Quarter"; import { FlowchartState, useMoveRequirement } from "~/dashboard/state"; diff --git a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx index a09069a..9caba8b 100644 --- a/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx +++ b/kanban-dashboard/src/dashboard/FlowchartSelectingMenu.tsx @@ -229,9 +229,7 @@ export default function FlowchartSelectingMenu() { fullWidth select value={newFlowchartConcentration} - onChange={(e) => - setNewFlowchartConcentration(e.target.value ) - } + onChange={(e) => setNewFlowchartConcentration(e.target.value)} > {/* Add your concentration options here */} Concentration 1 diff --git a/kanban-dashboard/src/dashboard/Quarter.tsx b/kanban-dashboard/src/dashboard/Quarter.tsx index d0901d0..67ce37d 100644 --- a/kanban-dashboard/src/dashboard/Quarter.tsx +++ b/kanban-dashboard/src/dashboard/Quarter.tsx @@ -39,9 +39,13 @@ export default function Quarter({ quarter }: Props) { className={classNames.tasks} > {quarterRequirements.map((requirement, index) => ( - + ))} - {provided.placeholder} + {provided.placeholder} ); }} From e3aa2cf8c5ce58b57f9189cf51c600f79a698ce8 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 10:35:11 -0700 Subject: [PATCH 18/62] create prisma connection --- kanban-dashboard/package.json | 2 +- kanban-dashboard/prisma/schema.prisma | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kanban-dashboard/package.json b/kanban-dashboard/package.json index 9e954a1..f921f6d 100644 --- a/kanban-dashboard/package.json +++ b/kanban-dashboard/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "build": "next build", - "dev": "next dev", + "dev": "npx prisma db push && next dev", "postinstall": "prisma generate", "lint": "next lint", "start": "next start", diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index d73d42a..02b5814 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -6,8 +6,9 @@ generator client { } datasource db { - provider = "sqlite" + provider = "mysql" url = env("DATABASE_URL") + relationMode = "prisma" } model Department { From 4a6fe46f77166a69a784ba5f9e97538321790916 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 11:08:08 -0700 Subject: [PATCH 19/62] update prisma db to align with scraped types --- kanban-dashboard/prisma/schema.prisma | 69 +++++++++++++-------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index 02b5814..f46c179 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -6,8 +6,8 @@ generator client { } datasource db { - provider = "mysql" - url = env("DATABASE_URL") + provider = "mysql" + url = env("DATABASE_URL") relationMode = "prisma" } @@ -15,72 +15,68 @@ model Department { id Int @id @default(autoincrement()) long_name String short_name String @unique - Program Program[] + Degree Degree[] Instructor Instructor[] } model Course { - id Int @id @default(autoincrement()) + code String @id // TODO: make department table and convert this to a foreign key - department String - number Int + subject String + number Int // string because it can be range or single number and we only need // to display it either way - units String + units String // string of comma separated terms - terms String + termsTypicallyOffered String fulfillsRequirements Requirement[] prerequisites Prerequisite[] @relation("Prereq") prerequisiteFor Prerequisite[] @relation("PrereqFor") sections Section[] - - @@unique([department, number]) } model Prerequisite { - id Int @id @default(autoincrement()) - requiredCourse Course @relation(name: "Prereq", fields: [requiredCourseId], references: [id]) - forCourse Course @relation(name: "PrereqFor", fields: [forCourseId], references: [id]) - forCourseId Int - requiredCourseId Int + id Int @id @default(autoincrement()) + requiredCourse Course @relation(name: "Prereq", fields: [requiredCourseCode], references: [code]) + forCourse Course @relation(name: "PrereqFor", fields: [forCourseCode], references: [code]) + forCourseCode String + requiredCourseCode String - @@unique([requiredCourseId, forCourseId]) + @@unique([requiredCourseCode, forCourseCode]) } model Requirement { // TODO: figure out how to make unique ids based on the requirement - id Int @id @default(autoincrement()) - course Course @relation(fields: [courseId], references: [id]) - program Program @relation(fields: [programId], references: [id]) + id Int @id @default(autoincrement()) + course Course @relation(fields: [courseCode], references: [code]) + degree Degree @relation(fields: [degreeId], references: [id]) // Ge, major, tech elective, etc. // TODO: make this an enum - kind String + kind String - courseId Int - programId Int + courseCode String + degreeId Int } -model Program { +model Degree { id Int @id @default(autoincrement()) - department Department @relation(fields: [departmentId], references: [id]) + name String + link String // BS, BA, etc. - type String + kind String requirements Requirement[] - departmentId Int - catolog Catolog @relation(fields: [catologId], references: [id]) - catologId Int - User User[] + Department Department? @relation(fields: [departmentId], references: [id]) + departmentId Int? - @@unique([departmentId, type]) + @@unique([name, kind]) } model Catolog { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) startYear Int endYear Int - programs Program[] } model Instructor { @@ -115,8 +111,8 @@ model Availability { model Section { classNumber Int @id - course Course @relation(fields: [courseId], references: [id]) - courseId Int + course Course @relation(fields: [courseCode], references: [code]) + courseCode String quarter Quarter @relation(fields: [quarterId], references: [id]) quarterId Int status String @@ -150,16 +146,15 @@ model Quarter { model User { calPolyUsername String @id - program Program @relation(fields: [programId], references: [id]) year Int - quarters Quarter[] - programId Int flowcharts UserFlowchart[] + Quarter Quarter[] } model UserFlowchart { id Int @id @default(autoincrement()) user User @relation(fields: [userCalPolyUsername], references: [calPolyUsername]) quarters Quarter[] + startYear Int userCalPolyUsername String } From 19654fc4b06e5f8aa77dd8ca929488e2ffc90ec8 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 11:28:22 -0700 Subject: [PATCH 20/62] use db for degrees --- kanban-dashboard/src/server/api/root.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 2f7cabd..44f92da 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -18,6 +18,7 @@ import { scrapeCurrentQuarter, termCode, } from "~/scraping/registrar"; +import { prisma } from "~/server/db"; const courseType_arr = RequirementTypeSchema.options; @@ -113,7 +114,13 @@ export const appRouter = createTRPCRouter({ ); }), degrees: publicProcedure.query(async () => { - return scrapeDegrees(); + let degrees = await prisma.degree.findMany(); + if (degrees.length === 0) { + // TODO: invalidation of db data + degrees = await scrapeDegrees(); + await prisma.degree.createMany({ data: degrees }); + } + return degrees; }), }); From 5be368b409e9e9a2ec5b31834e1fe1560e9c36a6 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 11:33:04 -0700 Subject: [PATCH 21/62] use url segement as degree id --- kanban-dashboard/prisma/schema.prisma | 4 ++-- kanban-dashboard/src/scraping/catalog.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index f46c179..d533212 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -57,11 +57,11 @@ model Requirement { kind String courseCode String - degreeId Int + degreeId String } model Degree { - id Int @id @default(autoincrement()) + id String @id name String link String // BS, BA, etc. diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 7ac4cdf..bc84954 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -130,7 +130,7 @@ export const DegreeSchema = z.object({ name: z.string(), kind: z.enum(BACHELOR_DEGREE_KINDS), link: z.string().url(), - id: z.number().nonnegative(), + id: z.string(), }); export type Degree = z.infer; @@ -379,7 +379,8 @@ export const scrapeDegrees = async () => { .each((i, elem) => { const [_matched, name, kind] = $(elem).text().match(majorRE) ?? []; const link = DOMAIN + $(elem).find("a").attr("href"); - degrees.push(DegreeSchema.parse({ name, kind, link, id: i })); + const id = link.split("/").findLast((s) => s.length > 0 && !s.startsWith('#')) ?? ""; + degrees.push(DegreeSchema.parse({ name, kind, link, id })); }); return degrees; }; From 8271ea3c1514389e2542f052fdad949947b8d4b0 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 12:37:10 -0700 Subject: [PATCH 22/62] remove unnecessary aliases to t.procedure and t.router --- kanban-dashboard/src/server/api/root.ts | 19 ++++++++----------- kanban-dashboard/src/server/api/trpc.ts | 25 +------------------------ 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 44f92da..8f6ed2d 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -1,4 +1,4 @@ -import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; +import { t } from "~/server/api/trpc"; import { scrapeDegrees, scrapeDegreeRequirements, @@ -53,15 +53,12 @@ export type Quarter = z.infer; * * All routers added in /api/routers should be manually added here. */ -export const appRouter = createTRPCRouter({ - currentQuarterId: publicProcedure - .output(z.number().gt(2000)) - .query(async () => { - return await scrapeCurrentQuarter(); - }), - quarters: publicProcedure +export const appRouter = t.router({ + currentQuarterId: t.procedure.output(z.number().gt(2000)).query(async () => { + return await scrapeCurrentQuarter(); + }), + quarters: t.procedure .input(z.object({ startYear: z.number().gte(2000) })) - .output(z.array(QuarterSchema)) .query(({ input: { startYear } }) => { const quarters = []; @@ -86,7 +83,7 @@ export const appRouter = createTRPCRouter({ } return quarters; }), - degreeRequirements: publicProcedure + degreeRequirements: t.procedure .input( z.object({ degree: DegreeSchema.nullable(), @@ -113,7 +110,7 @@ export const appRouter = createTRPCRouter({ }) ); }), - degrees: publicProcedure.query(async () => { + degrees: t.procedure.query(async () => { let degrees = await prisma.degree.findMany(); if (degrees.length === 0) { // TODO: invalidation of db data diff --git a/kanban-dashboard/src/server/api/trpc.ts b/kanban-dashboard/src/server/api/trpc.ts index 08305da..1a358f8 100644 --- a/kanban-dashboard/src/server/api/trpc.ts +++ b/kanban-dashboard/src/server/api/trpc.ts @@ -57,7 +57,7 @@ import { initTRPC } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; -const t = initTRPC.context().create({ +export const t = initTRPC.context().create({ transformer: superjson, errorFormatter({ shape, error }) { return { @@ -70,26 +70,3 @@ const t = initTRPC.context().create({ }; }, }); - -/** - * 3. ROUTER & PROCEDURE (THE IMPORTANT BIT) - * - * These are the pieces you use to build your tRPC API. You should import these a lot in the - * "/src/server/api/routers" directory. - */ - -/** - * This is how you create new routers and sub-routers in your tRPC API. - * - * @see https://trpc.io/docs/router - */ -export const createTRPCRouter = t.router; - -/** - * Public (unauthenticated) procedure - * - * This is the base piece you use to build new queries and mutations on your tRPC API. It does not - * guarantee that a user querying is authorized, but you can still access user session data if they - * are logged in. - */ -export const publicProcedure = t.procedure; From 7a6c5ca653c3aeab9e675c9b4bc4c40bba44fe6e Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 12:42:31 -0700 Subject: [PATCH 23/62] make quarters subrouter --- kanban-dashboard/src/dashboard/CourseCard.tsx | 2 +- kanban-dashboard/src/dashboard/Flowchart.tsx | 2 +- kanban-dashboard/src/server/api/root.ts | 54 ++++++++++--------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/kanban-dashboard/src/dashboard/CourseCard.tsx b/kanban-dashboard/src/dashboard/CourseCard.tsx index f259d7f..148f133 100644 --- a/kanban-dashboard/src/dashboard/CourseCard.tsx +++ b/kanban-dashboard/src/dashboard/CourseCard.tsx @@ -40,7 +40,7 @@ export default function CourseCard({ requirement, index }: Props) { }; const [completeStatus, setCompleteStatus] = useState("incomplete"); - const { data: currentQuarter } = api.currentQuarterId.useQuery(undefined, { + const { data: currentQuarter } = api.quarters.current.useQuery(undefined, { staleTime: Infinity, // don't refresh until the user refreshes }); diff --git a/kanban-dashboard/src/dashboard/Flowchart.tsx b/kanban-dashboard/src/dashboard/Flowchart.tsx index 72c2386..c0d359e 100644 --- a/kanban-dashboard/src/dashboard/Flowchart.tsx +++ b/kanban-dashboard/src/dashboard/Flowchart.tsx @@ -8,7 +8,7 @@ import { api } from "~/utils/api"; export default function Flowchart() { const { startYear } = React.useContext(FlowchartState); const moveRequirement = useMoveRequirement(); - const quartersQuery = api.quarters.useQuery({ startYear }); + const quartersQuery = api.quarters.all.useQuery({ startYear }); const classNames = useBoardStyles(); diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 8f6ed2d..ae2fa9a 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -54,35 +54,37 @@ export type Quarter = z.infer; * All routers added in /api/routers should be manually added here. */ export const appRouter = t.router({ - currentQuarterId: t.procedure.output(z.number().gt(2000)).query(async () => { - return await scrapeCurrentQuarter(); - }), - quarters: t.procedure - .input(z.object({ startYear: z.number().gte(2000) })) - .query(({ input: { startYear } }) => { - const quarters = []; + quarters: t.router({ + current: t.procedure.output(z.number().gt(2000)).query(async () => { + return await scrapeCurrentQuarter(); + }), + all: t.procedure + .input(z.object({ startYear: z.number().gte(2000) })) + .query(({ input: { startYear } }) => { + const quarters = []; - let calYear = startYear; - let schoolYear = 0; + let calYear = startYear; + let schoolYear = 0; - const q = (termSeason: Term) => ({ - id: termCode(calYear, termSeason), - termNum: TERM_NUMBER[termSeason] as z.infer< - typeof SchoolYearTermSchema - >, - year: schoolYear, - }); - while (schoolYear < 4) { - // winter/spring quarter will be in yeear 5 senior year but this is still 4th year + const q = (termSeason: Term) => ({ + id: termCode(calYear, termSeason), + termNum: TERM_NUMBER[termSeason] as z.infer< + typeof SchoolYearTermSchema + >, + year: schoolYear, + }); + while (schoolYear < 4) { + // winter/spring quarter will be in yeear 5 senior year but this is still 4th year - quarters.push(q("fall")); - calYear++; - quarters.push(q("winter")); - quarters.push(q("spring")); - schoolYear++; - } - return quarters; - }), + quarters.push(q("fall")); + calYear++; + quarters.push(q("winter")); + quarters.push(q("spring")); + schoolYear++; + } + return quarters; + }), + }), degreeRequirements: t.procedure .input( z.object({ From dd893dcd8c9e879f9e2c0d405a356320c3114b52 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 12:48:15 -0700 Subject: [PATCH 24/62] create degrees subrouter --- kanban-dashboard/src/dashboard/Menubar.tsx | 4 +- kanban-dashboard/src/dashboard/state.tsx | 4 +- kanban-dashboard/src/server/api/root.ts | 70 ++++++++++++---------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index 48a9f1e..0d40b20 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -32,7 +32,7 @@ export default function Menubar({}: MenubarProps) { const handleClose = () => { setAnchorEl(null); }; - const degreesQuery = api.degrees.useQuery(undefined, { + const degreesQuery = api.degrees.all.useQuery(undefined, { staleTime: Infinity, // don't refresh until the user refreshes }); @@ -48,7 +48,7 @@ export default function Menubar({}: MenubarProps) { // TODO: create record of string id: Degree for faster lookup if (degree.name === name) { console.log("fetching degree requirements for:", degree); - trpcClient.degreeRequirements.prefetch({ degree, startYear }); + trpcClient.degrees.requirements.prefetch({ degree, startYear }); setDegree(degree); setSelectedDegreeDisplayName(degree.name); break; diff --git a/kanban-dashboard/src/dashboard/state.tsx b/kanban-dashboard/src/dashboard/state.tsx index f05bbb0..988dd1a 100644 --- a/kanban-dashboard/src/dashboard/state.tsx +++ b/kanban-dashboard/src/dashboard/state.tsx @@ -39,7 +39,7 @@ export const FlowchartStateProvider: FC<{ children: React.ReactNode }> = ({ useEffect(() => { console.log("updating requirements!"); }, [requirements]); - const _requirementsQuery = api.degreeRequirements.useQuery( + const _requirementsQuery = api.degrees.requirements.useQuery( { degree, startYear }, { enabled: false, onSuccess: (data) => setRequirements(data) } ); @@ -65,7 +65,7 @@ export const useMoveRequirement = () => { const { degree, startYear } = useContext(FlowchartState); const trpcClient = api.useContext(); const moveRequirement = (requirementId: number, quarterId: number) => { - trpcClient.degreeRequirements.setData( + trpcClient.degrees.requirements.setData( { degree, startYear }, (requirements) => { if (!requirements) { diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index ae2fa9a..9ecae3a 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -85,41 +85,45 @@ export const appRouter = t.router({ return quarters; }), }), - degreeRequirements: t.procedure - .input( - z.object({ - degree: DegreeSchema.nullable(), - startYear: z.number().gte(2000), - }) - ) - .output(z.array(RequirementSchema)) - .query(async ({ input }) => { - if (input.degree === null) { - return []; - } - const courses = await scrapeDegreeRequirements(input.degree); - // generate random info for the data that isn't being scraped yet - return Array.from(courses.courses.values()).map( - (course: RequirementCourse, i) => ({ - ...course, - courseType: - courseType_arr[Math.floor(Math.random() * courseType_arr.length)], // TODO: figure out course type from group - quarterId: termCode( - Math.floor(Math.random() * 4) + input.startYear, - SchoolYearTermSchema.parse([2, 4, 8][Math.floor(Math.random() * 3)]) - ), - id: i, + degrees: t.router({ + requirements: t.procedure + .input( + z.object({ + degree: DegreeSchema.nullable(), + startYear: z.number().gte(2000), }) - ); + ) + .output(z.array(RequirementSchema)) + .query(async ({ input }) => { + if (input.degree === null) { + return []; + } + const courses = await scrapeDegreeRequirements(input.degree); + // generate random info for the data that isn't being scraped yet + return Array.from(courses.courses.values()).map( + (course: RequirementCourse, i) => ({ + ...course, + courseType: + courseType_arr[Math.floor(Math.random() * courseType_arr.length)], // TODO: figure out course type from group + quarterId: termCode( + Math.floor(Math.random() * 4) + input.startYear, + SchoolYearTermSchema.parse( + [2, 4, 8][Math.floor(Math.random() * 3)] + ) + ), + id: i, + }) + ); + }), + all: t.procedure.query(async () => { + let degrees = await prisma.degree.findMany(); + if (degrees.length === 0) { + // TODO: invalidation of db data + degrees = await scrapeDegrees(); + await prisma.degree.createMany({ data: degrees }); + } + return degrees; }), - degrees: t.procedure.query(async () => { - let degrees = await prisma.degree.findMany(); - if (degrees.length === 0) { - // TODO: invalidation of db data - degrees = await scrapeDegrees(); - await prisma.degree.createMany({ data: degrees }); - } - return degrees; }), }); From e27944e19b8aa38db168e5760355e859b2e5a200 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 30 May 2023 22:04:03 -0700 Subject: [PATCH 25/62] move scraping of department courses into catalog --- kanban-dashboard/prisma/schema.prisma | 3 +- kanban-dashboard/src/scraping/catalog.ts | 80 ++++++++++++++++++- .../src/scraping/department_courses.ts | 52 ------------ kanban-dashboard/src/server/api/root.ts | 16 +++- 4 files changed, 93 insertions(+), 58 deletions(-) delete mode 100644 kanban-dashboard/src/scraping/department_courses.ts diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index d533212..aaf96fa 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -21,9 +21,8 @@ model Department { model Course { code String @id - // TODO: make department table and convert this to a foreign key subject String - number Int + description String @db.MediumText // string because it can be range or single number and we only need // to display it either way units String diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index bc84954..2a682ce 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -379,8 +379,86 @@ export const scrapeDegrees = async () => { .each((i, elem) => { const [_matched, name, kind] = $(elem).text().match(majorRE) ?? []; const link = DOMAIN + $(elem).find("a").attr("href"); - const id = link.split("/").findLast((s) => s.length > 0 && !s.startsWith('#')) ?? ""; + const id = + link.split("/").findLast((s) => s.length > 0 && !s.startsWith("#")) ?? + ""; degrees.push(DegreeSchema.parse({ name, kind, link, id })); }); return degrees; }; + +const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); + +const CourseSchema = z.object({ + code: z.string(), + title: z.string(), + subject: z.string(), + num: z.number(), + description: z.string(), + termsTypicallyOffered: z.array(TermSchema), + // if not range minUnits is maxUnits + minUnits: z.number(), + maxUnits: z.number(), +}); + +type Course = z.infer; + +export const scrapeSubjectCourses = async (subjectCode: string) => { + const COURSE_INFO_RE = /(([A-Z]+)\s+(\d+))\. (.*?)\.?$/; + const URL = `https://catalog.calpoly.edu/coursesaz/${subjectCode.toLowerCase()}/`; + const $ = cheerio.load(await fetch(URL).then((res) => res.text())); + + const courses = $(".courseblock"); + const scrapedCourses: Course[] = []; + courses.each((i, course) => { + const title_block = $(course).find(".courseblocktitle"); + const units_str = $(title_block).find("strong span").text().trim(); + let minUnits = 0, + maxUnits = 0; + const units_num = units_str.replace(" units", ""); + if (units_num.includes("-")) { + const [minUnits, maxUnits] = units_num.split("-").map(Number); + } else { + let units = parseInt(units_num); + minUnits = units; + maxUnits = units; + } + const [_, code, subject, numStr, title] = + $(title_block) + .find("strong") + .text() + .replace(units_str, "") + .trim() + .match(COURSE_INFO_RE) ?? []; + const num = parseInt(numStr); + const info_block = $(course).find(".courseextendedwrap"); + let termsTypicallyOffered = null; + $(info_block) + .find("p") + .each((i, info_field) => { + const field_text = $(info_field).text().trim(); + if (field_text.startsWith("Term Typically Offered:")) { + const terms_offered = field_text + .replace("Term Typically Offered: ", "") + .split(/, ?/); + termsTypicallyOffered = terms_offered; + } + // TODO: "catolog:" field specifying the requirements it fulfills + // TODO: "CR/NC" field + }); + const description = $(course).find(".courseblockdesc").text().trim() + scrapedCourses.push( + CourseSchema.parse({ + subject, + num, + code, + title, + termsTypicallyOffered, + minUnits, + maxUnits, + description, + }) + ); + }); + return scrapedCourses; +}; diff --git a/kanban-dashboard/src/scraping/department_courses.ts b/kanban-dashboard/src/scraping/department_courses.ts deleted file mode 100644 index cc1ec54..0000000 --- a/kanban-dashboard/src/scraping/department_courses.ts +++ /dev/null @@ -1,52 +0,0 @@ -import cheerio from "cheerio"; - -const COURSE_INFO_RE = /([A-Z]+)\s+(\d+)\. (.*)$/; - -function scrape_department_courses(page) { - const $ = cheerio.load(page); - - const courses = $(".courseblock"); - courses.each((i, course) => { - const title_block = $(course).find(".courseblocktitle"); - const units_str = $(title_block).find("strong span").text().trim(); - const title_str = $(title_block) - .find("strong") - .text() - .replace(units_str, "") - .trim(); - const [_, major, num, name] = title_str.match(COURSE_INFO_RE); - let units = null; - const units_num = units_str.replace(" units", ""); - if (units_num.includes("-")) { - const [start, end] = units_num.split("-").map(Number); - units = Array.from({ length: end - start + 1 }, (_, i) => i + start); - } else { - units = parseInt(units_num); - } - const info_block = $(course).find(".courseextendedwrap"); - let terms; - $(info_block) - .find("p") - .each((i, info_field) => { - const field_text = $(info_field).text().trim(); - if (field_text.startsWith("Term Typically Offered:")) { - const terms_offered = field_text - .replace("Term Typically Offered: ", "") - .split(", "); - terms = terms_offered; - } - // TODO: "catolog:" field specifying the requirements it fulfills - // TODO: "CR/NC" field - }); - console.log( - `department=${major} num=${num} units=${units} name=${name} terms=${terms}` - ); - }); -} - -// TEST: -const DEPARTMENT = "csc"; -const page = await fetch( - `https://catalog.calpoly.edu/coursesaz/${DEPARTMENT}/` -).then((res) => res.text()); -scrape_department_courses(page); diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 9ecae3a..fedd3ab 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -98,9 +98,17 @@ export const appRouter = t.router({ if (input.degree === null) { return []; } - const courses = await scrapeDegreeRequirements(input.degree); - // generate random info for the data that isn't being scraped yet - return Array.from(courses.courses.values()).map( + let { requirements } = await prisma.degree.findUnique({ + where: { + id: input.degree.id, + }, + select: { + requirements: true, + }, + }) ?? {}; + if (!requirements || requirements.length === 0) { + const { courses } = await scrapeDegreeRequirements(input.degree); + requirements = Array.from(courses.values()).map( (course: RequirementCourse, i) => ({ ...course, courseType: @@ -114,6 +122,8 @@ export const appRouter = t.router({ id: i, }) ); + + } }), all: t.procedure.query(async () => { let degrees = await prisma.degree.findMany(); From 611a373a8f05893cdeae5a707f6594d2a5f21157 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 31 May 2023 11:04:35 -0700 Subject: [PATCH 26/62] clean up prisma schema --- kanban-dashboard/prisma/schema.prisma | 139 ++++++-------------------- 1 file changed, 30 insertions(+), 109 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index aaf96fa..2d8c2cb 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -1,3 +1,4 @@ +// vim: nnoremap = !npx prisma format // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema @@ -12,148 +13,68 @@ datasource db { } model Department { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) long_name String - short_name String @unique + short_name String @unique Degree Degree[] - Instructor Instructor[] } model Course { code String @id - subject String - description String @db.MediumText + subjectCode String + number Int + description String @db.LongText // string because it can be range or single number and we only need // to display it either way - units String + minUnits Int + maxUnits Int // string of comma separated terms + // TODO: make this a bitmask termsTypicallyOffered String - fulfillsRequirements Requirement[] - - prerequisites Prerequisite[] @relation("Prereq") - prerequisiteFor Prerequisite[] @relation("PrereqFor") - sections Section[] + fulfillsRequirements CourseRequirement[] } -model Prerequisite { - id Int @id @default(autoincrement()) - requiredCourse Course @relation(name: "Prereq", fields: [requiredCourseCode], references: [code]) - forCourse Course @relation(name: "PrereqFor", fields: [forCourseCode], references: [code]) - forCourseCode String - requiredCourseCode String - - @@unique([requiredCourseCode, forCourseCode]) -} - -model Requirement { - // TODO: figure out how to make unique ids based on the requirement - id Int @id @default(autoincrement()) - course Course @relation(fields: [courseCode], references: [code]) - degree Degree @relation(fields: [degreeId], references: [id]) +model CourseRequirement { + // TODO: figure out how to make unique ids based on the CourseRequirement + id Int @id @default(autoincrement()) + course Course @relation(fields: [courseCode], references: [code]) + degree Degree @relation(fields: [degreeId], references: [id]) // Ge, major, tech elective, etc. // TODO: make this an enum - kind String + kind String + // 0,1,2,3 + recommendedYear Int + recommendedTermCode Int courseCode String degreeId String + + @@unique([courseCode, degreeId]) } model Degree { - id String @id - name String - link String + id String @id + name String + link String // BS, BA, etc. - kind String - requirements Requirement[] - Department Department? @relation(fields: [departmentId], references: [id]) - departmentId Int? + kind String + courseRequirements CourseRequirement[] + Department Department? @relation(fields: [departmentId], references: [id]) + departmentId Int? @@unique([name, kind]) } -model Catolog { - id Int @id @default(autoincrement()) - startYear Int - endYear Int -} - -model Instructor { - id Int @id @default(autoincrement()) - name String @unique - department Department @relation(fields: [departmentId], references: [id]) - departmentId Int - officeHours String - Section Section[] -} - -// TODO: make sure this is the best way we could store this -model Meeting { - id Int @id @default(autoincrement()) - startTime DateTime - endTime DateTime - section Section? @relation(fields: [sectionClassNumber], references: [classNumber]) - sectionClassNumber Int? - location String -} - -model Availability { - id Int @id @default(autoincrement()) - seats Int - capacity Int - waitlist Int - waitlistCapacity Int - time DateTime @default(now()) - section Section @relation(fields: [sectionClassNumber], references: [classNumber]) - sectionClassNumber Int -} - -model Section { - classNumber Int @id - course Course @relation(fields: [courseCode], references: [code]) - courseCode String - quarter Quarter @relation(fields: [quarterId], references: [id]) - quarterId Int - status String - session String - intstructionMode String - career String - // TODO: make sure this aligns with a quarters start and end - // dates MeetingTime - instructor Instructor @relation(fields: [instructorId], references: [id]) - instructorId Int - meetings Meeting[] - grading String - location String - campus String - classComponents String - availability Availability[] -} - -model Quarter { - id Int @id @default(autoincrement()) - term String - year Int - classes Section[] - user User? @relation(fields: [userCalPolyUsername], references: [calPolyUsername]) - userCalPolyUsername String? - UserFlowchart UserFlowchart? @relation(fields: [userFlowchartId], references: [id]) - userFlowchartId Int? - startDate DateTime - endDate DateTime -} - model User { calPolyUsername String @id year Int flowcharts UserFlowchart[] - Quarter Quarter[] } model UserFlowchart { - id Int @id @default(autoincrement()) - user User @relation(fields: [userCalPolyUsername], references: [calPolyUsername]) - quarters Quarter[] + id Int @id @default(autoincrement()) + user User @relation(fields: [userCalPolyUsername], references: [calPolyUsername]) startYear Int userCalPolyUsername String } From 227f353e19eb26969aec56a762288d605ad75235 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 31 May 2023 11:23:56 -0700 Subject: [PATCH 27/62] department and degree ids from catalog url routes --- kanban-dashboard/src/scraping/catalog.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 2a682ce..a7ef3c6 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -5,6 +5,7 @@ import { z } from "zod"; const DOMAIN = "https://catalog.calpoly.edu"; export const DepartmentSchema = z.object({ + id: z.string(), name: z.string(), link: z.string().url(), }); @@ -34,10 +35,15 @@ export const scrapeCollegesAndDepartments = async () => { .next("ul") .find("li>a") .each((_i, elem) => { + const link = DOMAIN + $(elem).attr("href"); + const id = link + .split("/") + .findLast((s) => s.length > 0 && !s.startsWith("#")); departmentList.push( DepartmentSchema.parse({ name: $(elem).text().trim(), - link: DOMAIN + $(elem).attr("href"), + link, + id, }) ); }); @@ -131,6 +137,7 @@ export const DegreeSchema = z.object({ kind: z.enum(BACHELOR_DEGREE_KINDS), link: z.string().url(), id: z.string(), + departmentId: z.string(), }); export type Degree = z.infer; @@ -383,6 +390,12 @@ export const scrapeDegrees = async () => { link.split("/").findLast((s) => s.length > 0 && !s.startsWith("#")) ?? ""; degrees.push(DegreeSchema.parse({ name, kind, link, id })); + const linkSegments = link + .split("/") + .filter((s) => s.length > 0 && !s.startsWith("#")); + const id = linkSegments.at(-1); + const departmentId = linkSegments.at(-2); + degrees.push(DegreeSchema.parse({ name, kind, link, id, departmentId })); }); return degrees; }; From 39aab629b6f04a34712da3e9282a8dd455989d5a Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 31 May 2023 15:40:47 -0700 Subject: [PATCH 28/62] remove crosslist syntax from parsed degree requirements --- kanban-dashboard/src/scraping/catalog.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index a7ef3c6..6c59c62 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -366,9 +366,22 @@ export const scrapeDegreeRequirements = async ( } } // TODO: Parse GE table - // (returning false prevents it from being parsed by ending the iteration) + // (returning false prevents it from being parsed by ending the iteration after the first table) return false; }); + // NOTE: it is expected that information from crosslistings can be parsed in subject course lists and handled properly when using degree course requirements + // const crossListedCourses = new Map(); + // TODO: use non-crosslisted code when inserting course into courses, requirements instead of having postProcess loop + const crossListedCourses = new Map(); + courses.forEach((req, code) => { + const codeWOCrosslist = code.replace(/\/[A-Z]+/, ""); + req.code = codeWOCrosslist; + crossListedCourses.set(code, req); + }); + crossListedCourses.forEach((req, crossListedCourseCode) => { + courses.delete(crossListedCourseCode); + courses.set(req.code, req); + }); // TODO: check for correctness by counting the units and comparing to the degree's unit count From 33a702cedae34721ae6a1d5991ec49e26d02fb17 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 31 May 2023 21:36:29 -0700 Subject: [PATCH 29/62] function to update all catalog data in db --- kanban-dashboard/prisma/schema.prisma | 42 ++++--- kanban-dashboard/src/scraping/catalog.ts | 151 +++++++++++++++++------ 2 files changed, 141 insertions(+), 52 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index 2d8c2cb..6a9d4c1 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -1,7 +1,11 @@ -// vim: nnoremap = !npx prisma format // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema +// NOTE: models have either id or code fields +// Models whose primary key is not explicitly used by cal poly have an id field although it may be something aquired from cal poly such as +// the degree id which is determined from the degree page url path on the catalog site +// Models (such as subject) whose primary key is used by cal poly have a code field + generator client { provider = "prisma-client-js" } @@ -13,17 +17,18 @@ datasource db { } model Department { - id Int @id @default(autoincrement()) - long_name String - short_name String @unique - Degree Degree[] + id String @id + name String @unique + Degree Degree[] } model Course { - code String @id + code String @id subjectCode String + subject Subject @relation(fields: [subjectCode], references: [code]) + title String number Int - description String @db.LongText + description String @db.LongText // string because it can be range or single number and we only need // to display it either way minUnits Int @@ -35,33 +40,38 @@ model Course { fulfillsRequirements CourseRequirement[] } +model Subject { + code String @id + name String + courses Course[] +} + model CourseRequirement { // TODO: figure out how to make unique ids based on the CourseRequirement - id Int @id @default(autoincrement()) - course Course @relation(fields: [courseCode], references: [code]) - degree Degree @relation(fields: [degreeId], references: [id]) + course Course @relation(fields: [courseCode], references: [code]) + degree Degree @relation(fields: [degreeId], references: [id]) // Ge, major, tech elective, etc. // TODO: make this an enum - kind String + kind String? // 0,1,2,3 - recommendedYear Int - recommendedTermCode Int + recommendedYear Int? + recommendedTermCode Int? courseCode String degreeId String - @@unique([courseCode, degreeId]) + @@id([courseCode, degreeId]) } model Degree { id String @id name String link String - // BS, BA, etc. + // TODO: make this an enum of BS, BA, etc. kind String courseRequirements CourseRequirement[] Department Department? @relation(fields: [departmentId], references: [id]) - departmentId Int? + departmentId String? @@unique([name, kind]) } diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 6c59c62..6de2b83 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -1,3 +1,4 @@ +import { PrismaClient } from "@prisma/client"; import assert from "assert"; import * as cheerio from "cheerio/lib/slim"; import { z } from "zod"; @@ -58,27 +59,6 @@ export const scrapeCollegesAndDepartments = async () => { return colleges; }; -export const SubjectCodeSchema = z.string().regex(/[A-Z]+/); -export const SubjectSchema = z.object({ - subject: z.string(), - code: SubjectCodeSchema, -}); -export type Subject = z.infer; - -export const scrapeSubjects = async () => { - const subjectRE = /(.+)\s+\(([A-Z ]+)\)/; - - const URL = "https://catalog.calpoly.edu/coursesaz/"; - const $ = cheerio.load(await fetch(URL).then((res) => res.text())); - const subjects: Subject[] = []; - $("a.sitemaplink").each((_i, elem) => { - const txt = $(elem).text(); - const [_matched, subject, code] = txt.match(subjectRE) ?? []; - subjects.push(SubjectSchema.parse({ subject, code })); - }); - return subjects; -}; - export const BACHELOR_DEGREE_KINDS = [ "BA", "BFA", @@ -399,10 +379,6 @@ export const scrapeDegrees = async () => { .each((i, elem) => { const [_matched, name, kind] = $(elem).text().match(majorRE) ?? []; const link = DOMAIN + $(elem).find("a").attr("href"); - const id = - link.split("/").findLast((s) => s.length > 0 && !s.startsWith("#")) ?? - ""; - degrees.push(DegreeSchema.parse({ name, kind, link, id })); const linkSegments = link .split("/") .filter((s) => s.length > 0 && !s.startsWith("#")); @@ -418,10 +394,11 @@ const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); const CourseSchema = z.object({ code: z.string(), title: z.string(), - subject: z.string(), - num: z.number(), + // subjectCode: z.string(), + number: z.number(), description: z.string(), - termsTypicallyOffered: z.array(TermSchema), + // TODO: turn termsTypicallyOffered into bitmask based on 2,4,6,8 term codes + termsTypicallyOffered: z.string(), // z.array(TermSchema), // if not range minUnits is maxUnits minUnits: z.number(), maxUnits: z.number(), @@ -449,14 +426,14 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { minUnits = units; maxUnits = units; } - const [_, code, subject, numStr, title] = + let [_, code, subjectCode, numStr, title] = $(title_block) .find("strong") .text() .replace(units_str, "") .trim() .match(COURSE_INFO_RE) ?? []; - const num = parseInt(numStr); + const number = parseInt(numStr); const info_block = $(course).find(".courseextendedwrap"); let termsTypicallyOffered = null; $(info_block) @@ -464,19 +441,21 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { .each((i, info_field) => { const field_text = $(info_field).text().trim(); if (field_text.startsWith("Term Typically Offered:")) { - const terms_offered = field_text + // normalize terms offered list so it is in csv format without extra spaces + termsTypicallyOffered = field_text .replace("Term Typically Offered: ", "") - .split(/, ?/); - termsTypicallyOffered = terms_offered; + .split(/, ?/) + .join(","); } // TODO: "catolog:" field specifying the requirements it fulfills + // TODO: prerequisite field // TODO: "CR/NC" field + // TODO: crosslisted as (+ field in db schema) }); - const description = $(course).find(".courseblockdesc").text().trim() + const description = $(course).find(".courseblockdesc").text().trim(); scrapedCourses.push( CourseSchema.parse({ - subject, - num, + number, code, title, termsTypicallyOffered, @@ -488,3 +467,103 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { }); return scrapedCourses; }; + +export const SubjectSchema = z.object({ + name: z.string(), + code: z.string(), +}); + +export type Subject = z.infer; + +export const scrapeSubjects = async () => { + // TODO: scrape ge areas, gwr, uscp, etc from same page + const subjectRE = /(.+)\s+\(([A-Z ]+)\)/; + + const URL = "https://catalog.calpoly.edu/coursesaz/"; + const $ = cheerio.load(await fetch(URL).then((res) => res.text())); + const subjects: Subject[] = []; + $("a.sitemaplink").each((_i, elem) => { + const txt = $(elem).text(); + const [_matched, name, code] = txt.match(subjectRE) ?? []; + subjects.push(SubjectSchema.parse({ name, code })); + }); + return subjects; +}; + +// TODO: function that takes prisma schema and updates all catalog data in db + +export const updateCatalogDataInDB = async (prisma: PrismaClient) => { + const [departments, subjects, degrees] = await Promise.all([ + scrapeCollegesAndDepartments().then((colleges) => + colleges + .map((col) => col.departments.map(({ name, id }) => ({ name, id }))) + .flat() + ), + scrapeSubjects(), + scrapeDegrees(), + ]); + const skipDuplicates = true; + // TODO: figure out how to join these into a (single?) Promise.all + await prisma.department.createMany({ data: departments, skipDuplicates }); + await prisma.subject.createMany({ data: subjects, skipDuplicates }); + const foundCourses = new Set(); + await Promise.all( + subjects.map(async (subject) => { + const courses = await scrapeSubjectCourses(subject.code); + console.log( + "found", + courses.length, + "courses for subject:", + subject.code + ); + for (const course of courses) { + foundCourses.add(course.code); + } + await prisma.subject.update({ + where: { code: subject.code }, + data: { + courses: { + createMany: { + data: courses, + skipDuplicates, + }, + }, + }, + }); + }) + ); + + await prisma.degree.createMany({ data: degrees, skipDuplicates }); + await prisma.courseRequirement.deleteMany(); + degrees.forEach(async (degree) => { + const courseCodes = await scrapeDegreeRequirements(degree).then((reqs) => + Array.from(reqs.courses.keys()) + ); + courseCodes.forEach(async (courseCode) => { + console.log( + "creating course requirement", + courseCode, + "for degree", + degree.name + ); + await prisma.courseRequirement + .create({ + data: { + course: { connect: { code: courseCode } }, + degree: { connect: { id: degree.id } }, + }, + }) + .catch((_e) => + console.error( + "failed creating course requirement", + courseCode, + "for degree", + degree.name, + _e + ) + ); + }); + }); + // FIXME: create separate script (+bash script to call it) for updating db with above function and creation of prisma client without timeout + // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting +}; From c72bfa30fe4adbb92f7d4aece468c7687806b807 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 1 Jun 2023 17:14:29 -0700 Subject: [PATCH 30/62] create dedicated file for updating db from scraped data and bash script to run it --- kanban-dashboard/src/scraping/catalog.ts | 78 +------------------ kanban-dashboard/src/server/api/db.ts | 98 ++++++++++++++++++++++++ kanban-dashboard/update-db.sh | 3 + 3 files changed, 102 insertions(+), 77 deletions(-) create mode 100644 kanban-dashboard/src/server/api/db.ts create mode 100755 kanban-dashboard/update-db.sh diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 6de2b83..5df60cd 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -490,80 +490,4 @@ export const scrapeSubjects = async () => { return subjects; }; -// TODO: function that takes prisma schema and updates all catalog data in db - -export const updateCatalogDataInDB = async (prisma: PrismaClient) => { - const [departments, subjects, degrees] = await Promise.all([ - scrapeCollegesAndDepartments().then((colleges) => - colleges - .map((col) => col.departments.map(({ name, id }) => ({ name, id }))) - .flat() - ), - scrapeSubjects(), - scrapeDegrees(), - ]); - const skipDuplicates = true; - // TODO: figure out how to join these into a (single?) Promise.all - await prisma.department.createMany({ data: departments, skipDuplicates }); - await prisma.subject.createMany({ data: subjects, skipDuplicates }); - const foundCourses = new Set(); - await Promise.all( - subjects.map(async (subject) => { - const courses = await scrapeSubjectCourses(subject.code); - console.log( - "found", - courses.length, - "courses for subject:", - subject.code - ); - for (const course of courses) { - foundCourses.add(course.code); - } - await prisma.subject.update({ - where: { code: subject.code }, - data: { - courses: { - createMany: { - data: courses, - skipDuplicates, - }, - }, - }, - }); - }) - ); - - await prisma.degree.createMany({ data: degrees, skipDuplicates }); - await prisma.courseRequirement.deleteMany(); - degrees.forEach(async (degree) => { - const courseCodes = await scrapeDegreeRequirements(degree).then((reqs) => - Array.from(reqs.courses.keys()) - ); - courseCodes.forEach(async (courseCode) => { - console.log( - "creating course requirement", - courseCode, - "for degree", - degree.name - ); - await prisma.courseRequirement - .create({ - data: { - course: { connect: { code: courseCode } }, - degree: { connect: { id: degree.id } }, - }, - }) - .catch((_e) => - console.error( - "failed creating course requirement", - courseCode, - "for degree", - degree.name, - _e - ) - ); - }); - }); - // FIXME: create separate script (+bash script to call it) for updating db with above function and creation of prisma client without timeout - // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting -}; + diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts new file mode 100644 index 0000000..d0847c7 --- /dev/null +++ b/kanban-dashboard/src/server/api/db.ts @@ -0,0 +1,98 @@ +import { PrismaClient } from "@prisma/client"; +import { + scrapeDegrees, + scrapeSubjects, + scrapeCollegesAndDepartments, + scrapeSubjectCourses, + scrapeDegreeRequirements, +} from "../../scraping/catalog"; + +export const updateCatalogDataInDB = async (prisma: PrismaClient) => { + const [departments, subjects, degrees] = await Promise.all([ + scrapeCollegesAndDepartments().then((colleges) => + colleges + .map((col) => col.departments.map(({ name, id }) => ({ name, id }))) + .flat() + ), + scrapeSubjects(), + scrapeDegrees(), + ]); + const skipDuplicates = true; + // TODO: figure out how to join these into a (single?) Promise.all + await prisma.department.createMany({ data: departments, skipDuplicates }); + await prisma.subject.createMany({ data: subjects, skipDuplicates }); + const foundCourses = new Set(); + await Promise.all( + subjects.map(async (subject) => { + const courses = await scrapeSubjectCourses(subject.code); + console.log( + "found", + courses.length, + "courses for subject:", + subject.code + ); + for (const course of courses) { + foundCourses.add(course.code); + } + await prisma.subject.update({ + where: { code: subject.code }, + data: { + courses: { + createMany: { + data: courses, + skipDuplicates, + }, + }, + }, + }); + }) + ); + + await prisma.degree.createMany({ data: degrees, skipDuplicates }); + await prisma.courseRequirement.deleteMany(); + degrees.forEach(async (degree) => { + const courseCodes = await scrapeDegreeRequirements(degree).then((reqs) => + Array.from(reqs.courses.keys()) + ); + courseCodes.forEach(async (courseCode) => { + console.log( + "creating course requirement", + courseCode, + "for degree", + degree.name + ); + await prisma.courseRequirement + .create({ + data: { + course: { connect: { code: courseCode } }, + degree: { connect: { id: degree.id } }, + }, + }) + .catch((_e) => + console.error( + "failed creating course requirement", + courseCode, + "for degree", + degree.name, + _e + ) + ); + }); + }); + // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting + // FIXME: implement retry logic as connection is very unstable +}; + +if (require.main === module) { + const prisma = new PrismaClient({ + log: + process.env.NODE_ENV === "development" + ? ["query", "error", "warn"] + : ["error"], + datasources: { + // set timeout to unlimited because adding degree requirements is very slow + db: { url: process.env.DATABASE_URL + "&pool_timeout=0" }, + }, + }); + (async () => await updateCatalogDataInDB(prisma).then(console.log))(); +} diff --git a/kanban-dashboard/update-db.sh b/kanban-dashboard/update-db.sh new file mode 100755 index 0000000..bdfc802 --- /dev/null +++ b/kanban-dashboard/update-db.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +ts-node --transpile-only --skip-project ./src/server/api/db.ts From 5ce47ab239bfe0d1820b578e36343410083c7d7c Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 1 Jun 2023 17:14:52 -0700 Subject: [PATCH 31/62] create CourseCodeSchema for validation --- kanban-dashboard/src/scraping/catalog.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 5df60cd..eab3363 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -390,9 +390,10 @@ export const scrapeDegrees = async () => { }; const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); +const CourseCodeSchema = z.string().regex(/^[A-Z]+\s\d+$/) const CourseSchema = z.object({ - code: z.string(), + code: CourseCodeSchema, title: z.string(), // subjectCode: z.string(), number: z.number(), From a0d6d93b8798c0741baa7c2a1c4a635ca72626a3 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 3 Jun 2023 18:07:06 -0700 Subject: [PATCH 32/62] extract major courses function --- kanban-dashboard/src/scraping/catalog.ts | 383 +++++++++++------------ 1 file changed, 189 insertions(+), 194 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index eab3363..3e0d0ed 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -121,17 +121,13 @@ export const DegreeSchema = z.object({ }); export type Degree = z.infer; -export const DegreeWithRequirementsSchema = DegreeSchema.extend({ + +export const DegreeRequirementsSchema = z.object({ requirements: z.array(RequirementSchema), courses: z.map(z.string(), RequirementCourseSchema), }); -export type DegreeWithRequirements = z.infer< - typeof DegreeWithRequirementsSchema ->; -export const scrapeDegreeRequirements = async ( - degreeWOReqs: Degree -): Promise => { +const parseMajorCourseRequirementsTable = ($, table) => { // select from the following // If we're in a sftf block the courses are in one of the following formats: // a) @@ -161,211 +157,212 @@ export const scrapeDegreeRequirements = async ( // d) // [course] // or [course] + const courses = new Map(); + const requirements = []; const SFTF_RE = /\s*Select( one sequence)? from the following.*/; - const degree: DegreeWithRequirements = { - ...degreeWOReqs, - requirements: [], - courses: new Map(), - }; - const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); - - const tables = $("table.sc_courselist"); - - const requirements = degree.requirements; - const courses = degree.courses; - - tables.each((_ti, table) => { - const table_desc = $(table).prevAll().filter("h2").first().text(); - if (table_desc !== "Degree Requirements and Curriculum") { - console.warn("Parsing table of unrecognized kind:", table_desc); - } - - let cur_section: string | null = null; - // within a select from the following block - // see comment at top of file which explains these flags - let in_sftf = false; - let sftf_sep = null; - let prev_was_or = false; - const rows = $(table).find("tr"); - for (let i = 0; i < rows.length; i++) { - const tr = rows[i]; - // TODO: extracting 1 footnote tags - - if ($(tr).hasClass("areaheader")) { - in_sftf = false; - prev_was_or = false; + let cur_section: string | null = null; + // within a select from the following block + // see comment at top of file which explains these flags + let in_sftf = false; + let sftf_sep = null; + let prev_was_or = false; + const rows = $(table).find("tr"); + for (let i = 0; i < rows.length; i++) { + const tr = rows[i]; + // TODO: extracting 1 footnote tags + + if ($(tr).hasClass("areaheader")) { + in_sftf = false; + prev_was_or = false; + sftf_sep = null; + // new section + const cur_section_title = $(tr).text().trim(); + if (cur_section_title.includes("MAJOR COURSES")) { + cur_section = "major"; + } else if (cur_section_title.includes("Electives")) { + // FIXME: include the type of elective + cur_section = "elective"; + } else if (cur_section_title.includes("GENERAL EDUCATION")) { + cur_section = "ge"; + } else if (cur_section_title.includes("SUPPORT COURSES")) { + cur_section = "support"; + } else { + cur_section = cur_section_title as RequirementType; + // console.log("Unrecognized section kind for", cur_section_title); + } + if (!cur_section) { + console.error("no text in header:", $(tr)); + break; + } + } else if ($(tr).find("span.courselistcomment").length > 0) { + const comment = $(tr).find("span.courselistcomment").text().trim(); + if (comment.match(SFTF_RE)) { + in_sftf = true; + requirements.push({ or: [] }); sftf_sep = null; - // new section - const cur_section_title = $(tr).text().trim(); - if (cur_section_title.includes("MAJOR COURSES")) { - cur_section = "major"; - } else if (cur_section_title.includes("Electives")) { - // FIXME: include the type of elective - cur_section = "elective"; - } else if (cur_section_title.includes("GENERAL EDUCATION")) { - cur_section = "ge"; - } else if (cur_section_title.includes("SUPPORT COURSES")) { - cur_section = "support"; - } else { - cur_section = cur_section_title as RequirementType; - // console.log("Unrecognized section kind for", cur_section_title); - } - if (!cur_section) { - console.error("no text in header:", $(tr)); + } else if (comment === "or") { + if (!in_sftf) { + console.warn( + "Found an \"or\" row outside of 'Select from the following' block. There's even more variations :/", + "in", + degree.name, + "(", + degree.link, + ")", + comment + ); break; } - } else if ($(tr).find("span.courselistcomment").length > 0) { - const comment = $(tr).find("span.courselistcomment").text().trim(); - if (comment.match(SFTF_RE)) { - in_sftf = true; - requirements.push({ or: [] }); - sftf_sep = null; - } else if (comment === "or") { - if (!in_sftf) { - console.warn( - "Found an \"or\" row outside of 'Select from the following' block. There's even more variations :/", - "in", - degree.name, - "(", - degree.link, - ")", - comment - ); - break; - } - sftf_sep = "or"; - prev_was_or = true; - } else { - console.error("unrecognized comment:", comment); - } + sftf_sep = "or"; + prev_was_or = true; } else { - const course_elem = $(tr).find("td.codecol a[title]"); - let course: any; // TODO: type this - const is_and = course_elem.length > 1; - if (is_and) { - // course is actually courses plural - // make sure it's actually an '&' of the courses - if (!$(tr).find("span.blockindent").text().includes("&")) { - console.error( - "multiple elements found but no & to be found in:", - $(tr) - ); - } - const course_codes: string[] = []; - $(course_elem).each((_i, c) => { - course_codes.push($(c).text().trim()); + console.error("unrecognized comment:", comment); + } + } else { + const course_elem = $(tr).find("td.codecol a[title]"); + let course: any; // TODO: type this + const is_and = course_elem.length > 1; + if (is_and) { + // course is actually courses plural + // make sure it's actually an '&' of the courses + if (!$(tr).find("span.blockindent").text().includes("&")) { + console.error( + "multiple elements found but no & to be found in:", + $(tr) + ); + } + const course_codes: string[] = []; + $(course_elem).each((_i, c) => { + course_codes.push($(c).text().trim()); + }); + const course_titles = []; + const titles = $(tr).find("td:not([class])"); + $(titles) + .contents() + .each((i, t) => { + if (t.type === "text" && i === 0) { + course_titles.push($(t).text().trim()); + } else if (t.type === "tag" && t.name === "span") { + course_titles.push($(t).text().trim().replace(/^and /, "")); + } }); - const course_titles = []; - const titles = $(tr).find("td:not([class])"); - $(titles) - .contents() - .each((i, t) => { - if (t.type === "text" && i === 0) { - course_titles.push($(t).text().trim()); - } else if (t.type === "tag" && t.name === "span") { - course_titles.push($(t).text().trim().replace(/^and /, "")); - } - }); - if (course_codes.length !== course_titles.length) { - console.warn( - "found different length code,title lists in and block:", - { course_titles, course_codes }, - "in", - degree.name - ); - } else if (course_titles.length === 0) { - console.warn( - "didnt find any titles for course list:", - course_codes - ); - } else { - course_codes.map((code, i) => { - courses.set(code, { - code, - title: course_titles[i], - units: 0, // TODO: total units - }); + if (course_codes.length !== course_titles.length) { + console.warn( + "found different length code,title lists in and block:", + { course_titles, course_codes }, + "in", + degree.name + ); + } else if (course_titles.length === 0) { + console.warn("didnt find any titles for course list:", course_codes); + } else { + course_codes.map((code, i) => { + courses.set(code, { + code, + title: course_titles[i], + units: 0, // TODO: total units }); - } - - course = { and: course_codes }; - } else if (course_elem.length !== 1) { - if ($(tr).hasClass("listsum")) { - continue; - } - // TODO: handle sections with references to other information on page - console.log("no title for:", $(tr).find("td.codecol").text().trim()); + }); } - if (!is_and && course_elem.length === 1) { - course = course_elem.text().trim(); + + course = { and: course_codes }; + } else if (course_elem.length !== 1) { + if ($(tr).hasClass("listsum")) { + continue; } - const has_orclass = $(tr).hasClass("orclass"); - const last = requirements.length - 1; - - if (in_sftf) { - const last_or = requirements[last].or; - if (last_or.length === 0) { - last_or.push(course); - } else if (last_or.length >= 1) { - if (last_or.length === 1 && has_orclass) { - sftf_sep = "or"; - } - if (has_orclass || prev_was_or || sftf_sep == null) { - requirements[last].or.push(course); - } else { - in_sftf = false; - sftf_sep = null; - } + // TODO: handle sections with references to other information on page + console.log("no title for:", $(tr).find("td.codecol").text().trim()); + } + if (!is_and && course_elem.length === 1) { + course = course_elem.text().trim(); + } + const has_orclass = $(tr).hasClass("orclass"); + const last = requirements.length - 1; + + if (in_sftf) { + const last_or = requirements[last].or; + if (last_or.length === 0) { + last_or.push(course); + } else if (last_or.length >= 1) { + if (last_or.length === 1 && has_orclass) { + sftf_sep = "or"; + } + if (has_orclass || prev_was_or || sftf_sep == null) { + requirements[last].or.push(course); + } else { + in_sftf = false; + sftf_sep = null; } - prev_was_or = false; - } - if (!in_sftf && has_orclass) { - // TODO: assert data.cur.last is not or already - // (multiple or's chained togehter outside of sftf) - requirements[last] = { - or: [requirements[last], course], - }; - } else if (!in_sftf) { - // Normal row - requirements.push(course); - } - if (typeof course === "string") { - const title = $(tr).find("td:not([class])").text().trim(); - // TODO: more accurate units when in or/and block - const unitsStr = $(tr).find("td.hourscol").text().trim() || 0; - const units = parseInt(unitsStr); - const code = course; - const courseObj = RequirementCourseSchema.parse({ - title, - units, - code, - }); - courses.set(code, courseObj); } + prev_was_or = false; + } + if (!in_sftf && has_orclass) { + // TODO: assert data.cur.last is not or already + // (multiple or's chained togehter outside of sftf) + requirements[last] = { + or: [requirements[last], course], + }; + } else if (!in_sftf) { + // Normal row + requirements.push(course); } + if (typeof course === "string") { + const title = $(tr).find("td:not([class])").text().trim(); + // TODO: more accurate units when in or/and block + const unitsStr = $(tr).find("td.hourscol").text().trim() || 0; + const units = parseInt(unitsStr); + const code = course; + const courseObj = RequirementCourseSchema.parse({ + title, + units, + code, + }); + courses.set(code, courseObj); + } + } + } + // TODO: Parse GE table + // (returning false prevents it from being parsed by ending the iteration after the first table) + return { courses, requirements }; +}; +export const scrapeDegreeRequirements = async (degree: Degree) => { + const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); + let requirements; + + // TODO: Parse footers (sc_footnotes) + const tables = $("table.sc_courselist"); + console.log(tables.length); + + tables.each((_ti, table) => { + // page has flat structure and this is a way to find the previous h2 element (prevUntil is exclusive) + const titleElem = $(table).prevUntil("h2").last().prev(); + const title = $(titleElem).text().trim(); + if (title === "Degree Requirements and Curriculum") { + requirements = parseMajorCourseRequirementsTable($, table); + } else if (title === "General Education (GE) Requirements") { + // const geRequirements = parseGeCourseRequirementsTable($, table) + } else { + console.warn("Unrecognized table with title:", title); } - // TODO: Parse GE table - // (returning false prevents it from being parsed by ending the iteration after the first table) - return false; }); // NOTE: it is expected that information from crosslistings can be parsed in subject course lists and handled properly when using degree course requirements // const crossListedCourses = new Map(); // TODO: use non-crosslisted code when inserting course into courses, requirements instead of having postProcess loop - const crossListedCourses = new Map(); - courses.forEach((req, code) => { - const codeWOCrosslist = code.replace(/\/[A-Z]+/, ""); - req.code = codeWOCrosslist; - crossListedCourses.set(code, req); - }); - crossListedCourses.forEach((req, crossListedCourseCode) => { - courses.delete(crossListedCourseCode); - courses.set(req.code, req); - }); + // const crossListedCourses = new Map(); + // requirements.courses.forEach((req, code) => { + // const codeWOCrosslist = code.replace(/\/[A-Z]+/, ""); + // req.code = codeWOCrosslist; + // crossListedCourses.set(code, req); + // }); + // crossListedCourses.forEach((req, crossListedCourseCode) => { + // requirements.courses.delete(crossListedCourseCode); + // requirements.courses.set(req.code, req); + // }); // TODO: check for correctness by counting the units and comparing to the degree's unit count - return degree; + return requirements; }; export const scrapeDegrees = async () => { @@ -390,7 +387,7 @@ export const scrapeDegrees = async () => { }; const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); -const CourseCodeSchema = z.string().regex(/^[A-Z]+\s\d+$/) +const CourseCodeSchema = z.string().regex(/^[A-Z]+\s\d+$/); const CourseSchema = z.object({ code: CourseCodeSchema, @@ -490,5 +487,3 @@ export const scrapeSubjects = async () => { }); return subjects; }; - - From 13a2a0fa622d6baa7fe7464466a78c5e5042d9cb Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 3 Jun 2023 18:21:11 -0700 Subject: [PATCH 33/62] refactor requirements list as list of and/or groups --- kanban-dashboard/src/scraping/catalog.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 3e0d0ed..ce57431 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -127,7 +127,7 @@ export const DegreeRequirementsSchema = z.object({ courses: z.map(z.string(), RequirementCourseSchema), }); -const parseMajorCourseRequirementsTable = ($, table) => { +const parseMajorCourseRequirementsTable = ($, table, degree) => { // select from the following // If we're in a sftf block the courses are in one of the following formats: // a) @@ -322,9 +322,9 @@ const parseMajorCourseRequirementsTable = ($, table) => { } } } - // TODO: Parse GE table - // (returning false prevents it from being parsed by ending the iteration after the first table) - return { courses, requirements }; + // or and and groups + const groups = requirements.filter(req => typeof req !== "string") + return { courses, groups }; }; export const scrapeDegreeRequirements = async (degree: Degree) => { const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); @@ -339,7 +339,7 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { - requirements = parseMajorCourseRequirementsTable($, table); + requirements = parseMajorCourseRequirementsTable($, table, degree); } else if (title === "General Education (GE) Requirements") { // const geRequirements = parseGeCourseRequirementsTable($, table) } else { From 8946e4afdba03ae870d2d51b4a634fabaec5401e Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 3 Jun 2023 18:42:22 -0700 Subject: [PATCH 34/62] add course req kind --- kanban-dashboard/src/scraping/catalog.ts | 41 +++++++++++++----------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index ce57431..446093a 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -105,6 +105,7 @@ export const RequirementSchema = z.object({ }); export const RequirementCourseSchema = z.object({ + kind: RequirementTypeSchema.or(z.string()), code: z.string(), units: z.number(), title: z.string(), @@ -161,7 +162,7 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { const requirements = []; const SFTF_RE = /\s*Select( one sequence)? from the following.*/; - let cur_section: string | null = null; + let curRequirementKind: string | null = null; // within a select from the following block // see comment at top of file which explains these flags let in_sftf = false; @@ -177,21 +178,21 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { prev_was_or = false; sftf_sep = null; // new section - const cur_section_title = $(tr).text().trim(); - if (cur_section_title.includes("MAJOR COURSES")) { - cur_section = "major"; - } else if (cur_section_title.includes("Electives")) { + const sectionTitle = $(tr).text().trim(); + if (sectionTitle.includes("MAJOR COURSES")) { + curRequirementKind = "major"; + } else if (sectionTitle.includes("Electives")) { // FIXME: include the type of elective - cur_section = "elective"; - } else if (cur_section_title.includes("GENERAL EDUCATION")) { - cur_section = "ge"; - } else if (cur_section_title.includes("SUPPORT COURSES")) { - cur_section = "support"; + curRequirementKind = "elective"; + } else if (sectionTitle.includes("GENERAL EDUCATION")) { + curRequirementKind = "ge"; + } else if (sectionTitle.includes("SUPPORT COURSES")) { + curRequirementKind = "support"; } else { - cur_section = cur_section_title as RequirementType; - // console.log("Unrecognized section kind for", cur_section_title); + curRequirementKind = sectionTitle as RequirementType; + console.log("Unrecognized section kind for", sectionTitle); } - if (!cur_section) { + if (!curRequirementKind) { console.error("no text in header:", $(tr)); break; } @@ -222,8 +223,8 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { } else { const course_elem = $(tr).find("td.codecol a[title]"); let course: any; // TODO: type this - const is_and = course_elem.length > 1; - if (is_and) { + const isAndGroup = course_elem.length > 1; + if (isAndGroup) { // course is actually courses plural // make sure it's actually an '&' of the courses if (!$(tr).find("span.blockindent").text().includes("&")) { @@ -236,11 +237,11 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { $(course_elem).each((_i, c) => { course_codes.push($(c).text().trim()); }); - const course_titles = []; + const course_titles: string[] = []; const titles = $(tr).find("td:not([class])"); $(titles) .contents() - .each((i, t) => { + .each((i: number, t) => { if (t.type === "text" && i === 0) { course_titles.push($(t).text().trim()); } else if (t.type === "tag" && t.name === "span") { @@ -259,6 +260,7 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { } else { course_codes.map((code, i) => { courses.set(code, { + kind: curRequirementKind, code, title: course_titles[i], units: 0, // TODO: total units @@ -274,7 +276,7 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { // TODO: handle sections with references to other information on page console.log("no title for:", $(tr).find("td.codecol").text().trim()); } - if (!is_and && course_elem.length === 1) { + if (!isAndGroup && course_elem.length === 1) { course = course_elem.text().trim(); } const has_orclass = $(tr).hasClass("orclass"); @@ -314,12 +316,13 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { const units = parseInt(unitsStr); const code = course; const courseObj = RequirementCourseSchema.parse({ + kind: curRequirementKind, title, units, code, }); courses.set(code, courseObj); - } + } else console.warn("unrecognized:", course) } } // or and and groups From 7d25f14b7c530357b67d56e31b4207adb97ca845 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 3 Jun 2023 19:42:25 -0700 Subject: [PATCH 35/62] parsing ge reqs table --- kanban-dashboard/src/scraping/catalog.ts | 56 ++++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 446093a..6baa76e 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -128,7 +128,11 @@ export const DegreeRequirementsSchema = z.object({ courses: z.map(z.string(), RequirementCourseSchema), }); -const parseMajorCourseRequirementsTable = ($, table, degree) => { +const parseMajorCourseRequirementsTable = ( + $: cheerio.CheerioAPI, + table: cheerio.Element, + degree: Degree +) => { // select from the following // If we're in a sftf block the courses are in one of the following formats: // a) @@ -322,29 +326,65 @@ const parseMajorCourseRequirementsTable = ($, table, degree) => { code, }); courses.set(code, courseObj); - } else console.warn("unrecognized:", course) + } else console.warn("unrecognized:", course); } } - // or and and groups - const groups = requirements.filter(req => typeof req !== "string") + // or and and groups + const groups = requirements.filter((req) => typeof req !== "string"); return { courses, groups }; }; + +const GeAreaCodeRE = /[ABCDEF][1234]/; +const GeDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; +const GeAreaRE = /Area [ABCDEF]( Elective)?/; + +const GeRequirementSchema = z.object({ + code: z + .string() + .regex(GeAreaCodeRE) + .or(z.string().regex(GeDivisionCodeRE)) + .or(z.string().regex(GeAreaRE)) + .or(z.undefined()), + // TODO: unitsOf + // TODO: constraints (C1 or C2) / fullfilled by (B3 = lab w/ B1 or B2 course) +}); + +type GeRequirement = z.infer; + +const parseGeCourseRequirementsTable = ( + $: cheerio.CheerioAPI, + table: cheerio.Element +) => { + const requirements: GeRequirement[] = $(table) + .find("tr") + .filter(":not(:is(.areaheader,.listsum))") + .map((_i, tr) => { + const label = $(tr).find("td").first().text(); + let [code] = label.match(GeAreaCodeRE) ?? label.match(GeAreaRE) ?? label.match(GeDivisionCodeRE) ?? label.match(/^[ABCDEF]/) ?? []; + if (!code) console.error("unrecognized ge:", label); + return { code } + }) + .get() + .filter(({code}) => !!code) + console.log(requirements); + return requirements; +}; + export const scrapeDegreeRequirements = async (degree: Degree) => { const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); - let requirements; + let requirements = {}; // TODO: Parse footers (sc_footnotes) const tables = $("table.sc_courselist"); - console.log(tables.length); tables.each((_ti, table) => { // page has flat structure and this is a way to find the previous h2 element (prevUntil is exclusive) const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { - requirements = parseMajorCourseRequirementsTable($, table, degree); + // requirements.major = parseMajorCourseRequirementsTable($, table, degree); } else if (title === "General Education (GE) Requirements") { - // const geRequirements = parseGeCourseRequirementsTable($, table) + requirements.ge = parseGeCourseRequirementsTable($, table); } else { console.warn("Unrecognized table with title:", title); } From 378053f6159848df5fafb422b3660ef8581078c0 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sat, 3 Jun 2023 20:21:51 -0700 Subject: [PATCH 36/62] include ge units --- kanban-dashboard/src/scraping/catalog.ts | 84 +++++++++++++++++------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 6baa76e..51cc0e6 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -123,11 +123,32 @@ export const DegreeSchema = z.object({ export type Degree = z.infer; +const GeAreaCodeRE = /[ABCDEF][1234]/; +const GeDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; +const GeAreaRE = /Area [ABCDEF]( Elective)?/; + +const GeRequirementSchema = z.object({ + code: z + .string() + .regex(GeAreaCodeRE) + .or(z.string().regex(GeDivisionCodeRE)) + .or(z.string().regex(GeAreaRE)) + .or(z.null()), + units: z.number().nonnegative(), + // TODO: constraints (C1 or C2) / fullfilled by (B3 = lab w/ B1 or B2 course) +}); + +type GeRequirement = z.infer; + export const DegreeRequirementsSchema = z.object({ + degreeId: DegreeSchema.shape.id, requirements: z.array(RequirementSchema), courses: z.map(z.string(), RequirementCourseSchema), + ge: z.array(GeRequirementSchema), }); +export type DegreeRequirements = z.infer; + const parseMajorCourseRequirementsTable = ( $: cheerio.CheerioAPI, table: cheerio.Element, @@ -334,23 +355,6 @@ const parseMajorCourseRequirementsTable = ( return { courses, groups }; }; -const GeAreaCodeRE = /[ABCDEF][1234]/; -const GeDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; -const GeAreaRE = /Area [ABCDEF]( Elective)?/; - -const GeRequirementSchema = z.object({ - code: z - .string() - .regex(GeAreaCodeRE) - .or(z.string().regex(GeDivisionCodeRE)) - .or(z.string().regex(GeAreaRE)) - .or(z.undefined()), - // TODO: unitsOf - // TODO: constraints (C1 or C2) / fullfilled by (B3 = lab w/ B1 or B2 course) -}); - -type GeRequirement = z.infer; - const parseGeCourseRequirementsTable = ( $: cheerio.CheerioAPI, table: cheerio.Element @@ -360,19 +364,53 @@ const parseGeCourseRequirementsTable = ( .filter(":not(:is(.areaheader,.listsum))") .map((_i, tr) => { const label = $(tr).find("td").first().text(); - let [code] = label.match(GeAreaCodeRE) ?? label.match(GeAreaRE) ?? label.match(GeDivisionCodeRE) ?? label.match(/^[ABCDEF]/) ?? []; - if (!code) console.error("unrecognized ge:", label); - return { code } + let units = parseInt($(tr).find("td.hourscol").text().trim()); + if (isNaN(units)) { + let cSubjectPrefixesWarningStr = + "Lower-division courses in Area C must come from three different subject prefixes."; + if (label.includes(cSubjectPrefixesWarningStr)) { + return null; + } + } + let [code] = label.match(GeAreaCodeRE) ?? + label.match(GeAreaRE) ?? + label.match(GeDivisionCodeRE) ?? + label.match(/^[ABCDEF]/) ?? [null]; + if (code === undefined) { + if (label.includes("Select courses from two different areas")) { + return null; + } else if (label.includes("GE Electives")) { + code = null; + console.log(label); + console.assert(isNaN(units), "electives does not have NaN units"); + } else { + console.error("unrecognized ge:", label); + return null; + } + } + if (isNaN(units)) { + units = 0; + const rowText = $(tr).text(); + const b3OneLabWarningStr = + "One lab taken with either a B1 or B2 course"; + const twoAreasWarning = "Select courses from two different areas"; + if ( + !rowText.includes(twoAreasWarning) && + code !== "B3" + ) { + console.error("could not determine why units for:", label, "was NaN"); + } + } + return { code, units }; }) .get() - .filter(({code}) => !!code) - console.log(requirements); + .filter((req) => !!req); return requirements; }; export const scrapeDegreeRequirements = async (degree: Degree) => { const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); - let requirements = {}; + let requirements: DegreeRequirements = {}; // TODO: Parse footers (sc_footnotes) const tables = $("table.sc_courselist"); From 3c38fb28c5eacd4e5b0c199db97c92d12cf91158 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Sun, 4 Jun 2023 21:59:39 -0700 Subject: [PATCH 37/62] rigid course code schema --- kanban-dashboard/src/scraping/catalog.ts | 131 +++++++++++++---------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 51cc0e6..bfdf52a 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient, Requirement } from "@prisma/client"; import assert from "assert"; import * as cheerio from "cheerio/lib/slim"; import { z } from "zod"; @@ -83,30 +83,49 @@ export const RequirementTypeSchema = z.enum([ ]); export type RequirementType = z.infer; -export const RequirementCourseCodeSchema = z.string(); +const stripCrosslistInfoFromCourseCode = (courseCode: string) => { + const match = courseCode.match(/([A-Z]+)(?:\/[A-Z]+)*\s+(\d+)(?:\s+\d+)*/); + console.log(match); + if (!match) + throw new Error( + `course code: ${courseCode} did not match the course code regex` + ); + const [_, code, num] = match; + courseCode = code + " " + num; + if (!courseCode.match(/^[A-Z]+\s\d+$/)) + throw new Error( + `resulting course code: ${courseCode} from stripping crosslist info is not a valid course code` + ); + return courseCode; +}; -export const RequirementOneOfSchema: z.ZodType = z.object({ - kind: z.literal("oneof"), - oneof: z.array( - RequirementCourseCodeSchema.or(z.lazy(() => RequirementAllOfSchema)) - ), -}); -export const RequirementAllOfSchema = z.object({ - kind: z.literal("allof"), - allof: z.array(RequirementCourseCodeSchema.or(RequirementOneOfSchema)), -}); -export const RequirementSchema = z.object({ - kind: RequirementTypeSchema.or(z.string()), - fulfilledBy: z.array( - RequirementCourseCodeSchema.or(RequirementAllOfSchema).or( - RequirementOneOfSchema - ) - ), -}); +// NOTE: it is expected that information from crosslistings can be parsed in subject course +// lists and handled properly when using degree course requirements +const CourseCodeSchema = z.string().transform(stripCrosslistInfoFromCourseCode); // .regex(/^[A-Z]+\s\d+$/); + +type CourseCode = z.infer; +type RequirementGroupList = (RequirementGroup | CourseCode)[]; +type RequirementGroup = + | { or: RequirementGroupList } + | { and: RequirementGroupList }; + +export const RequirementGroupSchema: z.ZodType = z.lazy(() => + z.union([ + z.object({ or: z.array(RequirementGroupSchema.or(CourseCodeSchema)) }), + z.object({ and: z.array(RequirementGroupSchema.or(CourseCodeSchema)) }), + ]) +); + +// TODO: decide whether this is usefull +// export const RequirementSchema = z.object({ +// kind: RequirementTypeSchema.or(z.string()), +// fulfilledBy: +// +// }); export const RequirementCourseSchema = z.object({ kind: RequirementTypeSchema.or(z.string()), - code: z.string(), + code: CourseCodeSchema, units: z.number(), title: z.string(), }); @@ -142,7 +161,7 @@ type GeRequirement = z.infer; export const DegreeRequirementsSchema = z.object({ degreeId: DegreeSchema.shape.id, - requirements: z.array(RequirementSchema), + groups: z.array(RequirementGroupSchema), courses: z.map(z.string(), RequirementCourseSchema), ge: z.array(GeRequirementSchema), }); @@ -183,8 +202,10 @@ const parseMajorCourseRequirementsTable = ( // d) // [course] // or [course] + /// mapping of course code to meta information about the course (such as whether it is a support/major/etc) const courses = new Map(); - const requirements = []; + // TODO: + const groups: RequirementGroup[] = []; const SFTF_RE = /\s*Select( one sequence)? from the following.*/; let curRequirementKind: string | null = null; @@ -215,7 +236,7 @@ const parseMajorCourseRequirementsTable = ( curRequirementKind = "support"; } else { curRequirementKind = sectionTitle as RequirementType; - console.log("Unrecognized section kind for", sectionTitle); + console.log("Unrecognized section kind:", sectionTitle); } if (!curRequirementKind) { console.error("no text in header:", $(tr)); @@ -225,7 +246,7 @@ const parseMajorCourseRequirementsTable = ( const comment = $(tr).find("span.courselistcomment").text().trim(); if (comment.match(SFTF_RE)) { in_sftf = true; - requirements.push({ or: [] }); + groups.push({ or: [] }); sftf_sep = null; } else if (comment === "or") { if (!in_sftf) { @@ -242,7 +263,7 @@ const parseMajorCourseRequirementsTable = ( } sftf_sep = "or"; prev_was_or = true; - } else { + } else if (!comment.match(/\(?[Ss](ee|elect).*below.?\)?$/)) { console.error("unrecognized comment:", comment); } } else { @@ -305,10 +326,10 @@ const parseMajorCourseRequirementsTable = ( course = course_elem.text().trim(); } const has_orclass = $(tr).hasClass("orclass"); - const last = requirements.length - 1; + const last = groups.length - 1; if (in_sftf) { - const last_or = requirements[last].or; + const last_or = groups[last].or; if (last_or.length === 0) { last_or.push(course); } else if (last_or.length >= 1) { @@ -316,7 +337,7 @@ const parseMajorCourseRequirementsTable = ( sftf_sep = "or"; } if (has_orclass || prev_was_or || sftf_sep == null) { - requirements[last].or.push(course); + groups[last].or.push(course); } else { in_sftf = false; sftf_sep = null; @@ -327,14 +348,14 @@ const parseMajorCourseRequirementsTable = ( if (!in_sftf && has_orclass) { // TODO: assert data.cur.last is not or already // (multiple or's chained togehter outside of sftf) - requirements[last] = { - or: [requirements[last], course], + groups[last] = { + or: [groups[last], course], }; } else if (!in_sftf) { // Normal row - requirements.push(course); + groups.push(course); } - if (typeof course === "string") { + if (!course.and) { const title = $(tr).find("td:not([class])").text().trim(); // TODO: more accurate units when in or/and block const unitsStr = $(tr).find("td.hourscol").text().trim() || 0; @@ -347,11 +368,14 @@ const parseMajorCourseRequirementsTable = ( code, }); courses.set(code, courseObj); - } else console.warn("unrecognized:", course); + } } } - // or and and groups - const groups = requirements.filter((req) => typeof req !== "string"); + courses.forEach((code, { kind }) => { + if (["support", "elective"].includes(kind) && !!groups.find(code)) { + console.error("/////", kind, code, "not in or/and group"); + } + }); return { courses, groups }; }; @@ -359,6 +383,7 @@ const parseGeCourseRequirementsTable = ( $: cheerio.CheerioAPI, table: cheerio.Element ) => { + // FIXME: parse ge "constraints" (C1 or C2, three different prefixes, etc) const requirements: GeRequirement[] = $(table) .find("tr") .filter(":not(:is(.areaheader,.listsum))") @@ -378,7 +403,7 @@ const parseGeCourseRequirementsTable = ( label.match(/^[ABCDEF]/) ?? [null]; if (code === undefined) { if (label.includes("Select courses from two different areas")) { - return null; + return null; } else if (label.includes("GE Electives")) { code = null; console.log(label); @@ -394,10 +419,7 @@ const parseGeCourseRequirementsTable = ( const b3OneLabWarningStr = "One lab taken with either a B1 or B2 course"; const twoAreasWarning = "Select courses from two different areas"; - if ( - !rowText.includes(twoAreasWarning) && - code !== "B3" - ) { + if (!rowText.includes(twoAreasWarning) && code !== "B3") { console.error("could not determine why units for:", label, "was NaN"); } } @@ -410,7 +432,7 @@ const parseGeCourseRequirementsTable = ( export const scrapeDegreeRequirements = async (degree: Degree) => { const $ = cheerio.load(await fetch(degree.link).then((res) => res.text())); - let requirements: DegreeRequirements = {}; + let requirements: DegreeRequirements = {} as DegreeRequirements; // TODO: Parse footers (sc_footnotes) const tables = $("table.sc_courselist"); @@ -420,28 +442,22 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { - // requirements.major = parseMajorCourseRequirementsTable($, table, degree); + const { courses, groups } = parseMajorCourseRequirementsTable( + $, + table, + degree + ); + requirements.courses = courses; + requirements.groups = groups; } else if (title === "General Education (GE) Requirements") { requirements.ge = parseGeCourseRequirementsTable($, table); } else { console.warn("Unrecognized table with title:", title); } }); - // NOTE: it is expected that information from crosslistings can be parsed in subject course lists and handled properly when using degree course requirements - // const crossListedCourses = new Map(); - // TODO: use non-crosslisted code when inserting course into courses, requirements instead of having postProcess loop - // const crossListedCourses = new Map(); - // requirements.courses.forEach((req, code) => { - // const codeWOCrosslist = code.replace(/\/[A-Z]+/, ""); - // req.code = codeWOCrosslist; - // crossListedCourses.set(code, req); - // }); - // crossListedCourses.forEach((req, crossListedCourseCode) => { - // requirements.courses.delete(crossListedCourseCode); - // requirements.courses.set(req.code, req); - // }); // TODO: check for correctness by counting the units and comparing to the degree's unit count + // could keep total units count in groups and check against stated unit totals return requirements; }; @@ -468,7 +484,6 @@ export const scrapeDegrees = async () => { }; const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); -const CourseCodeSchema = z.string().regex(/^[A-Z]+\s\d+$/); const CourseSchema = z.object({ code: CourseCodeSchema, @@ -549,7 +564,7 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { export const SubjectSchema = z.object({ name: z.string(), - code: z.string(), + code: CourseCodeSchema, }); export type Subject = z.infer; From f627d0dc08efb7ce2527e88ea98390e780950a72 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 5 Jun 2023 09:19:32 -0700 Subject: [PATCH 38/62] ge area scraping --- kanban-dashboard/src/scraping/catalog.ts | 130 +++++++++++++++++++++-- 1 file changed, 123 insertions(+), 7 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index bfdf52a..876d1c7 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -142,15 +142,21 @@ export const DegreeSchema = z.object({ export type Degree = z.infer; -const GeAreaCodeRE = /[ABCDEF][1234]/; -const GeDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; +const GEAreaCodeRE = /[ABCDEF][1234]/; +const GEDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; const GeAreaRE = /Area [ABCDEF]( Elective)?/; +const GeSchema = z.union([ + z.string().regex(GEAreaCodeRE), + z.string().regex(GEDivisionCodeRE), + z.string().regex(GeAreaRE), +]); +export type GE = z.infer; const GeRequirementSchema = z.object({ code: z .string() - .regex(GeAreaCodeRE) - .or(z.string().regex(GeDivisionCodeRE)) + .regex(GEAreaCodeRE) + .or(z.string().regex(GEDivisionCodeRE)) .or(z.string().regex(GeAreaRE)) .or(z.null()), units: z.number().nonnegative(), @@ -397,9 +403,9 @@ const parseGeCourseRequirementsTable = ( return null; } } - let [code] = label.match(GeAreaCodeRE) ?? + let [code] = label.match(GEAreaCodeRE) ?? label.match(GeAreaRE) ?? - label.match(GeDivisionCodeRE) ?? + label.match(GEDivisionCodeRE) ?? label.match(/^[ABCDEF]/) ?? [null]; if (code === undefined) { if (label.includes("Select courses from two different areas")) { @@ -497,7 +503,6 @@ const CourseSchema = z.object({ minUnits: z.number(), maxUnits: z.number(), }); - type Course = z.infer; export const scrapeSubjectCourses = async (subjectCode: string) => { @@ -583,3 +588,114 @@ export const scrapeSubjects = async () => { }); return subjects; }; + +export const GEFullfillmentCoursesSchema = z.object({ + ge: z.string(), + meta: z.array(z.string()), + courses: z.array(CourseCodeSchema), +}); + +export type GEFullfillmentCourses = z.infer; + +/** Returns courses that fulfill ge requirements and which requirements they fulfill */ +export const scrapeCourseGEFullfillments = async () => { + const url = + "https://catalog.calpoly.edu/generalrequirementsbachelorsdegree/#GE-Requirements"; + const $ = await fetch(url) + .then((res) => res.text()) + .then(cheerio.load); + // TODO: use high-unit/standard info for verification against major ge requirement scraping + + const sections = new Map(); + const areaTables = $("table.tbl_transfercredits").filter( + (_i, table) => + // do not include info tables that are adjacent to sc_courselist tables + $(table).next(":not(.sc_courselist)").length > 0 && + $(table).prev(":not(.sc_courselist)").length > 0 + ); + areaTables.each((_i, table) => { + const info = { + meta: { + constraints: [], + }, + subareas: {}, + }; + const tbody = $(table).find("tbody"); + let areaLabel = $(tbody) + .find("tr.firstrow") + .find("td.column0") + .first() + .text() + .trim(); + let area = areaLabel; + if (areaLabel.includes("GE ELECTIVES")) { + info.meta.name = areaLabel; + area = "ELECTIVES"; + // TODO: include limit info (only area B C D) + } else { + let match = areaLabel.match(/\(AREA ([ABCDEF])\)/); + if (!match) + throw new Error( + "unrecognized ge area label for section: ".concat(areaLabel) + ); + area = match[1]; + areaLabel = areaLabel.replace(match[0], "").trim(); + info.meta.name = areaLabel; + } + + String.prototype.includesAny = function (ss: string[]) { + let includes = false; + for (let s of ss) { + includes = this.includes(s); + } + return includes; + }; + $(tbody) + .find("tr:not(.firstrow)") + .find("td.column0") + .map((_i, labelElement) => $(labelElement).text().trim()) + .get() + .filter((label) => { + return !!label && !["Unit Sub-total", "GE TOTAL"].includes(label); + }) + .forEach((label) => { + let match; + if ( + (match = label.match( + new RegExp(`\\(${area}([1234])-?(Writing Intensive)?\\)`) + )) + ) { + let [matched, subarea, _wi] = match; + info.subareas[subarea] = {desc: label.replace(matched, "").replace(/1$/, "").trim()}; + // TODO: handle wi (writing intensive) + } + + if (!match) info.meta.constraints.push(label); + }); + sections.set(area, info); + }); + const courseTables = $("table.sc_courselist"); + courseTables.each((_i, table) => { + const headerElement = $(table) + .prev("table.sc_sctable") + .find("tbody") + .find("tr") + .find("td.column0") + .get(); + // FIXME: error here + if (!headerElement) return; + const headerInfo = headerElement.map((e) => $(e).text().trim()); + const [title, ...meta] = headerInfo; + // TODO: updating title when "td>div.courselistcomment" is encountered + // TODO: parsing "ge" from title + const courses = $(table) + .find("td.codecol") + .map((_i, codeCol) => $(codeCol).text().trim()) + .get(); + const ge = { ge: title, meta, courses }; + + // sections.set(ge.ge, ge); + }); + // return Array.from(sections.values()); + return sections; +}; From 7689bf69067a84600b30a69732a0a11bfc3d4dfa Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Mon, 5 Jun 2023 15:16:48 -0700 Subject: [PATCH 39/62] parse subareas previously included in constraints --- kanban-dashboard/src/scraping/catalog.ts | 128 ++++++++++++++++------- 1 file changed, 88 insertions(+), 40 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 876d1c7..60335e7 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -105,6 +105,7 @@ const CourseCodeSchema = z.string().transform(stripCrosslistInfoFromCourseCode); type CourseCode = z.infer; type RequirementGroupList = (RequirementGroup | CourseCode)[]; +type RequirementGroupKind = "or" | "and"; type RequirementGroup = | { or: RequirementGroupList } | { and: RequirementGroupList }; @@ -145,12 +146,11 @@ export type Degree = z.infer; const GEAreaCodeRE = /[ABCDEF][1234]/; const GEDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; const GeAreaRE = /Area [ABCDEF]( Elective)?/; -const GeSchema = z.union([ +const GESubAreaVariant = z.union([ z.string().regex(GEAreaCodeRE), z.string().regex(GEDivisionCodeRE), z.string().regex(GeAreaRE), ]); -export type GE = z.infer; const GeRequirementSchema = z.object({ code: z @@ -350,13 +350,16 @@ const parseMajorCourseRequirementsTable = ( } } prev_was_or = false; - } - if (!in_sftf && has_orclass) { + } else if (has_orclass) { // TODO: assert data.cur.last is not or already // (multiple or's chained togehter outside of sftf) - groups[last] = { - or: [groups[last], course], - }; + if (groups[last].or) { + groups[last].or.push(course); + } else { + groups[last] = { + or: [groups[last], course], + }; + } } else if (!in_sftf) { // Normal row groups.push(course); @@ -489,7 +492,7 @@ export const scrapeDegrees = async () => { return degrees; }; -const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); +// const TermSchema = z.enum(["F", "W", "SP", "SU", "TBD"]); const CourseSchema = z.object({ code: CourseCodeSchema, @@ -503,6 +506,7 @@ const CourseSchema = z.object({ minUnits: z.number(), maxUnits: z.number(), }); + type Course = z.infer; export const scrapeSubjectCourses = async (subjectCode: string) => { @@ -519,7 +523,7 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { maxUnits = 0; const units_num = units_str.replace(" units", ""); if (units_num.includes("-")) { - const [minUnits, maxUnits] = units_num.split("-").map(Number); + [minUnits, maxUnits] = units_num.split("-").map(Number); } else { let units = parseInt(units_num); minUnits = units; @@ -589,13 +593,31 @@ export const scrapeSubjects = async () => { return subjects; }; -export const GEFullfillmentCoursesSchema = z.object({ - ge: z.string(), - meta: z.array(z.string()), - courses: z.array(CourseCodeSchema), -}); +const GEAreasEnum = z.enum(["A", "B", "C", "D", "E", "F", "ELECTIVES"]); + +const GESubAreaSchema = z + .object({ + constraints: z.array(z.string()).default([]), + name: z.string().nullable().default(null), + fullfilledBy: z.array(CourseCodeSchema).default([]), + description: z.string().nullable().default(null), + }) + .default({}); -export type GEFullfillmentCourses = z.infer; +type GESubArea = z.infer; + +const GEAreaSchema = z + .object({ + name: z.string().default(""), + constraints: z.array(z.string()).default([]), + subareas: z.record(GESubAreaVariant, GESubAreaSchema).default({}), + }) + .default({}); + +type GEArea = z.infer; + +export const GEDataSchema = z.map(GEAreasEnum, GEAreaSchema); +type GEData = z.infer; /** Returns courses that fulfill ge requirements and which requirements they fulfill */ export const scrapeCourseGEFullfillments = async () => { @@ -606,7 +628,7 @@ export const scrapeCourseGEFullfillments = async () => { .then(cheerio.load); // TODO: use high-unit/standard info for verification against major ge requirement scraping - const sections = new Map(); + const sections: GEData = new Map(); const areaTables = $("table.tbl_transfercredits").filter( (_i, table) => // do not include info tables that are adjacent to sc_courselist tables @@ -614,12 +636,7 @@ export const scrapeCourseGEFullfillments = async () => { $(table).prev(":not(.sc_courselist)").length > 0 ); areaTables.each((_i, table) => { - const info = { - meta: { - constraints: [], - }, - subareas: {}, - }; + const info: GEArea = GEAreaSchema.parse({}); const tbody = $(table).find("tbody"); let areaLabel = $(tbody) .find("tr.firstrow") @@ -627,9 +644,9 @@ export const scrapeCourseGEFullfillments = async () => { .first() .text() .trim(); - let area = areaLabel; + let area : z.infer; if (areaLabel.includes("GE ELECTIVES")) { - info.meta.name = areaLabel; + info.name = areaLabel; area = "ELECTIVES"; // TODO: include limit info (only area B C D) } else { @@ -638,39 +655,70 @@ export const scrapeCourseGEFullfillments = async () => { throw new Error( "unrecognized ge area label for section: ".concat(areaLabel) ); - area = match[1]; + area = GEAreasEnum.parse(match[1]); areaLabel = areaLabel.replace(match[0], "").trim(); - info.meta.name = areaLabel; + info.name = areaLabel; } - String.prototype.includesAny = function (ss: string[]) { - let includes = false; - for (let s of ss) { - includes = this.includes(s); - } - return includes; - }; $(tbody) .find("tr:not(.firstrow)") .find("td.column0") - .map((_i, labelElement) => $(labelElement).text().trim()) .get() + .map((labelElement) => $(labelElement).text().trim()) .filter((label) => { return !!label && !["Unit Sub-total", "GE TOTAL"].includes(label); }) .forEach((label) => { let match; + let subarea; + let subareaInfo: GESubArea = GESubAreaSchema.parse({}); if ( (match = label.match( - new RegExp(`\\(${area}([1234])-?(Writing Intensive)?\\)`) + /(?:-?(Writing Intensive))|(?:\s-\s((?:[\w \d,;-]|\(Standard\))+))/ )) ) { - let [matched, subarea, _wi] = match; - info.subareas[subarea] = {desc: label.replace(matched, "").replace(/1$/, "").trim()}; - // TODO: handle wi (writing intensive) + let subconstraint = match[1] ?? match[2]; + subareaInfo.constraints.push(subconstraint); + label = label.replace(match[0], "").replace("()", "").trim(); + // still push the label at the end + match = undefined; } - - if (!match) info.meta.constraints.push(label); + if ((match = label.match(new RegExp(`\\((${area}([1234])?)\\)`)))) { + let [matched, _subarea, num] = match; + label = label.replace(matched, "").replace(/1$/, "").trim(); + if (num) { + subarea = _subarea; + subareaInfo.description = label; + } + } + if ( + (match = label.match( + /((?:Upper|Lower)-Division) [A-F]( Elective)?s?/ + )) + ) { + let [matched, _subarea, elective] = match; + _subarea += elective ?? ""; + subarea = _subarea + label = label.replace(matched, "").trim(); + subareaInfo.description = label ?? null; + } + if ((match = label.match(/(Area [A-F] Elective)/))) { + subarea = "Elective" + } + if (!subarea) { + info.constraints.push(label); + if (subareaInfo.constraints) { + console.warn( + "adding subconstraints:", + subareaInfo.constraints, + "to area:", + area, + "because no subarea was found" + ); + } + return; + } + info.subareas[subarea] = subareaInfo; }); sections.set(area, info); }); From 656f9ccc771c24be996a2a9226675ebac80315ff Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 6 Jun 2023 09:51:01 -0700 Subject: [PATCH 40/62] scrape uscp courses --- kanban-dashboard/src/scraping/catalog.ts | 92 +++++++++++++++++++----- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 60335e7..c7dc6eb 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -1,5 +1,6 @@ import { PrismaClient, Requirement } from "@prisma/client"; import assert from "assert"; +import { constants } from "buffer"; import * as cheerio from "cheerio/lib/slim"; import { z } from "zod"; @@ -85,7 +86,6 @@ export type RequirementType = z.infer; const stripCrosslistInfoFromCourseCode = (courseCode: string) => { const match = courseCode.match(/([A-Z]+)(?:\/[A-Z]+)*\s+(\d+)(?:\s+\d+)*/); - console.log(match); if (!match) throw new Error( `course code: ${courseCode} did not match the course code regex` @@ -593,7 +593,7 @@ export const scrapeSubjects = async () => { return subjects; }; -const GEAreasEnum = z.enum(["A", "B", "C", "D", "E", "F", "ELECTIVES"]); +const GEAreasEnum = z.enum(["A", "B", "C", "D", "E", "F", "ELECTIVES", "USCP"]); const GESubAreaSchema = z .object({ @@ -611,6 +611,7 @@ const GEAreaSchema = z name: z.string().default(""), constraints: z.array(z.string()).default([]), subareas: z.record(GESubAreaVariant, GESubAreaSchema).default({}), + fullfilledBy: z.array(CourseCodeSchema).default([]), }) .default({}); @@ -619,7 +620,7 @@ type GEArea = z.infer; export const GEDataSchema = z.map(GEAreasEnum, GEAreaSchema); type GEData = z.infer; -/** Returns courses that fulfill ge requirements and which requirements they fulfill */ +/** Returns courses that fulfill ge requirements for each area */ export const scrapeCourseGEFullfillments = async () => { const url = "https://catalog.calpoly.edu/generalrequirementsbachelorsdegree/#GE-Requirements"; @@ -644,7 +645,7 @@ export const scrapeCourseGEFullfillments = async () => { .first() .text() .trim(); - let area : z.infer; + let area: z.infer; if (areaLabel.includes("GE ELECTIVES")) { info.name = areaLabel; area = "ELECTIVES"; @@ -678,7 +679,7 @@ export const scrapeCourseGEFullfillments = async () => { )) ) { let subconstraint = match[1] ?? match[2]; - subareaInfo.constraints.push(subconstraint); + if (match[1]) subareaInfo.constraints.push(subconstraint); label = label.replace(match[0], "").replace("()", "").trim(); // still push the label at the end match = undefined; @@ -696,18 +697,18 @@ export const scrapeCourseGEFullfillments = async () => { /((?:Upper|Lower)-Division) [A-F]( Elective)?s?/ )) ) { - let [matched, _subarea, elective] = match; + let [matched, _subarea, elective] = match; _subarea += elective ?? ""; - subarea = _subarea + subarea = _subarea; label = label.replace(matched, "").trim(); subareaInfo.description = label ?? null; } if ((match = label.match(/(Area [A-F] Elective)/))) { - subarea = "Elective" + subarea = "Elective"; } if (!subarea) { info.constraints.push(label); - if (subareaInfo.constraints) { + if (subareaInfo.constraints.length > 0) { console.warn( "adding subconstraints:", subareaInfo.constraints, @@ -722,28 +723,81 @@ export const scrapeCourseGEFullfillments = async () => { }); sections.set(area, info); }); - const courseTables = $("table.sc_courselist"); + const courseTables = $("table.sc_courselist:not(div#uscptextcontainer *)"); + courseTables.each((_i, table) => { const headerElement = $(table) .prev("table.sc_sctable") .find("tbody") - .find("tr") + .find("tr.lastrow") .find("td.column0") .get(); - // FIXME: error here - if (!headerElement) return; + const headerInfo = headerElement.map((e) => $(e).text().trim()); - const [title, ...meta] = headerInfo; + let [title, ...meta] = headerInfo; + const commentHeader = $(table) + .find("tr.firstrow span.courselistcomment.areaheader") + .first() + .text() + .trim(); + if (commentHeader && commentHeader !== "") title = commentHeader; + console.log("title:", title); + // title = commentHeader; // TODO: updating title when "td>div.courselistcomment" is encountered // TODO: parsing "ge" from title - const courses = $(table) - .find("td.codecol") - .map((_i, codeCol) => $(codeCol).text().trim()) - .get(); - const ge = { ge: title, meta, courses }; + + const courses = z.array(CourseCodeSchema).parse( + $(table) + .find("td.codecol") + .map((_i, codeCol) => $(codeCol).text().trim()) + .get() + ); + if (!title) { + console.error("found courses for table with no title", { courses }); + return; + } + let match; + if (title.includes("GE ELECTIVES")) { + sections.get("ELECTIVES")!.fullfilledBy = courses; + } else if ((match = title.match(/((?:Upper|Lower)-Division) ([A-F])/))) { + const [_, division, area] = match; + const subarea = sections.get(area)!.subareas[division]; + if (!subarea) { + console.warn( + "creating new found subarea:", + division, + "for", + area, + "because it was found in the course list" + ); + sections.get(area)!.subareas[division] = GESubAreaSchema.parse({ + fulfilledBy: courses, + }); + } else subarea.fullfilledBy = courses; + } else if ((match = title.match(/(([A-F])[1-4])/))) { + const [_, subarea, area] = match; + sections.get(area)!.subareas[subarea].fullfilledBy = courses; + if (subarea === "B2" || subarea === "B1") { + const b3courses = $(table) + .find('td:contains("& B3")') + .map((_i, b3desc) => $(b3desc).prev().text().trim()) + .get(); + const b3 = sections.get(area)!.subareas.B3 + b3.fullfilledBy = b3.fullfilledBy ?? []; + b3.fullfilledBy.push(...b3courses); + } + } + // FIXME: (B2 & B3) // sections.set(ge.ge, ge); }); + const uscpCourses = $("div#uscptextcontainer table.sc_courselist") + .first() + .find("td.codecol") + .map((_i, codeCol) => $(codeCol).text().trim()) + .get(); + sections.set("USCP", GEAreaSchema.parse({ fullfilledBy: uscpCourses })); + // return Array.from(sections.values()); return sections; }; From 87fea6f660052818acbe4edbb6cdace323de4531 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 6 Jun 2023 11:35:47 -0700 Subject: [PATCH 41/62] fetch-retry --- kanban-dashboard/package.json | 1 + kanban-dashboard/src/scraping/catalog.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/kanban-dashboard/package.json b/kanban-dashboard/package.json index f921f6d..1dfd3c7 100644 --- a/kanban-dashboard/package.json +++ b/kanban-dashboard/package.json @@ -25,6 +25,7 @@ "@types/react-beautiful-dnd": "^13.1.4", "cheerio": "1.0.0-rc.12", "eslint-config-next": "^13.4.2", + "fetch-retry": "^5.0.6", "moment": "^2.29.4", "next": "^13.4.2", "normalized-reducer": "^0.5.1", diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index c7dc6eb..b8788df 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -2,6 +2,8 @@ import { PrismaClient, Requirement } from "@prisma/client"; import assert from "assert"; import { constants } from "buffer"; import * as cheerio from "cheerio/lib/slim"; +import fetchRetry from "fetch-retry"; +const fetch = fetchRetry(global.fetch) import { z } from "zod"; const DOMAIN = "https://catalog.calpoly.edu"; From fcba14032c9656b9d93eb02a1cd92818fec36030 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 6 Jun 2023 11:36:00 -0700 Subject: [PATCH 42/62] scrape concentrations --- kanban-dashboard/src/scraping/catalog.ts | 101 ++++++++++++++++------- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index b8788df..cfbc111 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -127,7 +127,7 @@ export const RequirementGroupSchema: z.ZodType = z.lazy(() => // }); export const RequirementCourseSchema = z.object({ - kind: RequirementTypeSchema.or(z.string()), + kind: RequirementTypeSchema.or(z.string()).nullable(), code: CourseCodeSchema, units: z.number(), title: z.string(), @@ -148,13 +148,29 @@ export type Degree = z.infer; const GEAreaCodeRE = /[ABCDEF][1234]/; const GEDivisionCodeRE = /(Upper|Lower)-Division [ABCDEF]( Elective)?/; const GeAreaRE = /Area [ABCDEF]( Elective)?/; -const GESubAreaVariant = z.union([ + +const GEDivisionSubAreaRE = /(Upper|Lower)-Division( Elective)?/; +const GESubAreaVariantSchema = z.union([ z.string().regex(GEAreaCodeRE), z.string().regex(GEDivisionCodeRE), - z.string().regex(GeAreaRE), + z.literal("Elective"), +]); + +const GEAreasEnumSchema = z.enum([ + "A", + "B", + "C", + "D", + "E", + "F", + "ELECTIVES", + "USCP", ]); +type GEArea = z.infer; const GeRequirementSchema = z.object({ + area: GEAreasEnumSchema, + subarea: GESubAreaVariantSchema, code: z .string() .regex(GEAreaCodeRE) @@ -179,7 +195,7 @@ export type DegreeRequirements = z.infer; const parseMajorCourseRequirementsTable = ( $: cheerio.CheerioAPI, table: cheerio.Element, - degree: Degree + ctx: { name: string; link: string } ) => { // select from the following // If we're in a sftf block the courses are in one of the following formats: @@ -248,7 +264,6 @@ const parseMajorCourseRequirementsTable = ( } if (!curRequirementKind) { console.error("no text in header:", $(tr)); - break; } } else if ($(tr).find("span.courselistcomment").length > 0) { const comment = $(tr).find("span.courselistcomment").text().trim(); @@ -261,9 +276,9 @@ const parseMajorCourseRequirementsTable = ( console.warn( "Found an \"or\" row outside of 'Select from the following' block. There's even more variations :/", "in", - degree.name, + ctx.name, "(", - degree.link, + ctx.link, ")", comment ); @@ -307,7 +322,7 @@ const parseMajorCourseRequirementsTable = ( "found different length code,title lists in and block:", { course_titles, course_codes }, "in", - degree.name + ctx.name ); } else if (course_titles.length === 0) { console.warn("didnt find any titles for course list:", course_codes); @@ -337,6 +352,8 @@ const parseMajorCourseRequirementsTable = ( const last = groups.length - 1; if (in_sftf) { + if (!groups[last].or) + throw Error("expected or when trying to add course in sftf block"); const last_or = groups[last].or; if (last_or.length === 0) { last_or.push(course); @@ -453,6 +470,7 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { + return const { courses, groups } = parseMajorCourseRequirementsTable( $, table, @@ -461,12 +479,33 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { requirements.courses = courses; requirements.groups = groups; } else if (title === "General Education (GE) Requirements") { + return requirements.ge = parseGeCourseRequirementsTable($, table); } else { + return console.warn("Unrecognized table with title:", title); } }); + const concentrationsList = $("h2:contains(Concentration)+ul>li a") + .get() + .map((elem) => ({ name: $(elem).text(), link: "https://catalog.calpoly.edu" + $(elem).attr("href") })); + const concentrations = await Promise.all( + concentrationsList.map(async (conc) => { + if (!conc.link) throw new Error(`Concentration ${conc.name} has no link`); + const $ = await fetch(conc.link) + .then((res) => res.text()) + .then(cheerio.load); + const tables = $("table.sc_courselist") + .get() + console.log("found", tables.length, "tables for concentration") + conc.courses = tables + .map((table) => parseMajorCourseRequirementsTable($, table, conc)); + return conc; + }) + ); + requirements.concentrations = concentrations; + // FIXME: using unit counts to determine how many classes of sftf/or groups are required // TODO: check for correctness by counting the units and comparing to the degree's unit count // could keep total units count in groups and check against stated unit totals @@ -595,9 +634,7 @@ export const scrapeSubjects = async () => { return subjects; }; -const GEAreasEnum = z.enum(["A", "B", "C", "D", "E", "F", "ELECTIVES", "USCP"]); - -const GESubAreaSchema = z +const GESubAreaDataSchema = z .object({ constraints: z.array(z.string()).default([]), name: z.string().nullable().default(null), @@ -606,20 +643,20 @@ const GESubAreaSchema = z }) .default({}); -type GESubArea = z.infer; +type GESubAreaData = z.infer; -const GEAreaSchema = z +const GEAreaDataSchema = z .object({ name: z.string().default(""), constraints: z.array(z.string()).default([]), - subareas: z.record(GESubAreaVariant, GESubAreaSchema).default({}), + subareas: z.record(GESubAreaVariantSchema, GESubAreaDataSchema).default({}), fullfilledBy: z.array(CourseCodeSchema).default([]), }) .default({}); -type GEArea = z.infer; +type GEAreaData = z.infer; -export const GEDataSchema = z.map(GEAreasEnum, GEAreaSchema); +export const GEDataSchema = z.map(GEAreasEnumSchema, GEAreaDataSchema); type GEData = z.infer; /** Returns courses that fulfill ge requirements for each area */ @@ -639,7 +676,7 @@ export const scrapeCourseGEFullfillments = async () => { $(table).prev(":not(.sc_courselist)").length > 0 ); areaTables.each((_i, table) => { - const info: GEArea = GEAreaSchema.parse({}); + const info: GEAreaData = GEAreaDataSchema.parse({}); const tbody = $(table).find("tbody"); let areaLabel = $(tbody) .find("tr.firstrow") @@ -647,7 +684,7 @@ export const scrapeCourseGEFullfillments = async () => { .first() .text() .trim(); - let area: z.infer; + let area: GEArea; if (areaLabel.includes("GE ELECTIVES")) { info.name = areaLabel; area = "ELECTIVES"; @@ -658,7 +695,7 @@ export const scrapeCourseGEFullfillments = async () => { throw new Error( "unrecognized ge area label for section: ".concat(areaLabel) ); - area = GEAreasEnum.parse(match[1]); + area = GEAreasEnumSchema.parse(match[1]); areaLabel = areaLabel.replace(match[0], "").trim(); info.name = areaLabel; } @@ -674,7 +711,7 @@ export const scrapeCourseGEFullfillments = async () => { .forEach((label) => { let match; let subarea; - let subareaInfo: GESubArea = GESubAreaSchema.parse({}); + let subareaInfo: GESubAreaData = GESubAreaDataSchema.parse({}); if ( (match = label.match( /(?:-?(Writing Intensive))|(?:\s-\s((?:[\w \d,;-]|\(Standard\))+))/ @@ -763,7 +800,9 @@ export const scrapeCourseGEFullfillments = async () => { sections.get("ELECTIVES")!.fullfilledBy = courses; } else if ((match = title.match(/((?:Upper|Lower)-Division) ([A-F])/))) { const [_, division, area] = match; - const subarea = sections.get(area)!.subareas[division]; + const subarea = sections.get(GEAreasEnumSchema.parse(area))!.subareas[ + division + ]; if (!subarea) { console.warn( "creating new found subarea:", @@ -772,19 +811,22 @@ export const scrapeCourseGEFullfillments = async () => { area, "because it was found in the course list" ); - sections.get(area)!.subareas[division] = GESubAreaSchema.parse({ - fulfilledBy: courses, - }); + sections.get(GEAreasEnumSchema.parse(area))!.subareas[division] = + GESubAreaDataSchema.parse({ + fulfilledBy: courses, + }); } else subarea.fullfilledBy = courses; } else if ((match = title.match(/(([A-F])[1-4])/))) { const [_, subarea, area] = match; - sections.get(area)!.subareas[subarea].fullfilledBy = courses; - if (subarea === "B2" || subarea === "B1") { + sections.get(GEAreasEnumSchema.parse(area))!.subareas[ + subarea + ].fullfilledBy = courses; + if (subarea === "B2" || subarea === "B1") { const b3courses = $(table) .find('td:contains("& B3")') .map((_i, b3desc) => $(b3desc).prev().text().trim()) .get(); - const b3 = sections.get(area)!.subareas.B3 + const b3 = sections.get(GEAreasEnumSchema.parse(area))!.subareas.B3; b3.fullfilledBy = b3.fullfilledBy ?? []; b3.fullfilledBy.push(...b3courses); } @@ -798,7 +840,10 @@ export const scrapeCourseGEFullfillments = async () => { .find("td.codecol") .map((_i, codeCol) => $(codeCol).text().trim()) .get(); - sections.set("USCP", GEAreaSchema.parse({ fullfilledBy: uscpCourses })); + sections.set("USCP", GEAreaDataSchema.parse({ fullfilledBy: uscpCourses })); + // FIXME: GWR courses + // FIXME: extract parsing of these tables into separate functtions + // to allow all ge's, uscp, gwr, and subjects from https://catalog.calpoly.edu/coursesaz // return Array.from(sections.values()); return sections; From 54c98283a1ed4f3cce78fb5f93e875f72271f854 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 7 Jun 2023 14:10:02 -0700 Subject: [PATCH 43/62] update prisma schema for new requirements --- kanban-dashboard/prisma/schema.prisma | 200 ++++++++++++++++++++++---- 1 file changed, 174 insertions(+), 26 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index 6a9d4c1..f7581ac 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -16,12 +16,6 @@ datasource db { relationMode = "prisma" } -model Department { - id String @id - name String @unique - Degree Degree[] -} - model Course { code String @id subjectCode String @@ -37,7 +31,13 @@ model Course { // TODO: make this a bitmask termsTypicallyOffered String - fulfillsRequirements CourseRequirement[] + fulfillsMajorRequirements CourseRequirement[] + fullfillsGERequirements GEAreaFullfillmentCourse[] + fullfillsElectiveRequirements ElectiveRequirement[] + USCP Boolean @default(false) + GWR Boolean @default(false) + + @@index([code, USCP, GWR]) } model Subject { @@ -46,34 +46,182 @@ model Subject { courses Course[] } +model RecommendedCompletion { + id Int @id @default(autoincrement()) + year Int + term Term + CourseRequirement CourseRequirement[] + ElectiveRequirement ElectiveRequirement[] + GERequirement GERequirement[] + + @@unique([year, term]) + @@index([id, year, term]) +} + +enum Term { + F + W + SP + SU +} + +enum GEArea { + A + B + C + D + E + F +} + +enum GESubArea { + LowerDivision + UpperDivision + F + E + ELECTIVE + A1 + A2 + A3 + A4 + B1 + B2 + B3 + B4 + C1 + C2 + C3 + C4 + D1 + D2 + D3 + D4 +} + +model GERequirement { + area GEArea + subArea GESubArea + degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) + degreeId Int + units Int + recommendedCompletion RecommendedCompletion? @relation(fields: [recommendedCompletionYear, recommendedCompletionTerm], references: [year, term]) + recommendedCompletionTerm Term? + recommendedCompletionYear Int? + degreeRequirementsId Int + // TODO: connect to course requirement + + @@id([area, subArea, degreeId]) +} + +enum RequirementCourseKind { + major + support +} + model CourseRequirement { - // TODO: figure out how to make unique ids based on the CourseRequirement - course Course @relation(fields: [courseCode], references: [code]) - degree Degree @relation(fields: [degreeId], references: [id]) - // Ge, major, tech elective, etc. - // TODO: make this an enum - kind String? - // 0,1,2,3 - recommendedYear Int? - recommendedTermCode Int? + course Course @relation(fields: [courseCode], references: [code]) + courseCode String + kind RequirementCourseKind + degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) + degreeId Int + recommendedCompletion RecommendedCompletion? @relation(fields: [recommendedCompletionYear, recommendedCompletionTerm], references: [year, term]) + recommendedCompletionTerm Term? + recommendedCompletionYear Int? + RequirementGroup RequirementGroup? @relation(fields: [requirementGroupId], references: [id]) + requirementGroupId Int? + degreeRequirementsId Int - courseCode String - degreeId String + @@id([degreeId, courseCode]) +} - @@id([courseCode, degreeId]) +model ElectiveRequirement { + id Int @id @default(autoincrement()) + courses Course[] + recommendedCompletions RecommendedCompletion[] + kind String + degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) + degreeId Int + unitsOf Int + degreeRequirementsId Int + + @@unique([kind, degreeId]) +} + +// i.e. series A or series B +model NestedRequirementGroup { + parent RequirementGroup @relation("parent", fields: [parentId], references: [id]) + parentId Int + child RequirementGroup @relation("child", fields: [childId], references: [id]) + childId Int + + @@id([childId, parentId]) + @@index([childId, parentId]) +} + +enum RequirementGroupKind { + or + and +} + +// represents a series (such as PHYS 1,2,3) or a list of choices (such as an elective) +model RequirementGroup { + id Int @id @default(autoincrement()) + kind RequirementGroupKind + courses CourseRequirement[] + // child and parent are swapped in the relation name because it is referring to the reference to itself + // i.e. the reference to this groups parent views this group as the child + parentGroups NestedRequirementGroup[] @relation("child") + childGroups NestedRequirementGroup[] @relation("parent") + // should be total units for and group or total required for or group + unitsOf Int? + DegreeRequirements DegreeRequirements? @relation(fields: [degreeRequirementsId], references: [id]) + degreeRequirementsId Int? + + @@index([id]) +} + +model DegreeRequirements { + id Int @id @default(autoincrement()) + electives ElectiveRequirement[] + majorAndSupport CourseRequirement[] + ge GERequirement[] + groups RequirementGroup[] + Concentration Concentration[] + Degree Degree[] +} + +model Concentration { + id Int @id @default(autoincrement()) + name String + requirements DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) + degreeRequirementsId Int + degree Degree @relation(fields: [degreeId], references: [id]) + degreeId String + + @@unique([degreeId, name]) } model Degree { - id String @id - name String - link String + id String @id + name String + link String // TODO: make this an enum of BS, BA, etc. - kind String - courseRequirements CourseRequirement[] - Department Department? @relation(fields: [departmentId], references: [id]) - departmentId String? + kind String + requirements DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) + degreeRequirementsId Int + concentrations Concentration[] @@unique([name, kind]) + @@index([id]) +} + +model GEAreaFullfillmentCourse { + area GEArea + subArea GESubArea + courseId String + course Course @relation(fields: [courseId], references: [code]) + + @@id([area, subArea, courseId]) } model User { From f927d6c8839072e198516e36a1674ef91ac8a9b9 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 7 Jun 2023 14:10:13 -0700 Subject: [PATCH 44/62] rewrite course requirement scraping logic --- kanban-dashboard/src/scraping/catalog.ts | 492 +++++++++++++---------- 1 file changed, 277 insertions(+), 215 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index cfbc111..8b39db9 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -3,7 +3,7 @@ import assert from "assert"; import { constants } from "buffer"; import * as cheerio from "cheerio/lib/slim"; import fetchRetry from "fetch-retry"; -const fetch = fetchRetry(global.fetch) +const fetch = fetchRetry(global.fetch); import { z } from "zod"; const DOMAIN = "https://catalog.calpoly.edu"; @@ -188,223 +188,287 @@ export const DegreeRequirementsSchema = z.object({ groups: z.array(RequirementGroupSchema), courses: z.map(z.string(), RequirementCourseSchema), ge: z.array(GeRequirementSchema), + electives: z.map(z.string()), }); export type DegreeRequirements = z.infer; -const parseMajorCourseRequirementsTable = ( +type CourseRequirement = + | { kind: "or"; courses: CourseRequirement[]; units: number } + | { kind: "and"; courses: CourseRequirement[]; units: number } + | { kind: "course"; course: CourseCode; units: number }; + +const CourseRequirementSchema: z.ZodType = z.lazy(() => + z.discriminatedUnion("kind", [ + z.object({ + kind: z.literal("or"), + courses: z.array(CourseRequirementSchema), + units: z.number(), + }), + z.object({ + kind: z.literal("and"), + courses: z.array(CourseRequirementSchema), + units: z.number(), + }), + z.object({ + kind: z.literal("course"), + course: CourseCodeSchema, + units: z.number(), + }), + ]) +); + +const parseDegreeRequirementSectionHeader = ( + sectionTitle: string +): + | { kind: RequirementType | null } + | { kind: "elective"; electiveKind: string } => { + let kind: RequirementType | null = null; + let electiveKind; + if (sectionTitle.includes("MAJOR COURSES")) { + kind = "major"; + } else if (!!sectionTitle.match(/^[\w\/\s]+ electives?$/i)) { + // FIXME: include the type of elective + kind = "elective"; + electiveKind = sectionTitle.replace(/electives?/i, "").trim(); + } else if (sectionTitle.includes("GENERAL EDUCATION")) { + kind = "ge"; + } else if (sectionTitle.includes("SUPPORT COURSES")) { + kind = "support"; + } + if (electiveKind) { + if (kind !== "elective") + throw new Error("found elective without elective kind: " + sectionTitle); + return { kind, electiveKind }; + } + return { kind }; +}; + +// select from the following blocks: +// If we're in a sftf block the courses are in one of the following formats: +// a) +// [course] +// or [course] +// or [course] +// ... until row not starting with "or" +// +// b) +// [course] +// or +// [course] +// or +// ... until there are two [course] rows not separated by "or" row +// +// c) +// [course] +// [course] +// [course] +// ... until another sftf block or areaheader block (because y tf not) +// +// To differentiate these cases the in_sftf flag signifies if we're in a +// stft block and the sftf_sep is either "or" (for cases a or b) or null (for case c) +// +// Note that or conditions can occur OUTSIDE of a sftf block in which +// case we get our FOURTH and (hopefullly) final option: +// d) +// [course] +// or [course] +/// mapping of course code to meta information about the course (such as whether it is a support/major/etc) + +export const parseCourseRequirementsTable = ( $: cheerio.CheerioAPI, table: cheerio.Element, - ctx: { name: string; link: string } + ctx: { kind: "degree" | "concentration"; name: string; link: string } ) => { - // select from the following - // If we're in a sftf block the courses are in one of the following formats: - // a) - // [course] - // or [course] - // or [course] - // ... until row not starting with "or" - // - // b) - // [course] - // or - // [course] - // or - // ... until there are two [course] rows not separated by "or" row - // - // c) - // [course] - // [course] - // [course] - // ... until another sftf block or areaheader block (because y tf not) - // - // To differentiate these cases the in_sftf flag signifies if we're in a - // stft block and the sftf_sep is either "or" (for cases a or b) or null (for case c) - // - // Note that or conditions can occur OUTSIDE of a sftf block in which - // case we get our FOURTH and (hopefullly) final option: - // d) - // [course] - // or [course] - /// mapping of course code to meta information about the course (such as whether it is a support/major/etc) const courses = new Map(); - // TODO: - const groups: RequirementGroup[] = []; - const SFTF_RE = /\s*Select( one sequence)? from the following.*/; + const parsedClass = "parsed"; + + const parseRowUnits = (row: cheerio.Element) => { + // TODO: error checking + let unitsStr = $(row).find("td.hourscol").text(); + let units = unitsStr == "" ? 0 : parseInt(unitsStr); + return units; + }; + const markRowAsParsed = ( + rowOrIndex: number | cheerio.Element, + row?: cheerio.Element + ) => { + if (typeof rowOrIndex !== "number") { + row = rowOrIndex; + } + if (!row) throw new Error("trying to mark undefined row as parsed"); + $(row).addClass(parsedClass); + }; + const parseCourseRow = (row: cheerio.Element): CourseRequirement => { + let codeCol = $(row).find("td.codecol"); + if (codeCol.length !== 1) { + throw new Error( + `tried to parse row: ${$(row).text()} without codecol ${ctx.link}` + ); + } - let curRequirementKind: string | null = null; - // within a select from the following block - // see comment at top of file which explains these flags - let in_sftf = false; - let sftf_sep = null; - let prev_was_or = false; - const rows = $(table).find("tr"); - for (let i = 0; i < rows.length; i++) { - const tr = rows[i]; - // TODO: extracting 1 footnote tags - - if ($(tr).hasClass("areaheader")) { - in_sftf = false; - prev_was_or = false; - sftf_sep = null; - // new section - const sectionTitle = $(tr).text().trim(); - if (sectionTitle.includes("MAJOR COURSES")) { - curRequirementKind = "major"; - } else if (sectionTitle.includes("Electives")) { - // FIXME: include the type of elective - curRequirementKind = "elective"; - } else if (sectionTitle.includes("GENERAL EDUCATION")) { - curRequirementKind = "ge"; - } else if (sectionTitle.includes("SUPPORT COURSES")) { - curRequirementKind = "support"; - } else { - curRequirementKind = sectionTitle as RequirementType; - console.log("Unrecognized section kind:", sectionTitle); - } - if (!curRequirementKind) { - console.error("no text in header:", $(tr)); - } - } else if ($(tr).find("span.courselistcomment").length > 0) { - const comment = $(tr).find("span.courselistcomment").text().trim(); - if (comment.match(SFTF_RE)) { - in_sftf = true; - groups.push({ or: [] }); - sftf_sep = null; - } else if (comment === "or") { - if (!in_sftf) { - console.warn( - "Found an \"or\" row outside of 'Select from the following' block. There's even more variations :/", - "in", - ctx.name, - "(", - ctx.link, - ")", - comment - ); - break; - } - sftf_sep = "or"; - prev_was_or = true; - } else if (!comment.match(/\(?[Ss](ee|elect).*below.?\)?$/)) { - console.error("unrecognized comment:", comment); - } + let units = parseRowUnits(row); + + markRowAsParsed(row); + + let code = $(codeCol).find("a.code"); + let course; + // TODO: check for orclass + if (code.length > 1 && $(row).is(":has(span:contains(&))")) { + // and group + // TODO: check to make sure its an and row + let courses = $(code) + .map((_, c) => ({ kind: "course", course: $(c).text(), units: 0 })) + .get(); + course = { kind: "and", courses, units }; + } else if (codeCol.hasClass("orclass")) { + course = { + kind: "or", + courses: [{ kind: "course", course: $(code).text(), units: 0 }], + units, + }; } else { - const course_elem = $(tr).find("td.codecol a[title]"); - let course: any; // TODO: type this - const isAndGroup = course_elem.length > 1; - if (isAndGroup) { - // course is actually courses plural - // make sure it's actually an '&' of the courses - if (!$(tr).find("span.blockindent").text().includes("&")) { - console.error( - "multiple elements found but no & to be found in:", - $(tr) - ); - } - const course_codes: string[] = []; - $(course_elem).each((_i, c) => { - course_codes.push($(c).text().trim()); - }); - const course_titles: string[] = []; - const titles = $(tr).find("td:not([class])"); - $(titles) - .contents() - .each((i: number, t) => { - if (t.type === "text" && i === 0) { - course_titles.push($(t).text().trim()); - } else if (t.type === "tag" && t.name === "span") { - course_titles.push($(t).text().trim().replace(/^and /, "")); - } - }); - if (course_codes.length !== course_titles.length) { - console.warn( - "found different length code,title lists in and block:", - { course_titles, course_codes }, - "in", - ctx.name - ); - } else if (course_titles.length === 0) { - console.warn("didnt find any titles for course list:", course_codes); - } else { - course_codes.map((code, i) => { - courses.set(code, { - kind: curRequirementKind, - code, - title: course_titles[i], - units: 0, // TODO: total units - }); - }); - } - - course = { and: course_codes }; - } else if (course_elem.length !== 1) { - if ($(tr).hasClass("listsum")) { - continue; - } - // TODO: handle sections with references to other information on page - console.log("no title for:", $(tr).find("td.codecol").text().trim()); + course = { kind: "course", course: $(code).text(), units }; + } + return CourseRequirementSchema.parse(course); + }; + + // some of the concentrations have no top level header for the course list + // if that is the case we add one add one with the label Tech Electives + if ( + ctx.kind === "concentration" && + $(table).is( + ":has(tr.firstrow:has(td.codecol,span.courselistcomment:not(.areaheader)))" + ) + ) { + $('Technical Electives').insertBefore( + "tr.firstrow" + ); + } + // TODO: consider just reparsing the page when a non-header header is found instead of checking each comment for each page + // TODO: consider making sections not be the result of mapping but of pushing found sections to list and create way to modify the lists of + // headers/sftf comments then use if statements instead of the following replacements + let comments = $(table) + .find("tr:has(span.courselistcomment)") + .each((_, c) => { + const txt = $(c).text(); + let match; + // sometimes things that should be headers but are comments instead :/ + // see Mathematics/Statistics Elective on the csc game-development concentration page + if (parseDegreeRequirementSectionHeader(txt).kind !== null) { + console.log("making comment:", $(c).text(), "a header"); + $(c).addClass("areaheader"); + return; } - if (!isAndGroup && course_elem.length === 1) { - course = course_elem.text().trim(); + const approvedBelowRE = + /up to (\d+) units may be taken from the approved ([\w\s]+) listed below/i; + if (!!(match = txt.match(approvedBelowRE))) { + const [_, units, sectionTitle] = match; + $(c).replaceWith(`${sectionTitle} + + Select from the following + ${units} + `); } - const has_orclass = $(tr).hasClass("orclass"); - const last = groups.length - 1; - - if (in_sftf) { - if (!groups[last].or) - throw Error("expected or when trying to add course in sftf block"); - const last_or = groups[last].or; - if (last_or.length === 0) { - last_or.push(course); - } else if (last_or.length >= 1) { - if (last_or.length === 1 && has_orclass) { - sftf_sep = "or"; - } - if (has_orclass || prev_was_or || sftf_sep == null) { - groups[last].or.push(course); + }); + + const sectionHeaders = $(table).find("tr.areaheader"); + const SFTF_RE = /\s*Select( one sequence)? from the following.*/; + // TODO: check if table begins with course row (in concentrations) and figure out how to handle that + const sections = $(sectionHeaders) + .get() + .map((headerElem) => { + $(headerElem).addClass(parsedClass); + const sectionRows = $(headerElem).nextUntil("tr.areaheader,tr.listsum"); + const sftfBlocks: CourseRequirement[] = $(sectionRows) + .filter("tr:has(span.courselistcomment)") + .filter( + (_i, e) => !!$(e).find("span.courselistcomment").text().match(SFTF_RE) + ) + .get() + .map((sftf) => { + // see select from the following blocks comment above + let orRow = $(sftf).next().next(); + let courses; + if ($(orRow).is(":has(td.orclass)")) { + console.log("orclass"); + courses = $(orRow) + .nextUntil(":not(:has(td.orclass))") + .add(orRow) + .add($(orRow).prev()); + } else if ($(orRow).is(":has(span.courselistcomment:contains(or))")) { + console.log("dedicated or row"); + courses = $(orRow).prev().add($(orRow).next()); + orRow.addClass(parsedClass); + if ($(orRow).next().next().text() === "or") { + console.warn( + "found more than two courses in or list separated by dedicated or rows...skipping" + ); + } } else { - in_sftf = false; - sftf_sep = null; + console.log($(orRow).text()); + courses = $(sftf).nextUntil( + "tr.areaheader,tr:has(span.courselistcomment:contains(Select)),tr.listsum" + ); } + // TODO: remove this filterSelector and parse comments + courses = courses.filter(":has(tr.codecol)").get().map(parseCourseRow); + $(sftf).addClass(parsedClass); + return { kind: "or", courses, units: parseRowUnits(sftf) }; + }); + const remainingRows = $(sectionRows).not(`tr.${parsedClass}`); + let remainingCourses: CourseRequirement[] = []; + remainingRows.each((_, row) => { + if ($(row).is(":has(span.courselistcomment)")) { + // TODO: parsing comments (especially unit counts) + console.log("comment:", $(row).text()); + return; } - prev_was_or = false; - } else if (has_orclass) { - // TODO: assert data.cur.last is not or already - // (multiple or's chained togehter outside of sftf) - if (groups[last].or) { - groups[last].or.push(course); - } else { - groups[last] = { - or: [groups[last], course], - }; + let course = parseCourseRow(row); + if (course.kind === "or") { + let prevCourse = remainingCourses.pop(); + if (!prevCourse) { + console.error( + "found or row:", + $(row).text(), + "with no preceeding row" + ); + return; + } + switch (prevCourse.kind) { + case "or": + prevCourse.courses.push(...course.courses); + course = prevCourse; + break; + case "course": + case "and": + course.units = prevCourse.units; + prevCourse.units = 0; + course.courses.push(prevCourse); + break; + } } - } else if (!in_sftf) { - // Normal row - groups.push(course); - } - if (!course.and) { - const title = $(tr).find("td:not([class])").text().trim(); - // TODO: more accurate units when in or/and block - const unitsStr = $(tr).find("td.hourscol").text().trim() || 0; - const units = parseInt(unitsStr); - const code = course; - const courseObj = RequirementCourseSchema.parse({ - kind: curRequirementKind, - title, - units, - code, - }); - courses.set(code, courseObj); + remainingCourses.push(course); + }); + const section = { + ...parseDegreeRequirementSectionHeader($(headerElem).text()), + courses: sftfBlocks.concat(remainingCourses), + }; + if (!section.kind) { + console.error("failed to parse header:", $(headerElem).text()); } - } + return section; + }); + const unparsedRows = $(table) + .find("tr") + .not("." + parsedClass); + if (unparsedRows.length > 0) { + console.error( + "did not parse:", + unparsedRows.get().map((e) => $(e).text()) + ); } - courses.forEach((code, { kind }) => { - if (["support", "elective"].includes(kind) && !!groups.find(code)) { - console.error("/////", kind, code, "not in or/and group"); - } - }); - return { courses, groups }; + return sections; }; const parseGeCourseRequirementsTable = ( @@ -470,36 +534,34 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { - return - const { courses, groups } = parseMajorCourseRequirementsTable( - $, - table, - degree - ); - requirements.courses = courses; - requirements.groups = groups; + requirements.courses = parseCourseRequirementsTable($, table, degree) } else if (title === "General Education (GE) Requirements") { - return requirements.ge = parseGeCourseRequirementsTable($, table); } else { - return console.warn("Unrecognized table with title:", title); } }); const concentrationsList = $("h2:contains(Concentration)+ul>li a") .get() - .map((elem) => ({ name: $(elem).text(), link: "https://catalog.calpoly.edu" + $(elem).attr("href") })); + .map((elem) => ({ + name: $(elem).text(), + link: "https://catalog.calpoly.edu" + $(elem).attr("href"), + })); const concentrations = await Promise.all( concentrationsList.map(async (conc) => { if (!conc.link) throw new Error(`Concentration ${conc.name} has no link`); const $ = await fetch(conc.link) .then((res) => res.text()) .then(cheerio.load); - const tables = $("table.sc_courselist") - .get() - console.log("found", tables.length, "tables for concentration") + const tables = $("table.sc_courselist").get(); + // FIXME: uncomment this + const ctx: { kind: "concentration"; link: string; name: string } = { + ...conc, + kind: "concentration", + }; conc.courses = tables - .map((table) => parseMajorCourseRequirementsTable($, table, conc)); + .map((table) => parseCourseRequirementsTable($, table, ctx)) + .flat(); return conc; }) ); From 8bc9fe580ab7a134a4568ef9ede8ebe23f7fec21 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Wed, 7 Jun 2023 15:29:39 -0700 Subject: [PATCH 45/62] further improvements to scraping --- kanban-dashboard/src/scraping/catalog.ts | 173 +++++++++++++++-------- 1 file changed, 113 insertions(+), 60 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 8b39db9..d2fa276 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -2,6 +2,7 @@ import { PrismaClient, Requirement } from "@prisma/client"; import assert from "assert"; import { constants } from "buffer"; import * as cheerio from "cheerio/lib/slim"; +import { CheerioAPI } from "cheerio/lib/slim"; import fetchRetry from "fetch-retry"; const fetch = fetchRetry(global.fetch); import { z } from "zod"; @@ -219,15 +220,24 @@ const CourseRequirementSchema: z.ZodType = z.lazy(() => ); const parseDegreeRequirementSectionHeader = ( - sectionTitle: string + $: CheerioAPI, + headerElem: cheerio.Element ): - | { kind: RequirementType | null } - | { kind: "elective"; electiveKind: string } => { + | { kind: null; header: string } + | { kind: RequirementType } + | { kind: "elective"; electiveKind: string } + | { kind: "support"; supportKind?: string } => { let kind: RequirementType | null = null; + let sectionTitle = $(headerElem) + .find("span") + .text() + .replace(/\(.*\)$/, "") + .trim(); let electiveKind; + let supportKind = null; if (sectionTitle.includes("MAJOR COURSES")) { kind = "major"; - } else if (!!sectionTitle.match(/^[\w\/\s]+ electives?$/i)) { + } else if (!!sectionTitle.match(/^[\w\/\s\-]+ electives?$/i)) { // FIXME: include the type of elective kind = "elective"; electiveKind = sectionTitle.replace(/electives?/i, "").trim(); @@ -235,12 +245,23 @@ const parseDegreeRequirementSectionHeader = ( kind = "ge"; } else if (sectionTitle.includes("SUPPORT COURSES")) { kind = "support"; + } else { + kind = "support"; + supportKind = sectionTitle; } if (electiveKind) { if (kind !== "elective") throw new Error("found elective without elective kind: " + sectionTitle); return { kind, electiveKind }; } + if (supportKind) { + if (kind !== "support") + throw new Error("found support without support kind: " + sectionTitle); + return { kind, supportKind }; + } + if (!kind) { + return { kind, header: sectionTitle }; + } return { kind }; }; @@ -332,7 +353,42 @@ export const parseCourseRequirementsTable = ( } return CourseRequirementSchema.parse(course); }; - + const parseListOfCourseRows = (rows: cheerio.Cheerio) => { + let courses: CourseRequirement[] = []; + rows.each((_, row) => { + if ($(row).is(":has(span.courselistcomment)")) { + // TODO: parsing comments (especially unit counts) + console.log("comment:", $(row).text()); + return; + } + let course = parseCourseRow(row); + if (course.kind === "or") { + let prevCourse = courses.pop(); + if (!prevCourse) { + console.error( + "found or row:", + $(row).text(), + "with no preceeding row" + ); + return; + } + switch (prevCourse.kind) { + case "or": + prevCourse.courses.push(...course.courses); + course = prevCourse; + break; + case "course": + case "and": + course.units = prevCourse.units; + prevCourse.units = 0; + course.courses.push(prevCourse); + break; + } + } + courses.push(course); + }); + return courses; + }; // some of the concentrations have no top level header for the course list // if that is the case we add one add one with the label Tech Electives if ( @@ -341,9 +397,13 @@ export const parseCourseRequirementsTable = ( ":has(tr.firstrow:has(td.codecol,span.courselistcomment:not(.areaheader)))" ) ) { - $('Technical Electives').insertBefore( - "tr.firstrow" - ); + let txt = "Technical Electives"; + if ($(table).find("tr.firstrow").is(":has(td.codecol)")) { + txt = "MAJOR COURSES"; + } + $( + `${txt}` + ).insertBefore("tr.firstrow"); } // TODO: consider just reparsing the page when a non-header header is found instead of checking each comment for each page // TODO: consider making sections not be the result of mapping but of pushing found sections to list and create way to modify the lists of @@ -351,14 +411,21 @@ export const parseCourseRequirementsTable = ( let comments = $(table) .find("tr:has(span.courselistcomment)") .each((_, c) => { - const txt = $(c).text(); + const txt = $(c).find("span").text(); let match; // sometimes things that should be headers but are comments instead :/ // see Mathematics/Statistics Elective on the csc game-development concentration page - if (parseDegreeRequirementSectionHeader(txt).kind !== null) { - console.log("making comment:", $(c).text(), "a header"); - $(c).addClass("areaheader"); - return; + if (!$(c).hasClass("areaheader") && !$(c).prev().hasClass("areaheader")) { + let header = parseDegreeRequirementSectionHeader($, c); + if ( + header.kind !== null && + header.kind === "support" && + !header.supportKind + ) { + console.log("making comment:", $(c).text(), "a header"); + $(c).addClass("areaheader"); + return; + } } const approvedBelowRE = /up to (\d+) units may be taken from the approved ([\w\s]+) listed below/i; @@ -406,52 +473,21 @@ export const parseCourseRequirementsTable = ( ); } } else { - console.log($(orRow).text()); courses = $(sftf).nextUntil( "tr.areaheader,tr:has(span.courselistcomment:contains(Select)),tr.listsum" ); } - // TODO: remove this filterSelector and parse comments - courses = courses.filter(":has(tr.codecol)").get().map(parseCourseRow); + // FIXME: remove this filterSelector and parse comments + courses = parseListOfCourseRows(courses.filter(":has(td.codecol)")); $(sftf).addClass(parsedClass); return { kind: "or", courses, units: parseRowUnits(sftf) }; }); const remainingRows = $(sectionRows).not(`tr.${parsedClass}`); - let remainingCourses: CourseRequirement[] = []; - remainingRows.each((_, row) => { - if ($(row).is(":has(span.courselistcomment)")) { - // TODO: parsing comments (especially unit counts) - console.log("comment:", $(row).text()); - return; - } - let course = parseCourseRow(row); - if (course.kind === "or") { - let prevCourse = remainingCourses.pop(); - if (!prevCourse) { - console.error( - "found or row:", - $(row).text(), - "with no preceeding row" - ); - return; - } - switch (prevCourse.kind) { - case "or": - prevCourse.courses.push(...course.courses); - course = prevCourse; - break; - case "course": - case "and": - course.units = prevCourse.units; - prevCourse.units = 0; - course.courses.push(prevCourse); - break; - } - } - remainingCourses.push(course); - }); + let remainingCourses: CourseRequirement[] = + parseListOfCourseRows(remainingRows); + const section = { - ...parseDegreeRequirementSectionHeader($(headerElem).text()), + ...parseDegreeRequirementSectionHeader($, headerElem), courses: sftfBlocks.concat(remainingCourses), }; if (!section.kind) { @@ -489,16 +525,29 @@ const parseGeCourseRequirementsTable = ( return null; } } - let [code] = label.match(GEAreaCodeRE) ?? - label.match(GeAreaRE) ?? - label.match(GEDivisionCodeRE) ?? - label.match(/^[ABCDEF]/) ?? [null]; - if (code === undefined) { + let match; + let area = null; + let subarea = null; + if ((match = label.match(/([ABCDEF])([1234])?/))) { + let matched, num; + [matched, area, num] = match; + subarea = !!num ? matched : area + } else if ((match = label.match(/Area ([ABCDEF])( Elective)/))) { + let _; + [_, area, subarea] = match; + } else if ( + (match = label.match( + /((?:Upper|Lower)-Division) ([A-F])( Elective)?s?/ + )) + ) { + let _, elective; + [_, subarea, area, elective] = match; + subarea += elective ?? ""; + } + if (area === null) { if (label.includes("Select courses from two different areas")) { return null; } else if (label.includes("GE Electives")) { - code = null; - console.log(label); console.assert(isNaN(units), "electives does not have NaN units"); } else { console.error("unrecognized ge:", label); @@ -511,11 +560,11 @@ const parseGeCourseRequirementsTable = ( const b3OneLabWarningStr = "One lab taken with either a B1 or B2 course"; const twoAreasWarning = "Select courses from two different areas"; - if (!rowText.includes(twoAreasWarning) && code !== "B3") { + if (!rowText.includes(twoAreasWarning) && area !== "B3") { console.error("could not determine why units for:", label, "was NaN"); } } - return { code, units }; + return { area, subarea, units }; }) .get() .filter((req) => !!req); @@ -534,7 +583,7 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { const titleElem = $(table).prevUntil("h2").last().prev(); const title = $(titleElem).text().trim(); if (title === "Degree Requirements and Curriculum") { - requirements.courses = parseCourseRequirementsTable($, table, degree) + requirements.courses = parseCourseRequirementsTable($, table, degree); } else if (title === "General Education (GE) Requirements") { requirements.ge = parseGeCourseRequirementsTable($, table); } else { @@ -562,6 +611,10 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { conc.courses = tables .map((table) => parseCourseRequirementsTable($, table, ctx)) .flat(); + const linkSegments = conc.link + .split("/") + .filter((s) => s.length > 0 && !s.startsWith("#")); + conc.id = linkSegments.at(-1); return conc; }) ); From 05bdd31b32f414581cd2a5a2227cd0e9ae0cf1e7 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 09:37:35 -0700 Subject: [PATCH 46/62] further updates to schmea --- kanban-dashboard/prisma/schema.prisma | 135 +++++++++++--------------- 1 file changed, 54 insertions(+), 81 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index f7581ac..d3bf16b 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -31,11 +31,10 @@ model Course { // TODO: make this a bitmask termsTypicallyOffered String - fulfillsMajorRequirements CourseRequirement[] - fullfillsGERequirements GEAreaFullfillmentCourse[] - fullfillsElectiveRequirements ElectiveRequirement[] - USCP Boolean @default(false) - GWR Boolean @default(false) + fullfillsGERequirements GEAreaFullfillmentCourse[] + fullfillsCourseRequirements CourseRequirement[] + USCP Boolean @default(false) + GWR Boolean @default(false) @@index([code, USCP, GWR]) } @@ -46,16 +45,14 @@ model Subject { courses Course[] } +// TODO: make this a type model RecommendedCompletion { - id Int @id @default(autoincrement()) - year Int - term Term - CourseRequirement CourseRequirement[] - ElectiveRequirement ElectiveRequirement[] - GERequirement GERequirement[] + year Int + term Term + GERequirement GERequirement[] + CourseRequirement CourseRequirement[] - @@unique([year, term]) - @@index([id, year, term]) + @@id([year, term]) } enum Term { @@ -72,14 +69,17 @@ enum GEArea { D E F + ELECTIVE } enum GESubArea { LowerDivision UpperDivision + LowerDivisionElective + UpperDivisionElective F E - ELECTIVE + Elective A1 A2 A3 @@ -101,61 +101,34 @@ enum GESubArea { model GERequirement { area GEArea subArea GESubArea - degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) - degreeId Int units Int recommendedCompletion RecommendedCompletion? @relation(fields: [recommendedCompletionYear, recommendedCompletionTerm], references: [year, term]) - recommendedCompletionTerm Term? recommendedCompletionYear Int? - degreeRequirementsId Int + recommendedCompletionTerm Term? + degree Degree @relation(fields: [degreeId], references: [id]) + degreeId String // TODO: connect to course requirement @@id([area, subArea, degreeId]) } -enum RequirementCourseKind { +enum RequirementKind { major support + elective } model CourseRequirement { course Course @relation(fields: [courseCode], references: [code]) courseCode String - kind RequirementCourseKind - degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) - degreeId Int + kind RequirementKind recommendedCompletion RecommendedCompletion? @relation(fields: [recommendedCompletionYear, recommendedCompletionTerm], references: [year, term]) - recommendedCompletionTerm Term? recommendedCompletionYear Int? - RequirementGroup RequirementGroup? @relation(fields: [requirementGroupId], references: [id]) - requirementGroupId Int? - degreeRequirementsId Int - - @@id([degreeId, courseCode]) -} - -model ElectiveRequirement { - id Int @id @default(autoincrement()) - courses Course[] - recommendedCompletions RecommendedCompletion[] - kind String - degree DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) - degreeId Int - unitsOf Int - degreeRequirementsId Int - - @@unique([kind, degreeId]) -} - -// i.e. series A or series B -model NestedRequirementGroup { - parent RequirementGroup @relation("parent", fields: [parentId], references: [id]) - parentId Int - child RequirementGroup @relation("child", fields: [childId], references: [id]) - childId Int + recommendedCompletionTerm Term? + RequirementGroup CourseRequirementGroup @relation(fields: [requirementGroupId], references: [id]) + requirementGroupId Int - @@id([childId, parentId]) - @@index([childId, parentId]) + @@id([courseCode, requirementGroupId]) } enum RequirementGroupKind { @@ -164,52 +137,52 @@ enum RequirementGroupKind { } // represents a series (such as PHYS 1,2,3) or a list of choices (such as an elective) -model RequirementGroup { - id Int @id @default(autoincrement()) - kind RequirementGroupKind - courses CourseRequirement[] +model CourseRequirementGroup { + id Int @id @default(autoincrement()) + groupKind RequirementGroupKind + coursesKind RequirementKind + // e.x. Life Science Support where coursesKind is elective + courseKindInfo String? + courses CourseRequirement[] // child and parent are swapped in the relation name because it is referring to the reference to itself // i.e. the reference to this groups parent views this group as the child - parentGroups NestedRequirementGroup[] @relation("child") - childGroups NestedRequirementGroup[] @relation("parent") + parentGroup CourseRequirementGroup? @relation("toParent", fields: [parentId], references: [id], onDelete: NoAction, onUpdate: NoAction) + parentId Int? + childGroups CourseRequirementGroup[] @relation("toParent") // should be total units for and group or total required for or group - unitsOf Int? - DegreeRequirements DegreeRequirements? @relation(fields: [degreeRequirementsId], references: [id]) - degreeRequirementsId Int? + unitsOf Int? + degree Degree? @relation(fields: [degreeId], references: [id]) + concentration Concentration? @relation(fields: [concentrationId], references: [id]) + degreeId String? + concentrationId Int? @@index([id]) } -model DegreeRequirements { - id Int @id @default(autoincrement()) - electives ElectiveRequirement[] - majorAndSupport CourseRequirement[] - ge GERequirement[] - groups RequirementGroup[] - Concentration Concentration[] - Degree Degree[] +enum RequirementsKind { + degree + concentration } model Concentration { - id Int @id @default(autoincrement()) - name String - requirements DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) - degreeRequirementsId Int - degree Degree @relation(fields: [degreeId], references: [id]) - degreeId String + id Int @id @default(autoincrement()) + name String + courseRequirements CourseRequirementGroup[] + degree Degree @relation(fields: [degreeId], references: [id]) + degreeId String @@unique([degreeId, name]) } model Degree { - id String @id - name String - link String + id String @id + name String + link String // TODO: make this an enum of BS, BA, etc. - kind String - requirements DegreeRequirements @relation(fields: [degreeRequirementsId], references: [id]) - degreeRequirementsId Int - concentrations Concentration[] + kind String + requirements CourseRequirementGroup[] + concentrations Concentration[] + GERequirement GERequirement[] @@unique([name, kind]) @@index([id]) From 2ff6de564bd23c1de414a38184055ffc5b4bfaf4 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 09:39:03 -0700 Subject: [PATCH 47/62] minor bug fixes/cleaning in scraping --- kanban-dashboard/src/scraping/catalog.ts | 128 ++++++++++++----------- 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index d2fa276..f4199de 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -106,19 +106,7 @@ const stripCrosslistInfoFromCourseCode = (courseCode: string) => { // lists and handled properly when using degree course requirements const CourseCodeSchema = z.string().transform(stripCrosslistInfoFromCourseCode); // .regex(/^[A-Z]+\s\d+$/); -type CourseCode = z.infer; -type RequirementGroupList = (RequirementGroup | CourseCode)[]; -type RequirementGroupKind = "or" | "and"; -type RequirementGroup = - | { or: RequirementGroupList } - | { and: RequirementGroupList }; - -export const RequirementGroupSchema: z.ZodType = z.lazy(() => - z.union([ - z.object({ or: z.array(RequirementGroupSchema.or(CourseCodeSchema)) }), - z.object({ and: z.array(RequirementGroupSchema.or(CourseCodeSchema)) }), - ]) -); +export type CourseCode = z.infer; // TODO: decide whether this is usefull // export const RequirementSchema = z.object({ @@ -141,7 +129,7 @@ export const DegreeSchema = z.object({ kind: z.enum(BACHELOR_DEGREE_KINDS), link: z.string().url(), id: z.string(), - departmentId: z.string(), + // departmentId: z.string(), }); export type Degree = z.infer; @@ -157,44 +145,20 @@ const GESubAreaVariantSchema = z.union([ z.literal("Elective"), ]); -const GEAreasEnumSchema = z.enum([ - "A", - "B", - "C", - "D", - "E", - "F", - "ELECTIVES", - "USCP", -]); +const GEAreasEnumSchema = z.enum(["A", "B", "C", "D", "E", "F", "ELECTIVE"]); type GEArea = z.infer; -const GeRequirementSchema = z.object({ + +export const GeRequirementSchema = z.object({ area: GEAreasEnumSchema, subarea: GESubAreaVariantSchema, - code: z - .string() - .regex(GEAreaCodeRE) - .or(z.string().regex(GEDivisionCodeRE)) - .or(z.string().regex(GeAreaRE)) - .or(z.null()), units: z.number().nonnegative(), // TODO: constraints (C1 or C2) / fullfilled by (B3 = lab w/ B1 or B2 course) }); -type GeRequirement = z.infer; +export type GeRequirement = z.infer; -export const DegreeRequirementsSchema = z.object({ - degreeId: DegreeSchema.shape.id, - groups: z.array(RequirementGroupSchema), - courses: z.map(z.string(), RequirementCourseSchema), - ge: z.array(GeRequirementSchema), - electives: z.map(z.string()), -}); - -export type DegreeRequirements = z.infer; - -type CourseRequirement = +export type CourseRequirement = | { kind: "or"; courses: CourseRequirement[]; units: number } | { kind: "and"; courses: CourseRequirement[]; units: number } | { kind: "course"; course: CourseCode; units: number }; @@ -219,14 +183,54 @@ const CourseRequirementSchema: z.ZodType = z.lazy(() => ]) ); -const parseDegreeRequirementSectionHeader = ( - $: CheerioAPI, - headerElem: cheerio.Element -): +const DegreeRequirementSectionSchema = z.discriminatedUnion("kind", [ + z.object({ + kind: z.literal("major"), + courses: z.array(CourseRequirementSchema), + }), + z.object({ + kind: z.literal("elective"), + electiveKind: z.string(), + courses: z.array(CourseRequirementSchema), + }), + z.object({ + kind: z.literal("support"), + supportKind: z.string(), + courses: z.array(CourseRequirementSchema), + }), + z.object({ kind: z.literal("ge") }), +]); +export type DegreeRequirementSection = z.infer< + typeof DegreeRequirementSectionSchema +>; + +export type DegreeRequirementSectionInfo = | { kind: null; header: string } | { kind: RequirementType } | { kind: "elective"; electiveKind: string } - | { kind: "support"; supportKind?: string } => { + | { kind: "support"; supportKind: string | null }; + +export const DegreeRequirementsSchema = z.lazy(() => + z.object({ + courses: z.array(DegreeRequirementSectionSchema), + ge: z.array(GeRequirementSchema), + concentrations: z.array( + z.object({ + id: z.string(), + name: z.string(), + link: z.string(), + courses: z.array(DegreeRequirementSectionSchema), + }) + ), + }) +); + +export type DegreeRequirements = z.infer; + +const parseDegreeRequirementSectionHeader = ( + $: CheerioAPI, + headerElem: cheerio.Element +): DegreeRequirementSectionInfo => { let kind: RequirementType | null = null; let sectionTitle = $(headerElem) .find("span") @@ -254,9 +258,7 @@ const parseDegreeRequirementSectionHeader = ( throw new Error("found elective without elective kind: " + sectionTitle); return { kind, electiveKind }; } - if (supportKind) { - if (kind !== "support") - throw new Error("found support without support kind: " + sectionTitle); + if (kind === "support") { return { kind, supportKind }; } if (!kind) { @@ -528,13 +530,17 @@ const parseGeCourseRequirementsTable = ( let match; let area = null; let subarea = null; - if ((match = label.match(/([ABCDEF])([1234])?/))) { - let matched, num; - [matched, area, num] = match; - subarea = !!num ? matched : area + if ((match = label.match(/^([ABCDEF])([1234])?$/))) { + let num; + [subarea, area, num] = match; + console.log(area, subarea); } else if ((match = label.match(/Area ([ABCDEF])( Elective)/))) { - let _; - [_, area, subarea] = match; + let _, elective; + [_, area, elective] = match; + if (!!elective) { + subarea = elective.trim(); + } + console.log("Area", area, subarea); } else if ( (match = label.match( /((?:Upper|Lower)-Division) ([A-F])( Elective)?s?/ @@ -542,7 +548,8 @@ const parseGeCourseRequirementsTable = ( ) { let _, elective; [_, subarea, area, elective] = match; - subarea += elective ?? ""; + subarea = subarea.replace("-", "") + (elective ? elective.trim() : ""); + console.log(subarea, area, elective); } if (area === null) { if (label.includes("Select courses from two different areas")) { @@ -567,7 +574,8 @@ const parseGeCourseRequirementsTable = ( return { area, subarea, units }; }) .get() - .filter((req) => !!req); + .filter((req) => !!req && !!req.area); + console.dir(requirements, { depth: null }); return requirements; }; @@ -729,7 +737,7 @@ export const scrapeSubjectCourses = async (subjectCode: string) => { export const SubjectSchema = z.object({ name: z.string(), - code: CourseCodeSchema, + code: z.string(), }); export type Subject = z.infer; From e405c5e83c840d4e561029e8278368fcb1c6b864 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 09:42:25 -0700 Subject: [PATCH 48/62] working degree/course/subject creation --- kanban-dashboard/src/server/api/db.ts | 90 +++++++++++++++------------ 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index d0847c7..5119343 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -1,25 +1,23 @@ -import { PrismaClient } from "@prisma/client"; +import { Course, GESubArea, PrismaClient } from "@prisma/client"; import { scrapeDegrees, scrapeSubjects, scrapeCollegesAndDepartments, scrapeSubjectCourses, scrapeDegreeRequirements, + CourseRequirement, + DegreeRequirementSection, + GeRequirement, + CourseCode, } from "../../scraping/catalog"; -export const updateCatalogDataInDB = async (prisma: PrismaClient) => { - const [departments, subjects, degrees] = await Promise.all([ - scrapeCollegesAndDepartments().then((colleges) => - colleges - .map((col) => col.departments.map(({ name, id }) => ({ name, id }))) - .flat() - ), - scrapeSubjects(), - scrapeDegrees(), - ]); - const skipDuplicates = true; - // TODO: figure out how to join these into a (single?) Promise.all - await prisma.department.createMany({ data: departments, skipDuplicates }); +const CREATE_DEGREES = true; +const CREATE_COURSES = true; +const CREATE_GE_REQUIREMENTS = false; +const CREATE_COURSE_REQUIREMENTS = false; +const skipDuplicates = true; +const createCourses = async (prisma: PrismaClient) => { + const subjects = await scrapeSubjects(); await prisma.subject.createMany({ data: subjects, skipDuplicates }); const foundCourses = new Set(); await Promise.all( @@ -47,38 +45,48 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { }); }) ); +}; - await prisma.degree.createMany({ data: degrees, skipDuplicates }); - await prisma.courseRequirement.deleteMany(); - degrees.forEach(async (degree) => { - const courseCodes = await scrapeDegreeRequirements(degree).then((reqs) => - Array.from(reqs.courses.keys()) - ); - courseCodes.forEach(async (courseCode) => { - console.log( - "creating course requirement", - courseCode, - "for degree", - degree.name - ); - await prisma.courseRequirement - .create({ +const createDegrees = async (prisma: PrismaClient) => { + // await prisma.degree.deleteMany(); + const degrees = await scrapeDegrees(); + return await Promise.all( + degrees.map( + async (degree) => + await prisma.degree.create({ data: { - course: { connect: { code: courseCode } }, - degree: { connect: { id: degree.id } }, + name: degree.name, + link: degree.link, + id: degree.id, + kind: degree.kind, + }, + select: { + id: true, + name: true, + link: true, + kind: true, }, }) - .catch((_e) => - console.error( - "failed creating course requirement", - courseCode, - "for degree", - degree.name, - _e - ) - ); + ) + ); +}; + +export const updateCatalogDataInDB = async (prisma: PrismaClient) => { + if (CREATE_COURSES) await createCourses(prisma); + + let degrees; + if (CREATE_DEGREES) { + degrees = await createDegrees(prisma); + } else { + degrees = await prisma.degree.findMany({ + select: { + id: true, + name: true, + link: true, + kind: true, + }, }); - }); + } // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting // FIXME: implement retry logic as connection is very unstable }; From 71364c2c29cc329c2a79c9a73b9578f81358eaee Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 09:42:31 -0700 Subject: [PATCH 49/62] update prisma client --- kanban-dashboard/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kanban-dashboard/package.json b/kanban-dashboard/package.json index 1dfd3c7..20904a5 100644 --- a/kanban-dashboard/package.json +++ b/kanban-dashboard/package.json @@ -13,7 +13,7 @@ "dependencies": { "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.11.3", - "@prisma/client": "^4.11.0", + "@prisma/client": "^4.14.0", "@t3-oss/env-nextjs": "^0.2.1", "@tanstack/react-query": "^4.28.0", "@trpc/client": "^10.18.0", From 4b5c4a57ef073cddfbbbef8e0026d1c13cb5e6ea Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 10:49:47 -0700 Subject: [PATCH 50/62] catch and log scraping errors with FIXME's for later --- kanban-dashboard/src/scraping/catalog.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index f4199de..93a20aa 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -533,14 +533,12 @@ const parseGeCourseRequirementsTable = ( if ((match = label.match(/^([ABCDEF])([1234])?$/))) { let num; [subarea, area, num] = match; - console.log(area, subarea); } else if ((match = label.match(/Area ([ABCDEF])( Elective)/))) { let _, elective; [_, area, elective] = match; if (!!elective) { subarea = elective.trim(); } - console.log("Area", area, subarea); } else if ( (match = label.match( /((?:Upper|Lower)-Division) ([A-F])( Elective)?s?/ @@ -549,7 +547,6 @@ const parseGeCourseRequirementsTable = ( let _, elective; [_, subarea, area, elective] = match; subarea = subarea.replace("-", "") + (elective ? elective.trim() : ""); - console.log(subarea, area, elective); } if (area === null) { if (label.includes("Select courses from two different areas")) { @@ -574,8 +571,8 @@ const parseGeCourseRequirementsTable = ( return { area, subarea, units }; }) .get() + // FIXME: figure out why req?.area is sometimes null .filter((req) => !!req && !!req.area); - console.dir(requirements, { depth: null }); return requirements; }; @@ -598,6 +595,11 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { console.warn("Unrecognized table with title:", title); } }); + // FIXME: get to the bottom of this + if (!requirements.courses) { + console.error("no courses found for degree:", degree); + requirements.courses = []; + } const concentrationsList = $("h2:contains(Concentration)+ul>li a") .get() .map((elem) => ({ From 1f8e203c22df4d1cf323343a9fe8f89bf7d80d39 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 10:51:12 -0700 Subject: [PATCH 51/62] working course requirement creation --- kanban-dashboard/src/server/api/db.ts | 91 ++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index 5119343..8003a77 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -11,10 +11,10 @@ import { CourseCode, } from "../../scraping/catalog"; -const CREATE_DEGREES = true; -const CREATE_COURSES = true; +const CREATE_DEGREES = false; +const CREATE_COURSES = false; const CREATE_GE_REQUIREMENTS = false; -const CREATE_COURSE_REQUIREMENTS = false; +const CREATE_COURSE_REQUIREMENTS = true; const skipDuplicates = true; const createCourses = async (prisma: PrismaClient) => { const subjects = await scrapeSubjects(); @@ -71,6 +71,84 @@ const createDegrees = async (prisma: PrismaClient) => { ); }; +const createCourseRequirements = async ( + prisma: PrismaClient, + sections: DegreeRequirementSection[], + degreeId: string +) => { + for (const section of sections) { + if (section.kind === "ge") continue; + if (section.courses.length === 0) continue; + + const createGroup = async (group: CourseRequirement): Promise => { + const courses: CourseCode[] = []; + const childGroups = []; + let kind; + if (group.kind === "course") { + throw new Error("cannot create group from only course"); + } + for (let subGroup of group.courses) { + if (subGroup.kind === "course") { + courses.push(subGroup.course); + continue; + } + let subGroupId = await createGroup(subGroup); + childGroups.push(subGroupId); + } + + let courseKindInfo = null; + if (section.kind === "elective") { + courseKindInfo = section.electiveKind; + } else if (section.kind === "support") { + courseKindInfo = section.supportKind; + } + + const createdGroup = await prisma.courseRequirementGroup.create({ + data: { + groupKind: group.kind as "or" | "and", + coursesKind: section.kind, + courseKindInfo, + courses: { + createMany: { + data: courses.map((c: CourseCode) => ({ + courseCode: c, + kind: section.kind, + })), + skipDuplicates, + }, + }, + ...(childGroups.length > 0 && { + childGroups: { + connect: childGroups.map((id) => ({ id })), + }, + }), + }, + select: { + id: true, + }, + }).catch((e) => { console.error("failed to create group:",group); throw e}); + return createdGroup.id; + }; + + let groupKind: "or" | "and" = section.kind === "elective" ? "or" : "and"; + let rootGroupId = await createGroup({ + kind: groupKind, + courses: section.courses, + // FIXME: scrape degree units + units: 0, + }); + + await prisma.degree.update({ + where: { id: degreeId }, + data: { + requirements: { + connect: [{ id: rootGroupId }], + }, + }, + }); + } +}; + export const updateCatalogDataInDB = async (prisma: PrismaClient) => { if (CREATE_COURSES) await createCourses(prisma); @@ -87,6 +165,13 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { }, }); } + if (CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS) { + for (let degree of degrees) { + const requirements = await scrapeDegreeRequirements(degree); + if (CREATE_COURSE_REQUIREMENTS) + await createCourseRequirements(prisma, requirements.courses, degree.id); + } + } // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting // FIXME: implement retry logic as connection is very unstable }; From 1fe8549a7c636220c6dc8802f9a02c70e1465e04 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 10:56:59 -0700 Subject: [PATCH 52/62] working ge requirement creation --- kanban-dashboard/src/server/api/db.ts | 28 ++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index 8003a77..164b693 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -2,7 +2,6 @@ import { Course, GESubArea, PrismaClient } from "@prisma/client"; import { scrapeDegrees, scrapeSubjects, - scrapeCollegesAndDepartments, scrapeSubjectCourses, scrapeDegreeRequirements, CourseRequirement, @@ -13,9 +12,11 @@ import { const CREATE_DEGREES = false; const CREATE_COURSES = false; -const CREATE_GE_REQUIREMENTS = false; -const CREATE_COURSE_REQUIREMENTS = true; +const CREATE_GE_REQUIREMENTS = true; +const CREATE_COURSE_REQUIREMENTS = false; + const skipDuplicates = true; + const createCourses = async (prisma: PrismaClient) => { const subjects = await scrapeSubjects(); await prisma.subject.createMany({ data: subjects, skipDuplicates }); @@ -71,6 +72,25 @@ const createDegrees = async (prisma: PrismaClient) => { ); }; +const createDegreeGERequirements = async ( + prisma: PrismaClient, + ges: GeRequirement[], + degreeId: string +) => { + return await Promise.all( + ges.map(async (geReq: GeRequirement) => { + await prisma.gERequirement.create({ + data: { + degree: { connect: { id: degreeId } }, + area: geReq.area, + subArea: geReq.subarea as GESubArea, + units: geReq.units, + }, + }); + }) + ); +}; + const createCourseRequirements = async ( prisma: PrismaClient, sections: DegreeRequirementSection[], @@ -168,6 +188,8 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { if (CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS) { for (let degree of degrees) { const requirements = await scrapeDegreeRequirements(degree); + if (CREATE_GE_REQUIREMENTS) + await createDegreeGERequirements(prisma, requirements.ge, degree.id); if (CREATE_COURSE_REQUIREMENTS) await createCourseRequirements(prisma, requirements.courses, degree.id); } From bf7e5d739ad33da0324dc4551f39ad9b85ff70b0 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 11:43:56 -0700 Subject: [PATCH 53/62] working concentration creation --- kanban-dashboard/prisma/schema.prisma | 4 +- kanban-dashboard/src/server/api/db.ts | 188 ++++++++++++++++++-------- 2 files changed, 132 insertions(+), 60 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index d3bf16b..eeeb206 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -154,7 +154,7 @@ model CourseRequirementGroup { degree Degree? @relation(fields: [degreeId], references: [id]) concentration Concentration? @relation(fields: [concentrationId], references: [id]) degreeId String? - concentrationId Int? + concentrationId String? @@index([id]) } @@ -165,7 +165,7 @@ enum RequirementsKind { } model Concentration { - id Int @id @default(autoincrement()) + id String @id name String courseRequirements CourseRequirementGroup[] degree Degree @relation(fields: [degreeId], references: [id]) diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index 164b693..d1695f9 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -12,8 +12,9 @@ import { const CREATE_DEGREES = false; const CREATE_COURSES = false; -const CREATE_GE_REQUIREMENTS = true; +const CREATE_GE_REQUIREMENTS = false; const CREATE_COURSE_REQUIREMENTS = false; +const CREATE_CONCENTRATIONS = true; const skipDuplicates = true; @@ -91,6 +92,69 @@ const createDegreeGERequirements = async ( ); }; +const createRequirementGroup = async ( + prisma: PrismaClient, + group: CourseRequirement, + section: DegreeRequirementSection +): Promise => { + if (section.kind === "ge") { + throw new Error( + "cannot create course group for ge's:" + `${{ group, section }}` + ); + } + const courses: CourseCode[] = []; + const childGroups = []; + let kind; + if (group.kind === "course") { + throw new Error("cannot create group from only course"); + } + for (let subGroup of group.courses) { + if (subGroup.kind === "course") { + courses.push(subGroup.course); + continue; + } + let subGroupId = await createRequirementGroup(prisma, subGroup, section); + childGroups.push(subGroupId); + } + + let courseKindInfo = null; + if (section.kind === "elective") { + courseKindInfo = section.electiveKind; + } else if (section.kind === "support") { + courseKindInfo = section.supportKind; + } + + const createdGroup = await prisma.courseRequirementGroup + .create({ + data: { + groupKind: group.kind as "or" | "and", + coursesKind: section.kind, + courseKindInfo, + courses: { + createMany: { + data: courses.map((c: CourseCode) => ({ + courseCode: c, + kind: section.kind, + })), + skipDuplicates, + }, + }, + ...(childGroups.length > 0 && { + childGroups: { + connect: childGroups.map((id) => ({ id })), + }, + }), + }, + select: { + id: true, + }, + }) + .catch((e) => { + console.error("failed to create group:", group); + throw e; + }); + return createdGroup.id; +}; const createCourseRequirements = async ( prisma: PrismaClient, sections: DegreeRequirementSection[], @@ -100,63 +164,17 @@ const createCourseRequirements = async ( if (section.kind === "ge") continue; if (section.courses.length === 0) continue; - const createGroup = async (group: CourseRequirement): Promise => { - const courses: CourseCode[] = []; - const childGroups = []; - let kind; - if (group.kind === "course") { - throw new Error("cannot create group from only course"); - } - for (let subGroup of group.courses) { - if (subGroup.kind === "course") { - courses.push(subGroup.course); - continue; - } - let subGroupId = await createGroup(subGroup); - childGroups.push(subGroupId); - } - - let courseKindInfo = null; - if (section.kind === "elective") { - courseKindInfo = section.electiveKind; - } else if (section.kind === "support") { - courseKindInfo = section.supportKind; - } - - const createdGroup = await prisma.courseRequirementGroup.create({ - data: { - groupKind: group.kind as "or" | "and", - coursesKind: section.kind, - courseKindInfo, - courses: { - createMany: { - data: courses.map((c: CourseCode) => ({ - courseCode: c, - kind: section.kind, - })), - skipDuplicates, - }, - }, - ...(childGroups.length > 0 && { - childGroups: { - connect: childGroups.map((id) => ({ id })), - }, - }), - }, - select: { - id: true, - }, - }).catch((e) => { console.error("failed to create group:",group); throw e}); - return createdGroup.id; - }; - let groupKind: "or" | "and" = section.kind === "elective" ? "or" : "and"; - let rootGroupId = await createGroup({ - kind: groupKind, - courses: section.courses, - // FIXME: scrape degree units - units: 0, - }); + let rootGroupId = await createRequirementGroup( + prisma, + { + kind: groupKind, + courses: section.courses, + // FIXME: scrape degree units + units: 0, + }, + section + ); await prisma.degree.update({ where: { id: degreeId }, @@ -169,6 +187,58 @@ const createCourseRequirements = async ( } }; +const createConcentrations = async ( + prisma: PrismaClient, + concentrations: { + name: string; + link: string; + id: string; + courses: DegreeRequirementSection[]; + }[], + degreeId: string +) => { + await prisma.degree.update({ + where: { id: degreeId }, + data: { + concentrations: { + createMany: { + data: concentrations.map(({name,id}) => ({name, id})), + skipDuplicates, + }, + }, + }, + }); + + for (const concentration of concentrations) { + for (const section of concentration.courses) { + if (section.kind === "ge") + throw new Error( + "found ge section in concentration!" + `${{ concentration }}` + ); + let groupKind: "or" | "and" = section.kind === "elective" ? "or" : "and"; + let rootGroupId = await createRequirementGroup( + prisma, + { + kind: groupKind, + courses: section.courses, + // FIXME: scrape degree units + units: 0, + }, + section + ); + // TODO: make array of root group ids and update all with connnect{many} + await prisma.concentration.update({ + where: { id: concentration.id }, + data: { + courseRequirements: { + connect: [{ id: rootGroupId }], + }, + }, + }); + } + } +}; + export const updateCatalogDataInDB = async (prisma: PrismaClient) => { if (CREATE_COURSES) await createCourses(prisma); @@ -185,13 +255,15 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { }, }); } - if (CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS) { + if (CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS || CREATE_CONCENTRATIONS) { for (let degree of degrees) { const requirements = await scrapeDegreeRequirements(degree); if (CREATE_GE_REQUIREMENTS) await createDegreeGERequirements(prisma, requirements.ge, degree.id); if (CREATE_COURSE_REQUIREMENTS) await createCourseRequirements(prisma, requirements.courses, degree.id); + if (CREATE_CONCENTRATIONS) + await createConcentrations(prisma, requirements.concentrations, degree.id); } } // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting From 0314651f599ce35ef62ef45465e56cdeb7279f47 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 18:04:16 -0700 Subject: [PATCH 54/62] working db course requirement fetching --- kanban-dashboard/src/dashboard/Flowchart.tsx | 2 +- kanban-dashboard/src/dashboard/Menubar.tsx | 4 +- kanban-dashboard/src/dashboard/state.tsx | 18 ++-- kanban-dashboard/src/pages/onboarding.tsx | 4 +- kanban-dashboard/src/server/api/root.ts | 87 +++++++++++++------- 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/kanban-dashboard/src/dashboard/Flowchart.tsx b/kanban-dashboard/src/dashboard/Flowchart.tsx index 64ec96b..7946ab7 100644 --- a/kanban-dashboard/src/dashboard/Flowchart.tsx +++ b/kanban-dashboard/src/dashboard/Flowchart.tsx @@ -50,7 +50,7 @@ export default function Flowchart() { } if (source && destination) { // moveRequirement: (requirementId: number, quarterId: number) => void; - const requirementId = parseInt(draggableId); + const requirementId = draggableId; const quarterId = parseInt(destination.droppableId); moveRequirement(requirementId, quarterId); } diff --git a/kanban-dashboard/src/dashboard/Menubar.tsx b/kanban-dashboard/src/dashboard/Menubar.tsx index ecea7ef..c8edf45 100644 --- a/kanban-dashboard/src/dashboard/Menubar.tsx +++ b/kanban-dashboard/src/dashboard/Menubar.tsx @@ -293,7 +293,7 @@ export function FlowchartSwitcher({ className }: TeamSwitcherProps) { // TODO: create record of string id: Degree for faster lookup if (degree.name === name) { console.log("fetching degree requirements for:", degree); - trpcClient.degreeRequirements.prefetch({ degree, startYear }); + trpcClient.degrees.requirements.prefetch({ degreeId: degree.id, startYear }); setDegree(degree); break; } @@ -302,7 +302,7 @@ export function FlowchartSwitcher({ className }: TeamSwitcherProps) { const [value, setValue] = React.useState(""); const [openDegree, setOpenDegree] = React.useState(false); - const degreesQuery = api.degrees.useQuery(undefined, { + const degreesQuery = api.degrees.all.useQuery(undefined, { staleTime: Infinity, // don't refresh until the user refreshes }); diff --git a/kanban-dashboard/src/dashboard/state.tsx b/kanban-dashboard/src/dashboard/state.tsx index 0858381..f4e7da1 100644 --- a/kanban-dashboard/src/dashboard/state.tsx +++ b/kanban-dashboard/src/dashboard/state.tsx @@ -8,16 +8,18 @@ import React, { type Dispatch, } from "react"; -import { type Requirement, type Degree } from "~/server/api/root"; +import { type Requirement, type Degree} from "~/server/api/root"; import { api } from "~/utils/api"; type Setter = React.Dispatch>; +export type PartialDegree = Pick; + type FlowchartStateType = { requirements: Requirement[]; setRequirements: Setter; - degree: Degree | null; - setDegree: Setter; + degree: PartialDegree | null; + setDegree: Setter; startYear: number; setStartYear: Setter; selectedRequirements: number[]; @@ -35,7 +37,7 @@ export const FlowchartStateProvider: FC<{ children: React.ReactNode }> = ({ // TODO: remove StoreProvider and replace with trpc quarters query in flowchart // TODO: merge dashboard and flowhcart components // TODO: make moveRequirement a backend mutation - const [degree, setDegree] = useState(null); + const [degree, setDegree] = useState(null); const [requirements, setRequirements] = useState([]); const [selectedRequirements, setSelectedRequirements] = useState( @@ -47,8 +49,8 @@ export const FlowchartStateProvider: FC<{ children: React.ReactNode }> = ({ useEffect(() => { console.log("updating requirements!"); }, [requirements]); - const _requirementsQuery = api.degreeRequirements.useQuery( - { degree, startYear }, + const _requirementsQuery = api.degrees.requirements.useQuery( + { degreeId: degree?.id ?? null, startYear }, { enabled: false, onSuccess: (data) => setRequirements(data) } ); const flowchartContext = { @@ -74,9 +76,9 @@ export const FlowchartStateProvider: FC<{ children: React.ReactNode }> = ({ export const useMoveRequirement = () => { const { degree, startYear } = useContext(FlowchartState); const trpcClient = api.useContext(); - const moveRequirement = (requirementId: number, quarterId: number) => { + const moveRequirement = (requirementId: string, quarterId: number) => { trpcClient.degrees.requirements.setData( - { degree, startYear }, + { degreeId: degree?.id ?? null, startYear }, (requirements) => { if (!requirements) { console.error("No requirements found for degree:", degree); diff --git a/kanban-dashboard/src/pages/onboarding.tsx b/kanban-dashboard/src/pages/onboarding.tsx index 45097ec..3272cf3 100644 --- a/kanban-dashboard/src/pages/onboarding.tsx +++ b/kanban-dashboard/src/pages/onboarding.tsx @@ -48,7 +48,7 @@ export default function OnboardingPage() { const [open, setOpen] = useState(false); const [value, setValue] = useState(""); const router = useRouter(); - const degreesQuery = api.degrees.useQuery(undefined, { + const degreesQuery = api.degrees.all.useQuery(undefined, { staleTime: Infinity, // don't refresh until the user refreshes }); const [selectedClasses, setSelectedClasses] = useState([]); @@ -72,7 +72,7 @@ export default function OnboardingPage() { // TODO: create record of string id: Degree for faster lookup if (degree.name === name) { console.log("fetching degree requirements for:", degree); - trpcClient.degreeRequirements.prefetch({ degree, startYear }); + trpcClient.degrees.requirements.prefetch({ degreeId: degree.id, startYear }); setDegree(degree); break; } diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index fedd3ab..ab5fd68 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -18,7 +18,6 @@ import { scrapeCurrentQuarter, termCode, } from "~/scraping/registrar"; -import { prisma } from "~/server/db"; const courseType_arr = RequirementTypeSchema.options; @@ -34,7 +33,7 @@ const SchoolYearTermSchema = z.union([ const RequirementSchema = z.object({ code: z.string(), // TODO: validate course code - id: z.number(), + id: z.string(), title: z.string(), courseType: RequirementTypeSchema, units: z.number().nonnegative(), @@ -89,51 +88,77 @@ export const appRouter = t.router({ requirements: t.procedure .input( z.object({ - degree: DegreeSchema.nullable(), + degreeId: z.string().nullable(), startYear: z.number().gte(2000), }) ) .output(z.array(RequirementSchema)) - .query(async ({ input }) => { - if (input.degree === null) { - return []; - } - let { requirements } = await prisma.degree.findUnique({ + .query(async ({ ctx, input }) => { + if (!input.degreeId) return []; + const reqGroups = await ctx.prisma.courseRequirementGroup.findMany({ where: { - id: input.degree.id, + degreeId: input.degreeId, }, select: { - requirements: true, + courses: { + select: { + courseCode: true, + course: { + select: { + title: true, + maxUnits: true, + minUnits: true, + }, + }, + }, + }, + coursesKind: true, + groupKind: true, }, - }) ?? {}; - if (!requirements || requirements.length === 0) { - const { courses } = await scrapeDegreeRequirements(input.degree); - requirements = Array.from(courses.values()).map( - (course: RequirementCourse, i) => ({ - ...course, - courseType: - courseType_arr[Math.floor(Math.random() * courseType_arr.length)], // TODO: figure out course type from group + }); + return reqGroups.flatMap((group) => { + return group.courses.map((req) => ({ + code: req.courseCode, + id: `${group.groupKind}-${group.coursesKind}-${req.courseCode}`, + title: req.course.title, + courseType: group.coursesKind, quarterId: termCode( Math.floor(Math.random() * 4) + input.startYear, SchoolYearTermSchema.parse( [2, 4, 8][Math.floor(Math.random() * 3)] ) ), - id: i, - }) + units: req.course.maxUnits, + })); + }); + }), + all: t.procedure + .output(z.array(z.object({ name: z.string(), id: z.string() }))) + .query(async ({ ctx }) => { + let degrees = await ctx.prisma.degree.findMany({ + select: { + id: true, + name: true, + }, + }); + return degrees; + }), + concentrations: t.procedure + .input(z.object({ degreeId: z.string() })) + .output(z.array(z.object({ name: z.string(), id: z.string() }))) + .query(async ({ ctx, input }) => { + return ( + (await ctx.prisma.concentration.findMany({ + where: { + degreeId: input.degreeId, + }, + select: { + name: true, + id: true, + }, + })) ?? [] ); - - } }), - all: t.procedure.query(async () => { - let degrees = await prisma.degree.findMany(); - if (degrees.length === 0) { - // TODO: invalidation of db data - degrees = await scrapeDegrees(); - await prisma.degree.createMany({ data: degrees }); - } - return degrees; - }), }), }); From 17d15f188f7153be4b58d25ef507a275f1a56fb3 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 18:31:09 -0700 Subject: [PATCH 55/62] returning ge requirements --- kanban-dashboard/src/server/api/root.ts | 37 +++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index ab5fd68..72840f2 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -5,6 +5,7 @@ import { type RequirementCourse, DegreeSchema, RequirementTypeSchema, + RequirementType, } from "~/scraping/catalog"; export type { Degree, @@ -46,7 +47,15 @@ const QuarterSchema = z.object({ year: YearSchema, termNum: SchoolYearTermSchema, }); + export type Quarter = z.infer; + +const randomQuarter = (startYear: number) => { + return termCode( + Math.floor(Math.random() * 4) + startYear, + SchoolYearTermSchema.parse([2, 4, 8][Math.floor(Math.random() * 3)]) + ); +}; /** * This is the primary router for your server. * @@ -116,21 +125,33 @@ export const appRouter = t.router({ groupKind: true, }, }); + const geReqs = await ctx.prisma.gERequirement.findMany({ + where: { + degreeId: input.degreeId, + }, + select: { + units: true, + area: true, + subArea: true, + }, + }); return reqGroups.flatMap((group) => { return group.courses.map((req) => ({ code: req.courseCode, id: `${group.groupKind}-${group.coursesKind}-${req.courseCode}`, title: req.course.title, - courseType: group.coursesKind, - quarterId: termCode( - Math.floor(Math.random() * 4) + input.startYear, - SchoolYearTermSchema.parse( - [2, 4, 8][Math.floor(Math.random() * 3)] - ) - ), + courseType: group.coursesKind as RequirementType, + quarterId: randomQuarter(input.startYear), units: req.course.maxUnits, })); - }); + }).concat(geReqs.map((req) => ({ + code: `${req.area}-${req.subArea}`, + id: `${req.area}-${req.subArea}`, + title: `${req.subArea}`, + courseType: "ge", + quarterId: randomQuarter(input.startYear), + units: req.units, + }))); }), all: t.procedure .output(z.array(z.object({ name: z.string(), id: z.string() }))) From f76b08fb93944f45b604d81f96a899bd5f505368 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 21:35:30 -0700 Subject: [PATCH 56/62] wipe db function --- kanban-dashboard/src/server/api/db.ts | 58 +++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index d1695f9..97e117f 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -10,11 +10,12 @@ import { CourseCode, } from "../../scraping/catalog"; -const CREATE_DEGREES = false; const CREATE_COURSES = false; -const CREATE_GE_REQUIREMENTS = false; -const CREATE_COURSE_REQUIREMENTS = false; +const CREATE_DEGREES = true; +const CREATE_GE_REQUIREMENTS = true; +const CREATE_COURSE_REQUIREMENTS = true; const CREATE_CONCENTRATIONS = true; +const REMOVE_DEGREES_AND_REQUIREMENTS = false; const skipDuplicates = true; @@ -129,6 +130,7 @@ const createRequirementGroup = async ( data: { groupKind: group.kind as "or" | "and", coursesKind: section.kind, + unitsOf: group.units, courseKindInfo, courses: { createMany: { @@ -202,8 +204,8 @@ const createConcentrations = async ( data: { concentrations: { createMany: { - data: concentrations.map(({name,id}) => ({name, id})), - skipDuplicates, + data: concentrations.map(({ name, id }) => ({ name, id })), + skipDuplicates, }, }, }, @@ -226,7 +228,7 @@ const createConcentrations = async ( }, section ); - // TODO: make array of root group ids and update all with connnect{many} + // TODO: make array of root group ids and update all with connnect{many} await prisma.concentration.update({ where: { id: concentration.id }, data: { @@ -239,7 +241,39 @@ const createConcentrations = async ( } }; +const removeDegreesAndRequirements = async (prisma: PrismaClient) => { + await prisma.courseRequirement.deleteMany({}); + await prisma.courseRequirementGroup.updateMany({ + where: { + parentGroup: { + isNot: null, + }, + }, + data: { + parentId: null, + }, + }); + await prisma.courseRequirementGroup.updateMany({ + where: { + degree: { + isNot: null, + }, + }, + data: { + degreeId: null, + }, + }); + await prisma.gERequirement.deleteMany({}); + await prisma.concentration.deleteMany({}); + await prisma.courseRequirementGroup.deleteMany({}); + await prisma.degree.deleteMany({}); +}; + export const updateCatalogDataInDB = async (prisma: PrismaClient) => { + if (REMOVE_DEGREES_AND_REQUIREMENTS) { + await removeDegreesAndRequirements(prisma); + return "removed degrees and requirements"; + } if (CREATE_COURSES) await createCourses(prisma); let degrees; @@ -255,7 +289,11 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { }, }); } - if (CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS || CREATE_CONCENTRATIONS) { + if ( + CREATE_GE_REQUIREMENTS || + CREATE_COURSE_REQUIREMENTS || + CREATE_CONCENTRATIONS + ) { for (let degree of degrees) { const requirements = await scrapeDegreeRequirements(degree); if (CREATE_GE_REQUIREMENTS) @@ -263,7 +301,11 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { if (CREATE_COURSE_REQUIREMENTS) await createCourseRequirements(prisma, requirements.courses, degree.id); if (CREATE_CONCENTRATIONS) - await createConcentrations(prisma, requirements.concentrations, degree.id); + await createConcentrations( + prisma, + requirements.concentrations, + degree.id + ); } } // FIXME: use CourseCodeSchema for ALL course codes to catch weird edge cases and prevent the "not found" errors when connecting From 9bdf72876c96beb947f2b1c198e7749e5ce165dc Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Thu, 8 Jun 2023 21:35:39 -0700 Subject: [PATCH 57/62] use db in backend --- kanban-dashboard/src/server/api/root.ts | 123 +++++++++++++++++++++--- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 72840f2..5dcc7ea 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -19,6 +19,7 @@ import { scrapeCurrentQuarter, termCode, } from "~/scraping/registrar"; +import { GEArea, GESubArea } from "@prisma/client"; const courseType_arr = RequirementTypeSchema.options; @@ -32,6 +33,17 @@ const SchoolYearTermSchema = z.union([ z.literal(8), ]); +export const GroupSchema = z.discriminatedUnion("kind", [ + z.object({ + kind: z.literal("ge"), + area: z.string(), + subArea: z.string(), + }), + z.object({ kind: z.literal("uscp") }), + z.object({ kind: z.literal("gwr") }), + z.object({ kind: z.literal("elective"), groupId: z.number() }), +]); + const RequirementSchema = z.object({ code: z.string(), // TODO: validate course code id: z.string(), @@ -39,6 +51,7 @@ const RequirementSchema = z.object({ courseType: RequirementTypeSchema, units: z.number().nonnegative(), quarterId: z.number().gte(2000, { message: "term code < 2000" }), // see termCode function in scraping/registrar.ts for details + groupId: GroupSchema.optional(), }); export type Requirement = z.infer; @@ -121,8 +134,19 @@ export const appRouter = t.router({ }, }, }, + childGroups: { + select: { + id: true, + unitsOf: true, + coursesKind: true, + courseKindInfo: true, + groupKind: true, + }, + }, coursesKind: true, + courseKindInfo: true, groupKind: true, + unitsOf: true, }, }); const geReqs = await ctx.prisma.gERequirement.findMany({ @@ -135,23 +159,98 @@ export const appRouter = t.router({ subArea: true, }, }); - return reqGroups.flatMap((group) => { - return group.courses.map((req) => ({ - code: req.courseCode, - id: `${group.groupKind}-${group.coursesKind}-${req.courseCode}`, - title: req.course.title, - courseType: group.coursesKind as RequirementType, - quarterId: randomQuarter(input.startYear), - units: req.course.maxUnits, - })); - }).concat(geReqs.map((req) => ({ - code: `${req.area}-${req.subArea}`, + let courses = []; + reqGroups.forEach((group) => { + courses = courses.concat( + group.courses.map((req) => ({ + code: req.courseCode, + id: `${group.groupKind}-${group.coursesKind}-${req.courseCode}`, + title: req.course.title, + courseType: group.coursesKind as RequirementType, + quarterId: randomQuarter(input.startYear), + units: req.course.maxUnits, + })) + ); + }); + + reqGroups.forEach((group) => { + group.childGroups.forEach((childGroup) => { + switch (childGroup.groupKind) { + case "or": + if (!childGroup.unitsOf || !group.unitsOf) + childGroup.unitsOf = 4; + let numCourses = (childGroup.unitsOf ?? group.unitsOf) / 4; + if (numCourses < 1) numCourses = 1; + let code; + let title; + if (group.coursesKind === "elective") { + code = group.courseKindInfo + ? group.courseKindInfo + " " + "Elective" + : "Elective"; + title = ""; + } else { + console.warn("skipping group:", { group }); + return; + } + for (let i = 0; i < numCourses; i++) { + courses.push({ + code, + title, + id: `${group.groupKind}-${group.coursesKind}-${group.courseKindInfo}-${i}`, + courseType: group.coursesKind as RequirementType, + quarterId: randomQuarter(input.startYear), + units: childGroup.unitsOf ?? group.unitsOf, + groupId: { kind: "elective", groupId: childGroup.id }, + }); + } + break; + case "and": + // FIXME: fetch courses + + // let subGroupCourses = + // (await ctx.prisma.courseRequirementGroup.findUnique({ + // where: { + // id: childGroup.id, + // }, + // select: { + // courses: { + // select: { + // courseCode: true, + // course: { + // select: { + // title: true, + // }, + // }, + // }, + // }, + // }, + // })) ?? { courses: [] }; + // courses = courses.concat( + // subGroupCourses.courses.map((req) => ({ + // code: req.courseCode, + // title: req.course.title, + // id: `${group.groupKind}-${group.coursesKind}-${req.courseCode}`, + // courseType: group.coursesKind as RequirementType, + // quarterId: randomQuarter(input.startYear), + // units: group.unitsOf, + // })) + // ); + } + }); + }); + courses = courses.concat( + geReqs.map((req) => ({ + code: `GE Area ${req.area} ${req.subArea}`, id: `${req.area}-${req.subArea}`, title: `${req.subArea}`, courseType: "ge", quarterId: randomQuarter(input.startYear), units: req.units, - }))); + groupId: { kind: "ge", area: req.area, subArea: req.subArea }, + })) + ); + console.dir(courses, { depth: null }); + return courses; }), all: t.procedure .output(z.array(z.object({ name: z.string(), id: z.string() }))) From c4f1f1d16546cb6b13c6ff6f4e47525e3b617eb1 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 9 Jun 2023 00:52:03 -0700 Subject: [PATCH 58/62] fullfillments endpoint --- kanban-dashboard/prisma/schema.prisma | 3 +- kanban-dashboard/src/scraping/catalog.ts | 32 ++++++--- kanban-dashboard/src/server/api/db.ts | 74 ++++++++++++++++++-- kanban-dashboard/src/server/api/root.ts | 86 ++++++++++++++++++++++-- 4 files changed, 177 insertions(+), 18 deletions(-) diff --git a/kanban-dashboard/prisma/schema.prisma b/kanban-dashboard/prisma/schema.prisma index eeeb206..10715bf 100644 --- a/kanban-dashboard/prisma/schema.prisma +++ b/kanban-dashboard/prisma/schema.prisma @@ -189,12 +189,13 @@ model Degree { } model GEAreaFullfillmentCourse { + id Int @id @default(autoincrement()) area GEArea subArea GESubArea courseId String course Course @relation(fields: [courseId], references: [code]) - @@id([area, subArea, courseId]) + @@unique([area, subArea, courseId]) } model User { diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index 93a20aa..dcc914e 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -595,7 +595,7 @@ export const scrapeDegreeRequirements = async (degree: Degree) => { console.warn("Unrecognized table with title:", title); } }); - // FIXME: get to the bottom of this + // FIXME: get to the bottom of this if (!requirements.courses) { console.error("no courses found for degree:", degree); requirements.courses = []; @@ -781,8 +781,11 @@ const GEAreaDataSchema = z type GEAreaData = z.infer; -export const GEDataSchema = z.map(GEAreasEnumSchema, GEAreaDataSchema); -type GEData = z.infer; +export const GEDataSchema = z.map( + GEAreasEnumSchema.or(z.literal("USCP")).or(z.literal("GWR")), + GEAreaDataSchema +); +export type GEData = z.infer; /** Returns courses that fulfill ge requirements for each area */ export const scrapeCourseGEFullfillments = async () => { @@ -812,7 +815,7 @@ export const scrapeCourseGEFullfillments = async () => { let area: GEArea; if (areaLabel.includes("GE ELECTIVES")) { info.name = areaLabel; - area = "ELECTIVES"; + area = "ELECTIVE"; // TODO: include limit info (only area B C D) } else { let match = areaLabel.match(/\(AREA ([ABCDEF])\)/); @@ -858,7 +861,7 @@ export const scrapeCourseGEFullfillments = async () => { } if ( (match = label.match( - /((?:Upper|Lower)-Division) [A-F]( Elective)?s?/ + /((?:Upper|Lower)-Division) [A-F]\s?(Elective)?s?/ )) ) { let [matched, _subarea, elective] = match; @@ -922,9 +925,10 @@ export const scrapeCourseGEFullfillments = async () => { } let match; if (title.includes("GE ELECTIVES")) { - sections.get("ELECTIVES")!.fullfilledBy = courses; + sections.get("ELECTIVE")!.fullfilledBy = courses; } else if ((match = title.match(/((?:Upper|Lower)-Division) ([A-F])/))) { - const [_, division, area] = match; + let [_, division, area] = match; + division = division.replace("-", ""); const subarea = sections.get(GEAreasEnumSchema.parse(area))!.subareas[ division ]; @@ -966,7 +970,19 @@ export const scrapeCourseGEFullfillments = async () => { .map((_i, codeCol) => $(codeCol).text().trim()) .get(); sections.set("USCP", GEAreaDataSchema.parse({ fullfilledBy: uscpCourses })); - // FIXME: GWR courses + const gwr$ = await fetch( + "https://catalog.calpoly.edu/coursesaz/#gwrcoursestext" + ) + .then((r) => r.text()) + .then(cheerio.load) + + const gwrCourses = gwr$("h2:contains(GWR)") + .next("table.sc_courselist") + .find("a.code") + .get() + .map((c) => $(c).text()); + sections.set("GWR", GEAreaDataSchema.parse({ fullfilledBy: gwrCourses })); + // FIXME: extract parsing of these tables into separate functtions // to allow all ge's, uscp, gwr, and subjects from https://catalog.calpoly.edu/coursesaz diff --git a/kanban-dashboard/src/server/api/db.ts b/kanban-dashboard/src/server/api/db.ts index 97e117f..920615f 100644 --- a/kanban-dashboard/src/server/api/db.ts +++ b/kanban-dashboard/src/server/api/db.ts @@ -8,14 +8,17 @@ import { DegreeRequirementSection, GeRequirement, CourseCode, + GEData, + scrapeCourseGEFullfillments, } from "../../scraping/catalog"; const CREATE_COURSES = false; -const CREATE_DEGREES = true; -const CREATE_GE_REQUIREMENTS = true; -const CREATE_COURSE_REQUIREMENTS = true; -const CREATE_CONCENTRATIONS = true; +const CREATE_DEGREES = false; +const CREATE_GE_REQUIREMENTS = false; +const CREATE_COURSE_REQUIREMENTS = false; +const CREATE_CONCENTRATIONS = false; const REMOVE_DEGREES_AND_REQUIREMENTS = false; +const UPDATE_GE_FULLFILLMENTS = true; const skipDuplicates = true; @@ -241,6 +244,65 @@ const createConcentrations = async ( } }; +const createGEFullfillments = async (prisma: PrismaClient, ges: GEData) => { + await prisma.gEAreaFullfillmentCourse.deleteMany(); + for (let [area, info] of ges.entries()) { + for (let [subArea, subInfo] of Object.entries(info.subareas)) { + if (area === "USCP" || area === "GWR") { + await prisma.course.updateMany({ + where: { + code: { + in: subInfo.fullfilledBy, + }, + }, + data: { + [area]: true, + }, + }); + continue; + } + for (let course of subInfo.fullfilledBy) { + if (!area || !subArea || !course) { + console.error("missing data for ge fullfillment", { + area, + subArea, + course, + }); + continue; + } + try { + await prisma.course.findUniqueOrThrow({ + where: { + code: course, + }, + }); + } catch { + console.error("could not find course:", course); + continue; + } + await prisma.gEAreaFullfillmentCourse + .create({ + data: { + course: { + connect: { code: course }, + }, + courseId: course, + area, + subArea, + }, + }) + .catch((_) => + console.error("failed to create:", { + area, + subArea, + course, + }) + ); + } + } + } +}; + const removeDegreesAndRequirements = async (prisma: PrismaClient) => { await prisma.courseRequirement.deleteMany({}); await prisma.courseRequirementGroup.updateMany({ @@ -289,6 +351,10 @@ export const updateCatalogDataInDB = async (prisma: PrismaClient) => { }, }); } + if (UPDATE_GE_FULLFILLMENTS) { + const ges = await scrapeCourseGEFullfillments(); + await createGEFullfillments(prisma, ges); + } if ( CREATE_GE_REQUIREMENTS || CREATE_COURSE_REQUIREMENTS || diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 5dcc7ea..9790003 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -6,6 +6,7 @@ import { DegreeSchema, RequirementTypeSchema, RequirementType, + scrapeCourseGEFullfillments, } from "~/scraping/catalog"; export type { Degree, @@ -39,9 +40,13 @@ export const GroupSchema = z.discriminatedUnion("kind", [ area: z.string(), subArea: z.string(), }), - z.object({ kind: z.literal("uscp") }), - z.object({ kind: z.literal("gwr") }), - z.object({ kind: z.literal("elective"), groupId: z.number() }), + z.object({ kind: z.literal("uscp"), degreeId: z.string() }), + z.object({ kind: z.literal("gwr"), degreeId: z.string() }), + z.object({ + kind: z.literal("elective"), + groupId: z.number(), + degreeId: z.string(), + }), ]); const RequirementSchema = z.object({ @@ -53,6 +58,7 @@ const RequirementSchema = z.object({ quarterId: z.number().gte(2000, { message: "term code < 2000" }), // see termCode function in scraping/registrar.ts for details groupId: GroupSchema.optional(), }); + export type Requirement = z.infer; const QuarterSchema = z.object({ @@ -69,6 +75,7 @@ const randomQuarter = (startYear: number) => { SchoolYearTermSchema.parse([2, 4, 8][Math.floor(Math.random() * 3)]) ); }; + /** * This is the primary router for your server. * @@ -200,7 +207,11 @@ export const appRouter = t.router({ courseType: group.coursesKind as RequirementType, quarterId: randomQuarter(input.startYear), units: childGroup.unitsOf ?? group.unitsOf, - groupId: { kind: "elective", groupId: childGroup.id }, + groupId: { + kind: "elective", + groupId: childGroup.id, + degreeId: input.degreeId, + }, }); } break; @@ -246,10 +257,18 @@ export const appRouter = t.router({ courseType: "ge", quarterId: randomQuarter(input.startYear), units: req.units, - groupId: { kind: "ge", area: req.area, subArea: req.subArea }, + groupId: { + kind: "ge", + area: req.area, + subArea: req.subArea, + degreeId: input.degreeId, + }, })) ); console.dir(courses, { depth: null }); + let courseSet = new Set(courses.map(c => c.id)) + if (courseSet.size !== courses.length) + throw new Error(`only ${courseSet.size} unique ids in ${courses.length} courses`) return courses; }), all: t.procedure @@ -280,6 +299,63 @@ export const appRouter = t.router({ ); }), }), + fulllfillments: t.procedure + .input(z.object({ group: GroupSchema })) + .output( + z.array( + z.object({ code: z.string(), title: z.string(), units: z.number() }) + ) + ) + .query(async ({ ctx, input }) => { + switch (input.group.kind) { + case "uscp": + return await scrapeCourseGEFullfillments().then( + (reqs) => reqs.get("USCP")?.fullfilledBy + ); + break; + case "gwr": + return await scrapeCourseGEFullfillments().then( + (reqs) => reqs.get("GWR")?.fullfilledBy + ); + break; + case "ge": + return await scrapeCourseGEFullfillments().then( + (reqs) => + reqs.get(input.group.area)?.[input.group.subArea].fullfilledBy + ); + break; + case "elective": + return await ctx.prisma.courseRequirementGroup + .findUnique({ + where: { + id: input.group.groupId, + }, + select: { + courses: { + select: { + courseCode: true, + course: { + select: { + title: true, + maxUnits: true, + minUnits: true, + }, + }, + }, + }, + }, + }) + .then((courses) => { + if (!courses) return []; + + return courses.courses.map((course) => ({ + code: course.courseCode, + title: course.course.title, + units: course.course.maxUnits, + })); + }); + } + }), }); // export type definition of API From 346d89e974a230ded85e26ae105427aa5731ac4b Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 9 Jun 2023 00:54:56 -0700 Subject: [PATCH 59/62] check all ids unique --- kanban-dashboard/src/server/api/root.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 9790003..7cfc1a9 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -266,9 +266,11 @@ export const appRouter = t.router({ })) ); console.dir(courses, { depth: null }); - let courseSet = new Set(courses.map(c => c.id)) + let courseSet = new Set(courses.map((c) => c.id)); if (courseSet.size !== courses.length) - throw new Error(`only ${courseSet.size} unique ids in ${courses.length} courses`) + throw new Error( + `only ${courseSet.size} unique ids in ${courses.length} courses` + ); return courses; }), all: t.procedure From 17be8a826520967c0aa5b1a5ab4e54e5cf5ca747 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 9 Jun 2023 03:24:54 -0700 Subject: [PATCH 60/62] sections endpoint! --- kanban-dashboard/src/scraping/catalog.ts | 2 +- .../src/scraping/sections_fetch.ts | 299 ++++++++++-------- kanban-dashboard/src/server/api/root.ts | 19 ++ 3 files changed, 181 insertions(+), 139 deletions(-) diff --git a/kanban-dashboard/src/scraping/catalog.ts b/kanban-dashboard/src/scraping/catalog.ts index dcc914e..5e4fba0 100644 --- a/kanban-dashboard/src/scraping/catalog.ts +++ b/kanban-dashboard/src/scraping/catalog.ts @@ -104,7 +104,7 @@ const stripCrosslistInfoFromCourseCode = (courseCode: string) => { // NOTE: it is expected that information from crosslistings can be parsed in subject course // lists and handled properly when using degree course requirements -const CourseCodeSchema = z.string().transform(stripCrosslistInfoFromCourseCode); // .regex(/^[A-Z]+\s\d+$/); +export const CourseCodeSchema = z.string().transform(stripCrosslistInfoFromCourseCode); // .regex(/^[A-Z]+\s\d+$/); export type CourseCode = z.infer; diff --git a/kanban-dashboard/src/scraping/sections_fetch.ts b/kanban-dashboard/src/scraping/sections_fetch.ts index bb35e7e..55e0f1b 100644 --- a/kanban-dashboard/src/scraping/sections_fetch.ts +++ b/kanban-dashboard/src/scraping/sections_fetch.ts @@ -2,162 +2,185 @@ // TODO: remove eslint-disable once this code is being used import assert from "assert"; import * as cheerio from "cheerio/lib/slim"; +import { CourseCode } from "./catalog"; +import { z } from "zod"; -const URL = - "https://cmsweb.pscs.calpoly.edu/psc/CSLOPRD/EMPLOYEE/SA/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"; +export const SectionSchema = z.object({ + num: z.number(), + prof: z.string(), + dates: z.string(), + title: z.string(), + location: z.string(), + status: z.enum(["WAITLIST", "OPEN", "CLOSE"]), +}); -const assertNotPageNoLongerAvailable = async (body: string) => { - assert(!body.includes("This page is no longer available.")); - return body; -}; +export const scrapeSections = async ( + courseCode: CourseCode, + quarterId: number +) => { + const [courseSubject, courseNumber] = courseCode.split(" "); + const URL = + "https://cmsweb.pscs.calpoly.edu/psc/CSLOPRD/EMPLOYEE/SA/c/COMMUNITY_ACCESS.CLASS_SEARCH.GBL"; -const initialFetch = await fetch(URL, { - method: "GET", - redirect: "manual", -}) - .then((res) => { - if (res.headers.get("RespondingWithSignOnPage") !== null) { - throw new Error( - "RespondingWithSignOnPage - set redirect back to manual instead of follow" - ); - } - return res; + const assertNotPageNoLongerAvailable = async (body: string) => { + assert(!body.includes("This page is no longer available.")); + return body; + }; + + const initialFetch = await fetch(URL, { + method: "GET", + redirect: "manual", }) - .then((res) => { - if (res.status === 302) { - console.log("redirected"); - const cookies = res.headers.get("set-cookie"); - // NOTE: actually going to newURL is not necessary. - // The only thing stopping us from getting another 302 is the cookies - const newURL = res.headers.get("location"); - return fetch(newURL, { - method: "GET", - headers: { Cookie: cookies }, - }); - } else { + .then((res) => { + if (res.headers.get("RespondingWithSignOnPage") !== null) { + throw new Error( + "RespondingWithSignOnPage - set redirect back to manual instead of follow" + ); + } return res; - } - }); + }) + .then((res) => { + if (res.status === 302) { + console.log("redirected"); + const cookies = res.headers.get("set-cookie"); + // NOTE: actually going to newURL is not necessary. + // The only thing stopping us from getting another 302 is the cookies + const newURL = res.headers.get("location"); + return fetch(newURL, { + method: "GET", + headers: { Cookie: cookies }, + }); + } else { + return res; + } + }); -const cookies = initialFetch.headers.get("set-cookie"); -let ICHiddens = await initialFetch.text().then((page) => { - const $ = cheerio.load(page); - const hiddens = $("#win0divPSHIDDENFIELDS").find("input"); - const ics = new Map(); - hiddens.each((i, elem) => { - ics.set($(elem).attr("name"), $(elem).attr("value")); + const cookies = initialFetch.headers.get("set-cookie"); + let ICHiddens = await initialFetch.text().then((page) => { + const $ = cheerio.load(page); + const hiddens = $("#win0divPSHIDDENFIELDS").find("input"); + const ics = new Map(); + hiddens.each((i, elem) => { + ics.set($(elem).attr("name"), $(elem).attr("value")); + }); + return ics; }); - return ics; -}); -const headers = new Headers({ Cookie: cookies }); -ICHiddens = new URLSearchParams(ICHiddens); -const ICHiddensCopy = new URLSearchParams(ICHiddens); + const headers = new Headers({ Cookie: cookies }); + ICHiddens = new URLSearchParams(ICHiddens); + const ICHiddensCopy = new URLSearchParams(ICHiddens); -// select SLCMP as institution -headers.set("Content-Type", "application/x-www-form-urlencoded"); -ICHiddens.set("ICAction", "CLASS_SRCH_WRK2_INSTITUTION$31$"); -ICHiddens.set("CLASS_SRCH_WRK2_INSTITUTION$31$", "SLCMP"); + // select SLCMP as institution + headers.set("Content-Type", "application/x-www-form-urlencoded"); + ICHiddens.set("ICAction", "CLASS_SRCH_WRK2_INSTITUTION$31$"); + ICHiddens.set("CLASS_SRCH_WRK2_INSTITUTION$31$", "SLCMP"); -await fetch(URL, { - method: "POST", - headers, - body: ICHiddens, -}) - .then((res) => res.text()) - .then(assertNotPageNoLongerAvailable) - .then((page) => { - const $ = cheerio.load(page); - assert( - $("option[value=SLCMP]").attr("selected") === "selected", - "failed to select SLCMP" - ); - }); + await fetch(URL, { + method: "POST", + headers, + body: ICHiddens, + }) + .then((res) => res.text()) + .then(assertNotPageNoLongerAvailable) + .then((page) => { + const $ = cheerio.load(page); + assert( + $("option[value=SLCMP]").attr("selected") === "selected", + "failed to select SLCMP" + ); + }); -// select current quarter -ICHiddens.set("ICAction", "SLO_SS_DERIVED_STRM"); -ICHiddens.set("SLO_SS_DERIVED_STRM", "2234"); -await fetch(URL, { - method: "POST", - headers, - body: ICHiddens, -}) - .then((res) => res.text()) - .then(assertNotPageNoLongerAvailable) - .then((page) => { - const $ = cheerio.load(page); - assert( - $("#SLO_SS_DERIVED_STRM").attr("value") === "2234", - "failed to change selected term" - ); - }); + // select current quarter + ICHiddens.set("ICAction", "SLO_SS_DERIVED_STRM"); + ICHiddens.set("SLO_SS_DERIVED_STRM", quarterId.toString()); + await fetch(URL, { + method: "POST", + headers, + body: ICHiddens, + }) + .then((res) => res.text()) + .then(assertNotPageNoLongerAvailable) + .then((page) => { + const $ = cheerio.load(page); + // assert( + // $("#SLO_SS_DERIVED_STRM").attr("value") === "2234", + // "failed to change selected term" + // ); + }); -// select CS as subject -ICHiddens.set("SSR_CLSRCH_WRK_SUBJECT_SRCH$0", "CSC"); + // select CS as subject + ICHiddens.set("SSR_CLSRCH_WRK_SUBJECT_SRCH$0", "CSC"); -// set course number >= -ICHiddens.set("SSR_CLSRCH_WRK_SSR_EXACT_MATCH1$1", "G"); + // set course number >= + // ICHiddens.set("SSR_CLSRCH_WRK_SSR_EXACT_MATCH1$1", "G"); + ICHiddens.set("SSR_CLSRCH_WRK_CATALOG_NBR$1", courseNumber); -// set course number >= than 0 (hack to get the minimum 2 search criteria) -ICHiddens.set("SSR_CLSRCH_WRK_CATALOG_NBR$1", "0"); + // set course number >= than 0 (hack to get the minimum 2 search criteria) + // ICHiddens.set("SSR_CLSRCH_WRK_CATALOG_NBR$1", "0"); -// Show Closed classes as well -// ICHiddens.set("SSR_CLSRCH_WRK_SSR_OPEN_ONLY$chk$3", "N"); + // Show Closed classes as well + ICHiddens.set("SSR_CLSRCH_WRK_SSR_OPEN_ONLY$chk$3", "N"); -// execute search -ICHiddens.set("ICAction", "CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"); -const searchResultsPage = await fetch(URL, { - method: "POST", - headers, - body: ICHiddens, -}) - .then((res) => res.text()) - .then(assertNotPageNoLongerAvailable) - .then((page) => { - if ( - page.includes( - "Your search will return over 50 classes, would you like to continue?" - ) - ) { - console.log("over 50 classes found, continuing"); - // TODO: ignore this problem for now and redo the search with a constraint on the course number - // ICHiddensCopy.set("ICAction", "#ICSave"); - // ICHiddensCopy.set("ICAJAX", "1"); - // ICHiddensCopy.set("ICNAVTYPEDROPDOWN", "0"); - // ICHiddensCopy.set("ICBcDomData", "Unknownvalue"); - // ICHiddensCopy.set("ICStateNum", "6"); - // console.log(ICHiddensCopy) - // console.log(headers.get('Cookie')) - return fetch(URL, { - method: "POST", - headers, - body: ICHiddensCopy, - }) - .then((res) => res.text()) - .then(assertNotPageNoLongerAvailable); - } else { - // TODO: check for other messages and handle - return page; - } - }) - .then((page) => { - assert(page.includes("Search Results"), "not on search results page"); - return page; + // execute search + ICHiddens.set("ICAction", "CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"); + const searchResultsPage = await fetch(URL, { + method: "POST", + headers, + body: ICHiddens, }) - .then((page) => { - const $ = cheerio.load(page); - const courses = $("div[id*=win0divSSR_CLSRSLT_WRK_GROUPBOX2\\$]"); - courses.each((i, elem) => { - const name = $(elem).find(".PAGROUPBOXLABELLEVEL1").text().trim(); - console.log(name); - const sections = $(elem).find("span[title=Class\\ Nbr]"); - sections.each((i, elem) => { - const action = $(elem).find("a").attr("id"); - const num = $(elem).text(); - console.log(num); - }); + .then((res) => res.text()) + .then(assertNotPageNoLongerAvailable) + .then((page) => { + if ( + page.includes( + "Your search will return over 50 classes, would you like to continue?" + ) + ) { + console.log("over 50 classes found, continuing"); + // TODO: ignore this problem for now and redo the search with a constraint on the course number + // ICHiddensCopy.set("ICAction", "#ICSave"); + // ICHiddensCopy.set("ICAJAX", "1"); + // ICHiddensCopy.set("ICNAVTYPEDROPDOWN", "0"); + // ICHiddensCopy.set("ICBcDomData", "Unknownvalue"); + // ICHiddensCopy.set("ICStateNum", "6"); + // console.log(ICHiddensCopy) + // console.log(headers.get('Cookie')) + return fetch(URL, { + method: "POST", + headers, + body: ICHiddensCopy, + }) + .then((res) => res.text()) + .then(assertNotPageNoLongerAvailable); + } else { + // TODO: check for other messages and handle + return page; + } + }) + .then((page) => { + assert(page.includes("Search Results"), "not on search results page"); + return page; }); - }); + const $ = cheerio.load(searchResultsPage); + const courses = $("tr[id*=trSSR_CLSRCH_MTG1]"); + return courses + .map((i, elem) => { + const [$num, $title, $dates, $location, $prof, _, $status] = $(elem) + .find("td") + .get(); + const num = parseInt($($num).text().trim()); + const title = $($title).text().trim(); + const dates = $($dates).text().trim(); + const location = $($location).text().trim(); + const prof = $($prof).text().trim(); + const status = $($status) + .find("img") + .attr("src") + .match(/(OPEN)|(CLOSED)|(WAITLIST)/)[0]; + return { num, title, dates, location, prof, status }; + }) + .get(); +}; // TODO: look into this AppServ link
// AppServ is a php/apache/mysql server // ToolsRel is a PeopleSoft/Tools function for formatting the current version diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 7cfc1a9..225919a 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -7,6 +7,7 @@ import { RequirementTypeSchema, RequirementType, scrapeCourseGEFullfillments, + CourseCodeSchema, } from "~/scraping/catalog"; export type { Degree, @@ -21,6 +22,7 @@ import { termCode, } from "~/scraping/registrar"; import { GEArea, GESubArea } from "@prisma/client"; +import { scrapeSections } from "~/scraping/sections_fetch"; const courseType_arr = RequirementTypeSchema.options; @@ -358,6 +360,23 @@ export const appRouter = t.router({ }); } }), + sections: t.procedure + .input(z.object({ courseCode: CourseCodeSchema, quarterId: z.number() })) + .output( + z.array( + z.object({ + num: z.number(), + prof: z.string(), + dates: z.string(), + title: z.string(), + location: z.string(), + status: z.enum(["WAITLIST", "OPEN", "CLOSE"]), + }) + ) + ) + .query(async (input) => { + return await scrapeSections(input.courseCode, input.quarterId); + }), }); // export type definition of API From 0a7ac50eb0221aa6af08d0cadbd5973e0e8dc006 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 9 Jun 2023 03:26:21 -0700 Subject: [PATCH 61/62] oops import the type --- kanban-dashboard/src/server/api/root.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index 225919a..f1a9c74 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -22,7 +22,7 @@ import { termCode, } from "~/scraping/registrar"; import { GEArea, GESubArea } from "@prisma/client"; -import { scrapeSections } from "~/scraping/sections_fetch"; +import { scrapeSections, SectionSchema } from "~/scraping/sections_fetch"; const courseType_arr = RequirementTypeSchema.options; @@ -364,14 +364,7 @@ export const appRouter = t.router({ .input(z.object({ courseCode: CourseCodeSchema, quarterId: z.number() })) .output( z.array( - z.object({ - num: z.number(), - prof: z.string(), - dates: z.string(), - title: z.string(), - location: z.string(), - status: z.enum(["WAITLIST", "OPEN", "CLOSE"]), - }) + SectionSchema ) ) .query(async (input) => { From 68c0fa11eebe25af4dff2a98ddc0e83e12aabd08 Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Fri, 9 Jun 2023 03:30:20 -0700 Subject: [PATCH 62/62] uscp+gwr requirements --- kanban-dashboard/src/server/api/root.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/kanban-dashboard/src/server/api/root.ts b/kanban-dashboard/src/server/api/root.ts index f1a9c74..e5836d7 100644 --- a/kanban-dashboard/src/server/api/root.ts +++ b/kanban-dashboard/src/server/api/root.ts @@ -267,6 +267,24 @@ export const appRouter = t.router({ }, })) ); + courses.push({ + code: "GWR", + id: "GWR", + title: "Graduation Writing Requirement", + courseType: "GWR", + quarterId: randomQuarter(startYear), + units: 4, + groupId: { kind: "GWR", degreeId: input.degreeId }, + }); + courses.push({ + code: "USCP", + id: "USCP", + title: "United States Cultural Pluralism", + courseType: "USCP", + quarterId: randomQuarter(startYear), + units: 4, + groupId: { kind: "USCP", degreeId: input.degreeId }, + }); console.dir(courses, { depth: null }); let courseSet = new Set(courses.map((c) => c.id)); if (courseSet.size !== courses.length) @@ -362,11 +380,7 @@ export const appRouter = t.router({ }), sections: t.procedure .input(z.object({ courseCode: CourseCodeSchema, quarterId: z.number() })) - .output( - z.array( - SectionSchema - ) - ) + .output(z.array(SectionSchema)) .query(async (input) => { return await scrapeSections(input.courseCode, input.quarterId); }),