Add simulator

This commit is contained in:
Jakob Kordež 2023-03-01 20:20:57 +01:00
parent c5d7097dfd
commit 263618f98a
15 changed files with 474 additions and 196 deletions

View File

@ -19,7 +19,7 @@
"bulma": "^0.9.4",
"eslint": "8.34.0",
"eslint-config-next": "13.1.6",
"next": "13.1.7-canary.21",
"next": "^13.2.3",
"node-sass": "^8.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",

View File

@ -1,10 +1,9 @@
"use client";
import { create } from "zustand";
import Exam from "@/components/exam";
import { getQuestions } from "@/util/question-util";
import { PDFViewer, Document } from "@react-pdf/renderer";
import { Document, PDFViewer } from "@react-pdf/renderer";
import { create } from "zustand";
interface IzpitState {
doc: any | null;
@ -14,11 +13,11 @@ const useS = create<IzpitState>((set) => ({
doc: null,
}));
export default function Izpit() {
export default function Generator() {
const doc = useS((s) => s.doc);
return (
<div className="section">
<>
<button className="button is-primary" onClick={generate}>
Ustvari PDF
</button>
@ -34,7 +33,7 @@ export default function Izpit() {
{doc}
</PDFViewer>
)}
</div>
</>
);
}

View File

@ -0,0 +1,23 @@
import { Metadata } from "next";
import Generator from "./generator";
export const metadata: Metadata = {
title: "Generator izpitnih pol",
description: "Pripomoček za generiranje izpitnih pol za radioamaterski izpit",
};
export default function Izpit() {
return (
<div className="section">
<div className="content">
<h1>Generator izpitnih pol</h1>
</div>
<div className="notification is-danger is-light">
<strong>Opomba:</strong> Generator izpitnih pol je še v razvoju.
</div>
<Generator />
</div>
);
}

View File

@ -0,0 +1,147 @@
"use client";
import { Question } from "@/interfaces/question";
import { getExamQuestions } from "@/util/question-util";
import { create } from "zustand";
import QuestionCard from "@/components/question_card";
enum QuizState {
Loading,
Ready,
InProgress,
Finished,
}
interface IzpitQuizStore {
state: QuizState;
questions?: Question[];
answers?: number[][];
correctCount?: number;
load: () => Promise<void>;
finish: (correctCount: number) => Promise<void>;
reset: () => Promise<void>;
}
const useStore = create<IzpitQuizStore>((set) => ({
state: QuizState.Ready,
questions: undefined,
answers: undefined,
correctCount: undefined,
load: async () => {
set({ state: QuizState.Loading });
const questions = await getExamQuestions();
set({
state: QuizState.InProgress,
questions,
answers: Array(questions.length).fill([-1]),
});
},
finish: async (correctCount: number) => {
set({ state: QuizState.Finished, correctCount });
scrollToTop();
},
reset: async () => {
set({ state: QuizState.Ready });
},
}));
export default function IzpitQuiz() {
const [state, questions, answers, correctCount, load, finish, reset] =
useStore((state) => [
state.state,
state.questions,
state.answers,
state.correctCount,
state.load,
state.finish,
state.reset,
]);
return (
<>
{state === QuizState.Ready && (
<div className="is-flex">
<button className="button is-primary mx-auto" onClick={load}>
Začni
</button>
</div>
)}
{state === QuizState.Loading && <div>Pripravljanje ...</div>}
{state === QuizState.InProgress && (
<>
{questions?.map((question, qi) => (
<QuestionCard
key={qi}
question={question}
reveal={false}
selected={answers![qi]}
onClick={(i) => {
const newAnswers = [...answers!];
newAnswers[qi] = [i];
useStore.setState({ answers: newAnswers });
}}
/>
))}
<button
className="button is-primary"
onClick={() =>
finish(
questions!
.map((q, qi) => q.correct === answers![qi][0])
.reduce((acc, cur) => acc + (cur ? 1 : 0), 0)
)
}
>
Zaključi
</button>
</>
)}
{state === QuizState.Finished && (
<>
<div className="box notification is-info is-light is-flex is-flex-direction-column is-align-items-center">
<h2 className="is-size-4">Rezultat</h2>
<p className="is-size-2">
{correctCount} / {answers!.length} (
{Math.round((correctCount! / answers!.length) * 1000) / 10} %)
</p>
<button className="button is-primary mt-3" onClick={reset}>
Nazaj na začetek
</button>
</div>
<h1 className="is-size-3 my-3 has-text-centered">Napačni odgovori</h1>
{questions
?.filter((q, qi) => q.correct !== answers![qi][0])
.map((question, qi) => (
<QuestionCard
key={qi}
question={question}
reveal={true}
selected={[answers![qi][0], question.correct]}
/>
))}
</>
)}
</>
);
}
const isBrowser = () => typeof window !== "undefined";
function scrollToTop() {
if (!isBrowser()) return;
window.scrollTo({ top: 0, behavior: "smooth" });
}

View File

@ -0,0 +1,27 @@
import { Metadata } from "next";
import IzpitQuiz from "./izpit-quiz";
export const metadata: Metadata = {
title: "Simulator izpita",
description: "Pripomoček za simuliranje izpita za radioamaterski izpit",
};
export default function Priprave() {
return (
<div className="section">
<div className="content">
<h1>Simulator izpita</h1>
<p>
Kandidati za radioamaterja razreda A opravljajo izpit, ki je
sestavljen iz <strong>60 različnih vprašanj</strong>. Vsako vprašanje
ima 3 možne odgovore, od katerih je samo en pravilen. Kandidat ima na
voljo 90 minut za reševanje izpitne pole. Kandidat mora{" "}
<strong>pravilno odgovoriti vsaj na 36 vprašanj</strong> (60 %) .
</p>
</div>
<IzpitQuiz />
</div>
);
}

View File

@ -1,15 +1,34 @@
import { AnalyticsWrapper } from "@/components/analytics";
import Header from "@/components/header";
import { Metadata } from "next";
import "@/styles/globals.scss";
export const metadata = {
export const metadata: Metadata = {
title: {
default: "Radioamaterski izpit",
template: "%s | Radioamaterski izpit",
},
description: "Priprave na radioamaterski izpit",
description: "Priprava na radioamaterski izpit",
icons: {
shortcut: "/logo/zrs_logo_white.svg",
icon: "/logo/S5_practice.png",
shortcut: "/logo/S5_practice.png",
},
creator: "Jakob Kordež [S52KJ]",
themeColor: "#2196f3",
openGraph: {
title: "Radioamaterski izpit",
description: "Priprava na radioamaterski izpit",
url: "http://izpit.jkob.cc/",
locale: "sl_SL",
type: "website",
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
},
},
};

View File

@ -1,10 +1,14 @@
import Link from "next/link";
const uporabne_povezave = [
const povezave = [
{
label: "Priročnik za radioamaterje",
label: "Priročnik za radioamaterje (3. izdaja)",
href: "http://www.homemade.net/ra/prirocnik_novi.pdf",
},
{
label: "Priročnik za radioamaterje (2. izdaja)",
href: "https://www.radioamater.si/wp-content/uploads/2016/01/prirocnik-za-radioamaterje_2izd.pdf",
},
{
label: "Etika in operaterski postopki",
href: "http://www.hamradio.si/images/dokumenti/publikacije/etika_junij%202021.pdf",
@ -13,14 +17,14 @@ const uporabne_povezave = [
label: "Izpitni roki ZRS",
href: "http://www.hamradio.si/index.php?option=com_content&view=article&id=677&Itemid=118",
},
{
label: "Seznam zasedenih klicnih znakov",
href: "https://www.akos-rs.si/registri/seznam-registrov/radioamaterji",
},
{
label: "Kriteriji za izpit",
href: "https://zrs.si/files/kriteriji.pdf",
},
{
label: "Seznam zasedenih klicnih znakov",
href: "https://www.akos-rs.si/registri/seznam-registrov/radioamaterji",
},
];
export default function Home() {
@ -28,25 +32,20 @@ export default function Home() {
<div className="section content">
<h1>Pozdravljen!</h1>
<p>
Ta spletna stran je namenjena pripravi na radioamaterski izpit. Na njej
najdete vse potrebne informacije, ki jih potrebujete za pripravo na
izpit. Vsebina je zasnovana tako, da je lahko dostopna tudi za
neizkušene radioamaterje.
Na podstrani <Link href="/priprave">Priprave</Link> so vaje za pripravo
na izpit. Vprašanja so razdeljena po kategorijah, pravilni odgovori pa
se razkrivajo sproti.
</p>
<h2>Kaj je radioamaterski izpit?</h2>
<p>
Radioamaterski izpit je izpit, ki ga mora opraviti vsak, ki želi postati
radioamater. Izpit je sestavljen iz dveh delov: teoretičnega in
praktičnega dela. Teoretični del izpita je sestavljen iz 50 vprašanj, od
katerih je potrebno odgovoriti na 40 pravilno. Praktični del izpita pa
je sestavljen iz 3 delov: izdelava antene, izdelava sprejemnika in
izdelava oddajnika. Vse tri naloge mora opraviti v 30 minutah.
Na podstrani <Link href="/izpit-sim">Simulator izpita</Link> lahko
preizkusiš svoje znanje. Vprašanja so generirana kot bi bila na
resničnem izpitu. Pravilni odgovori se razkrijejo šele po koncu.
</p>
<h2>Uporabne povezave</h2>
<ul className="list-inside list-disc">
{uporabne_povezave.map(({ label, href }) => (
{povezave.map(({ label, href }) => (
<li key={label}>
<Link href={href}>{label}</Link>
</li>

View File

@ -1,34 +1,18 @@
import Quiz from "@/components/quiz";
import { Category } from "@/interfaces/category";
import { Question } from "@/interfaces/question";
import { Metadata } from "next";
import VajaQuiz from "./vaja-quiz";
interface QuizStore {
isLoading: boolean;
categories: Category[];
selectedCategory: string;
questions: Question[];
answers: number[][];
displayed: number;
loadMore: () => void;
}
export const metadata: Metadata = {
title: "Priprave na izpit",
};
export default function Priprave() {
return (
<div className="section">
<div className="content mb-6">
<div className="content">
<h1>Priprave na izpit</h1>
<p>
Priprave na radioamaterski izpit so namenjene vsem, ki želijo postati
radioamaterji. Priprave so brezplačne in potekajo v prostorih Zveze
radioamaterjev Slovenije (ZRS) v Ljubljani. Priprave so namenjene tudi
tistim, ki so že opravili izpit, vendar se želijo pripraviti na
nadaljnje izpite.
</p>
</div>
<Quiz />
<VajaQuiz />
</div>
);
}

View File

@ -4,10 +4,8 @@ import { Question } from "@/interfaces/question";
import { getCategories, getQuestions } from "@/util/question-util";
import { useEffect } from "react";
import { create } from "zustand";
import styles from "@/styles/Quiz.module.scss";
import { Category } from "@/interfaces/category";
import { InlineMath } from "react-katex";
import Image from "next/image";
import QuestionCard from "@/components/question_card";
const qPerPage = 5;
@ -59,7 +57,7 @@ async function load(selectedCategory: string) {
});
}
export default function Quiz() {
export default function VajaQuiz() {
const [
isLoading,
categories,
@ -120,64 +118,21 @@ export default function Quiz() {
<div>
{questions.slice(0, displayed).map((question, qi) => (
<div key={qi} className="box">
<p>{question.id}</p>
<div className="title is-4">
<h3>{question.question}</h3>
</div>
{question.image && (
<figure className="image">
<Image
className={styles.image}
src={`/question_images/${question.image}`}
alt={question.image}
height={500}
width={500}
/>
</figure>
)}
<div className="buttons mt-5">
{question.answers.map((answer, i) => {
const revealed = answers[qi].includes(i);
const isCorrect = question.correct === i;
const isDone = answers[qi].includes(question.correct!);
const onClick = () => {
if (answers[qi].includes(i)) return;
const answersNew = Array.from(answers);
answersNew[qi] = Array.from(answers[qi]);
answersNew[qi].push(i);
useStore.setState({ answers: answersNew });
};
return (
<button
key={i}
className={`button is-fullwidth ${styles.answer} ${
revealed
? isCorrect
? "is-success is-light is-static"
: "is-danger is-light is-static"
: isDone && "is-static"
}`}
onClick={onClick}
>
{String.fromCharCode(65 + i) + ". "}
{answer.startsWith("$") ? (
<span className="ml-2">
<InlineMath math={answer.slice(1, answer.length - 1)} />
</span>
) : (
answer
)}
</button>
);
})}
</div>
</div>
<QuestionCard
key={qi}
question={question}
reveal={true}
selected={answers[qi]}
onClick={
answers[qi].includes(question.correct)
? undefined
: (i) => {
const newAnswers = [...answers];
newAnswers[qi] = [...newAnswers[qi], i];
useStore.setState({ answers: newAnswers });
}
}
/>
))}
</div>

View File

@ -7,7 +7,8 @@ import { usePathname } from "next/navigation";
const nav = [
{ href: "/", label: "Domov" },
{ href: "/priprave", label: "Priprave" },
{ href: "/izpit", label: "Izpit" },
{ href: "/izpit-sim", label: "Simulator izpita" },
// { href: "/izpit-gen", label: "Generator izpitnih pol" },
];
export default function Header() {
@ -20,8 +21,8 @@ export default function Header() {
<div className="is-flex is-align-items-center">
<figure className="image is-96x96">
<Image
src="/logo/zrs_logo_white.svg"
alt="ZRS Logo"
src="/logo/S5_practice_front.png"
alt="Logo"
width={100}
height={100}
/>

View File

@ -0,0 +1,96 @@
import { Question } from "@/interfaces/question";
import { InlineMath } from "react-katex";
import styles from "@/styles/Quiz.module.scss";
import Image from "next/image";
interface QuestionCardProps {
question: Question;
reveal: boolean;
selected: number[];
onClick?: (answer: number) => void;
}
export default function QuestionCard({
question,
reveal,
selected,
onClick,
}: QuestionCardProps) {
return (
<div className="box">
<p>{question.id}</p>
<div className="title is-4">
<h3>{question.question}</h3>
</div>
{question.image && (
<figure className="image">
<Image
className={styles.image}
src={`/question_images/${question.image}`}
alt={question.image}
height={500}
width={500}
/>
</figure>
)}
<div className="buttons mt-5">
{question.answers.map((answer, i) => (
<Answer
key={i}
index={i}
answer={answer}
reveal={reveal}
isCorrect={question.correct === i}
isSelected={selected.includes(i)}
onClick={!onClick ? undefined : () => onClick(i)}
/>
))}
</div>
</div>
);
}
interface AnswerProps {
index: number;
answer: string;
reveal: boolean;
isCorrect: boolean;
isSelected: boolean;
onClick?: () => void;
}
function Answer({
index,
answer,
reveal,
isCorrect,
isSelected,
onClick,
}: AnswerProps) {
let className = `button is-fullwidth ${styles.answer}`;
if (!onClick) className += " is-static";
if (isSelected) {
if (reveal) {
if (isCorrect) className += " is-success is-light";
else className += " is-danger is-light";
} else {
className += " is-info";
}
}
return (
<button className={className} onClick={onClick}>
{String.fromCharCode(65 + index) + ". "}
{answer.startsWith("$") ? (
<span className="ml-2">
<InlineMath math={answer.slice(1, answer.length - 1)} />
</span>
) : (
answer
)}
</button>
);
}

View File

@ -1,7 +1,7 @@
$primary: #03a9f4;
$primary: #2196f3;
$container-max-width: 1200px;
$section-padding: 2rem 1.5rem;
$body-font-size: 1.1em;
@import "bulma/sass/utilities/_all.sass";
@import "bulma/sass/base/_all.sass";

View File

@ -38,3 +38,17 @@ export const getCategories = async (): Promise<Category[]> => {
questions: category.questions,
}));
};
export const getExamQuestions = async (
count: number = 60
): Promise<Question[]> => {
let questions = await getQuestions();
// TODO Correct
// Shuffle questions
questions.sort(() => Math.random() - 0.5);
questions = questions.slice(0, count);
questions.sort((a, b) => a.id - b.id);
return questions;
};

View File

@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@ -21,9 +25,19 @@
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
"@/*": [
"./src/*"
]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"C:\\Users\\Jakob\\Documents\\Ham\\s5_practice\\.next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}

148
yarn.lock
View File

@ -69,10 +69,10 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@next/env@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.1.7-canary.21.tgz#36db6a4e369c5967c9211382063508c477ee37c3"
integrity sha512-w5ZByxFUXzAC15KwVaOQ2/AkD9BgM6xXxCshr7M7qZDert7Z62SevuxIqrrIFTEj5psLPTT7WHlJufY8JXLGXg==
"@next/env@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.2.3.tgz#77ca49edb3c1d7c5263bb8f2ebe686080e98279e"
integrity sha512-FN50r/E+b8wuqyRjmGaqvqNDuWBWYWQiigfZ50KnSFH0f+AMQQyaZl+Zm2+CIpKk0fL9QxhLxOpTVA3xFHgFow==
"@next/eslint-plugin-next@13.1.6":
version "13.1.6"
@ -86,70 +86,70 @@
resolved "https://registry.yarnpkg.com/@next/font/-/font-13.1.6.tgz#2bf99e3321ec9b4d65781c0d0ebff072e8752e1a"
integrity sha512-AITjmeb1RgX1HKMCiA39ztx2mxeAyxl4ljv2UoSBUGAbFFMg8MO7YAvjHCgFhD39hL7YTbFjol04e/BPBH5RzQ==
"@next/swc-android-arm-eabi@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.7-canary.21.tgz#a82bdf7b189075c550104c8598b2286ebce98188"
integrity sha512-DPHm1aY/+1+TgZhRJXxspKExvwIdONC6ZHCLaU8xhqKEuojZbkwYiB8wG/qukhwy/6H2G8O9jD5qzbkWZQdt8w==
"@next/swc-android-arm-eabi@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.3.tgz#85eed560c87c7996558c868a117be9780778f192"
integrity sha512-mykdVaAXX/gm+eFO2kPeVjnOCKwanJ9mV2U0lsUGLrEdMUifPUjiXKc6qFAIs08PvmTMOLMNnUxqhGsJlWGKSw==
"@next/swc-android-arm64@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.1.7-canary.21.tgz#a651920e1c64babfa637e518936670195f078119"
integrity sha512-Oglp5AGW69iF0M7ELqzUSD2AJJZDYcF88EpxgnG43iE6NkylWZQl9aFW05C6lb4h28YALnopdN8NMQxexomXeQ==
"@next/swc-android-arm64@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.2.3.tgz#8ac54ca9795a48afc4631b4823a4864bd5db0129"
integrity sha512-8XwHPpA12gdIFtope+n9xCtJZM3U4gH4vVTpUwJ2w1kfxFmCpwQ4xmeGSkR67uOg80yRMuF0h9V1ueo05sws5w==
"@next/swc-darwin-arm64@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.7-canary.21.tgz#87bc8098671ba7ce44fc50096ee784df5f31f988"
integrity sha512-SAPqhUGAco0DIIGpV0Kr7bQ3IjbDISdvGoYcY38BB7xd2Gv2TynQezNcZtX2NZ7RI30tyxRxUspIQsf958d2oQ==
"@next/swc-darwin-arm64@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.3.tgz#f674e3c65aec505b6d218a662ade3fe248ccdbda"
integrity sha512-TXOubiFdLpMfMtaRu1K5d1I9ipKbW5iS2BNbu8zJhoqrhk3Kp7aRKTxqFfWrbliAHhWVE/3fQZUYZOWSXVQi1w==
"@next/swc-darwin-x64@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.7-canary.21.tgz#64cdee1c1e30cdd38124110c2000f5c6bc59924e"
integrity sha512-OinLF0EP6xWCSq8CMgqCb0KdsrjkdPp/+CNURTjFEYMc9jkp5C6lLhjVK2hIs0b9vlcsdhDmDmYYr0kxenFiuQ==
"@next/swc-darwin-x64@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.3.tgz#a15ea7fb4c46034a8f5e387906d0cad08387075a"
integrity sha512-GZctkN6bJbpjlFiS5pylgB2pifHvgkqLAPumJzxnxkf7kqNm6rOGuNjsROvOWVWXmKhrzQkREO/WPS2aWsr/yw==
"@next/swc-freebsd-x64@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.7-canary.21.tgz#36b2ff13cfb98e055687dd11df79da10e02ed7c7"
integrity sha512-OSvPwS0v9CuQQyX57stm+nGF5qXvOUISlR5HfrI4igP4dCRzJ9Fb4WSH12P75GV9fcjJxzJiDZlzaWzPh9ZJbA==
"@next/swc-freebsd-x64@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.3.tgz#f7ac6ae4f7d706ff2431f33e40230a554c8c2cbc"
integrity sha512-rK6GpmMt/mU6MPuav0/M7hJ/3t8HbKPCELw/Uqhi4732xoq2hJ2zbo2FkYs56y6w0KiXrIp4IOwNB9K8L/q62g==
"@next/swc-linux-arm-gnueabihf@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.7-canary.21.tgz#2fe5dc4a88d49002a88fe2005f0efd051f295de3"
integrity sha512-83Frp3/WIEOrzirGYR8aCwTYhtT23IgpOZyGOruZNic8JmCZruk/c5FvekYbE+UCglsNXllZEJJ7c/Vhe4lm0A==
"@next/swc-linux-arm-gnueabihf@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.3.tgz#84ad9e9679d55542a23b590ad9f2e1e9b2df62f7"
integrity sha512-yeiCp/Odt1UJ4KUE89XkeaaboIDiVFqKP4esvoLKGJ0fcqJXMofj4ad3tuQxAMs3F+qqrz9MclqhAHkex1aPZA==
"@next/swc-linux-arm64-gnu@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.7-canary.21.tgz#26eaec172178518d5ad4fde48d18660d1baf8b93"
integrity sha512-REKwi3MkTHnDwwxn2rl4RkiJ/vOs2+wP0U+p0hhZeSUfBh43a/+MShZ5BLUDlM+Uec25UHp1QWMBq/EQ5TQG+g==
"@next/swc-linux-arm64-gnu@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.3.tgz#56f9175bc632d647c60b9e8bedc0875edf92d8b7"
integrity sha512-/miIopDOUsuNlvjBjTipvoyjjaxgkOuvlz+cIbbPcm1eFvzX2ltSfgMgty15GuOiR8Hub4FeTSiq3g2dmCkzGA==
"@next/swc-linux-arm64-musl@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.7-canary.21.tgz#71413b4492e91849612d004d46bb69f114930fcb"
integrity sha512-FCBfNRQc3GbHku/T33zMUV3e8WQwF4FK42t0hlW0sCckkJ+0r/7J/8/3uoX621msTtYiwrndIySqoqP+jbtSyg==
"@next/swc-linux-arm64-musl@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.3.tgz#7d4cf00e8f1729a3de464da0624773f5d0d14888"
integrity sha512-sujxFDhMMDjqhruup8LLGV/y+nCPi6nm5DlFoThMJFvaaKr/imhkXuk8uCTq4YJDbtRxnjydFv2y8laBSJVC2g==
"@next/swc-linux-x64-gnu@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.7-canary.21.tgz#22741be76b2b6bd749a1acf900e1d55205840de2"
integrity sha512-9+e/YU8kOGcKYqrDqSFztrSrF1BFoDnwn2wiev7egBRgOqYHGsG2ZScA+tZLn3at5wtCXyrbEO1NR0sFgrrHJA==
"@next/swc-linux-x64-gnu@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.3.tgz#17de404910c4ebf7a1d366b19334d7e27e126ab0"
integrity sha512-w5MyxPknVvC9LVnMenAYMXMx4KxPwXuJRMQFvY71uXg68n7cvcas85U5zkdrbmuZ+JvsO5SIG8k36/6X3nUhmQ==
"@next/swc-linux-x64-musl@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.7-canary.21.tgz#6d6b5a70f7557b1a262b6b6d2101708f5a5c5a9a"
integrity sha512-XF5y8WKUJHB5uDPYiHqQ7es27wV7lw1BC9DCIzS+TbGJgUhsiSue1w3cS1YYEqxdF7kbeYNOLRwsQ/3+NsPPow==
"@next/swc-linux-x64-musl@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.3.tgz#07cb7b7f3a3a98034e2533f82638a9b099ba4ab1"
integrity sha512-CTeelh8OzSOVqpzMFMFnVRJIFAFQoTsI9RmVJWW/92S4xfECGcOzgsX37CZ8K982WHRzKU7exeh7vYdG/Eh4CA==
"@next/swc-win32-arm64-msvc@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.7-canary.21.tgz#1592626be2d0996479b8c8208256fffca06a574e"
integrity sha512-uJWP0qc2B+PBmedV/CF5sR9WRxrVQ1do2AV3mJLPPQqFFoG0UnTW7bRm+IT+u/MFWFmll2zsNFoXwL3utWFDEg==
"@next/swc-win32-arm64-msvc@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.3.tgz#b9ac98c954c71ec9de45d3497a8585096b873152"
integrity sha512-7N1KBQP5mo4xf52cFCHgMjzbc9jizIlkTepe9tMa2WFvEIlKDfdt38QYcr9mbtny17yuaIw02FXOVEytGzqdOQ==
"@next/swc-win32-ia32-msvc@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.7-canary.21.tgz#115c15788571ebc716cd488485870a5dcd914072"
integrity sha512-iz/kTKBQaDxxcP/qhddZF77DLj53I/JkLiSSnkseuRI7949tPOGfmTu9JHyR8xBP+d3Br/fj9/oIQ2ipQ/U6Aw==
"@next/swc-win32-ia32-msvc@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.3.tgz#5ec48653a48fd664e940c69c96bba698fdae92eb"
integrity sha512-LzWD5pTSipUXTEMRjtxES/NBYktuZdo7xExJqGDMnZU8WOI+v9mQzsmQgZS/q02eIv78JOCSemqVVKZBGCgUvA==
"@next/swc-win32-x64-msvc@13.1.7-canary.21":
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.7-canary.21.tgz#29030372bb9dd10036245ab957b2343320544af4"
integrity sha512-jSVNfA3cTAO+cBL8RMtiXJrk1G4eGMaYmtTRs1RS15QtIrbqExzeLlDkiGFKx/QGpakgxro3t+YefETSb9QDSA==
"@next/swc-win32-x64-msvc@13.2.3":
version "13.2.3"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.3.tgz#cd432f280beb8d8de5b7cd2501e9f502e9f3dd72"
integrity sha512-aLG2MaFs4y7IwaMTosz2r4mVbqRyCnMoFqOcmfTi7/mAS+G4IMH0vJp4oLdbshqiVoiVuKrAfqtXj55/m7Qu1Q==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@ -2494,30 +2494,30 @@ negotiator@^0.6.2, negotiator@^0.6.3:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
next@13.1.7-canary.21:
version "13.1.7-canary.21"
resolved "https://registry.yarnpkg.com/next/-/next-13.1.7-canary.21.tgz#eb795fe5c3d2393394cb67c3623f2a8db07a9e9d"
integrity sha512-uuPJG7XESnr5xupNumU61udF2ApiH+MP7Cc7CfL1zEzhqJGIEscI4BZZcv3QTSPgy9c3CNJoxuYxaa1DQ8tzmQ==
next@^13.2.3:
version "13.2.3"
resolved "https://registry.yarnpkg.com/next/-/next-13.2.3.tgz#92d170e7aca421321f230ff80c35c4751035f42e"
integrity sha512-nKFJC6upCPN7DWRx4+0S/1PIOT7vNlCT157w9AzbXEgKy6zkiPKEt5YyRUsRZkmpEqBVrGgOqNfwecTociyg+w==
dependencies:
"@next/env" "13.1.7-canary.21"
"@next/env" "13.2.3"
"@swc/helpers" "0.4.14"
caniuse-lite "^1.0.30001406"
postcss "8.4.14"
styled-jsx "5.1.1"
optionalDependencies:
"@next/swc-android-arm-eabi" "13.1.7-canary.21"
"@next/swc-android-arm64" "13.1.7-canary.21"
"@next/swc-darwin-arm64" "13.1.7-canary.21"
"@next/swc-darwin-x64" "13.1.7-canary.21"
"@next/swc-freebsd-x64" "13.1.7-canary.21"
"@next/swc-linux-arm-gnueabihf" "13.1.7-canary.21"
"@next/swc-linux-arm64-gnu" "13.1.7-canary.21"
"@next/swc-linux-arm64-musl" "13.1.7-canary.21"
"@next/swc-linux-x64-gnu" "13.1.7-canary.21"
"@next/swc-linux-x64-musl" "13.1.7-canary.21"
"@next/swc-win32-arm64-msvc" "13.1.7-canary.21"
"@next/swc-win32-ia32-msvc" "13.1.7-canary.21"
"@next/swc-win32-x64-msvc" "13.1.7-canary.21"
"@next/swc-android-arm-eabi" "13.2.3"
"@next/swc-android-arm64" "13.2.3"
"@next/swc-darwin-arm64" "13.2.3"
"@next/swc-darwin-x64" "13.2.3"
"@next/swc-freebsd-x64" "13.2.3"
"@next/swc-linux-arm-gnueabihf" "13.2.3"
"@next/swc-linux-arm64-gnu" "13.2.3"
"@next/swc-linux-arm64-musl" "13.2.3"
"@next/swc-linux-x64-gnu" "13.2.3"
"@next/swc-linux-x64-musl" "13.2.3"
"@next/swc-win32-arm64-msvc" "13.2.3"
"@next/swc-win32-ia32-msvc" "13.2.3"
"@next/swc-win32-x64-msvc" "13.2.3"
node-fetch@2.6.7:
version "2.6.7"