fengmuxi commited on
Commit
9c10adf
1 Parent(s): dfafc09

维护更新

Browse files
.github/workflows/sync.yml CHANGED
@@ -5,7 +5,7 @@ permissions:
5
 
6
  on:
7
  schedule:
8
- - cron: "0 * * * *" # every hour
9
  workflow_dispatch:
10
 
11
  jobs:
 
5
 
6
  on:
7
  schedule:
8
+ - cron: "0 0 * * *" # every hour
9
  workflow_dispatch:
10
 
11
  jobs:
app/api/common.ts CHANGED
@@ -26,7 +26,7 @@ export async function requestOpenai(req: NextRequest) {
26
  }
27
 
28
  if (!authValue || !authValue.startsWith("Bearer sk-")) {
29
- console.error("[OpenAI Request] invlid api key provided", authValue);
30
  }
31
 
32
  return fetch(`${baseUrl}/${openaiPath}`, {
 
26
  }
27
 
28
  if (!authValue || !authValue.startsWith("Bearer sk-")) {
29
+ console.error("[OpenAI Request] invalid api key provided", authValue);
30
  }
31
 
32
  return fetch(`${baseUrl}/${openaiPath}`, {
app/api/config/route.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NextRequest, NextResponse } from "next/server";
2
 
3
  import { getServerSideConfig } from "../../config/server";
4
 
@@ -9,6 +9,7 @@ const serverConfig = getServerSideConfig();
9
  const DANGER_CONFIG = {
10
  needCode: serverConfig.needCode,
11
  hideUserApiKey: serverConfig.hideUserApiKey,
 
12
  };
13
 
14
  declare global {
 
1
+ import { NextResponse } from "next/server";
2
 
3
  import { getServerSideConfig } from "../../config/server";
4
 
 
9
  const DANGER_CONFIG = {
10
  needCode: serverConfig.needCode,
11
  hideUserApiKey: serverConfig.hideUserApiKey,
12
+ enableGPT4: serverConfig.enableGPT4,
13
  };
14
 
15
  declare global {
app/command.ts ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useSearchParams } from "react-router-dom";
2
+
3
+ type Command = (param: string) => void;
4
+ interface Commands {
5
+ fill?: Command;
6
+ submit?: Command;
7
+ mask?: Command;
8
+ }
9
+
10
+ export function useCommand(commands: Commands = {}) {
11
+ const [searchParams, setSearchParams] = useSearchParams();
12
+
13
+ if (commands === undefined) return;
14
+
15
+ let shouldUpdate = false;
16
+ searchParams.forEach((param, name) => {
17
+ const commandName = name as keyof Commands;
18
+ if (typeof commands[commandName] === "function") {
19
+ commands[commandName]!(param);
20
+ searchParams.delete(name);
21
+ shouldUpdate = true;
22
+ }
23
+ });
24
+
25
+ if (shouldUpdate) {
26
+ setSearchParams(searchParams);
27
+ }
28
+ }
app/components/chat.tsx CHANGED
@@ -26,12 +26,10 @@ import {
26
  SubmitKey,
27
  useChatStore,
28
  BOT_HELLO,
29
- ROLES,
30
  createMessage,
31
  useAccessStore,
32
  Theme,
33
  useAppConfig,
34
- ModelConfig,
35
  DEFAULT_TOPIC,
36
  } from "../store";
37
 
@@ -55,14 +53,11 @@ import chatStyle from "./chat.module.scss";
55
 
56
  import { ListItem, Modal, showModal } from "./ui-lib";
57
  import { useLocation, useNavigate } from "react-router-dom";
58
- import { Path } from "../constant";
59
  import { Avatar } from "./emoji";
60
  import { MaskAvatar, MaskConfig } from "./mask";
61
- import {
62
- DEFAULT_MASK_AVATAR,
63
- DEFAULT_MASK_ID,
64
- useMaskStore,
65
- } from "../store/mask";
66
 
67
  const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
68
  loading: () => <LoadingIcon />,
@@ -479,11 +474,11 @@ export function Chat() {
479
  };
480
 
481
  // submit user input
482
- const onUserSubmit = () => {
483
  if (userInput.trim() === "") return;
484
  setIsLoading(true);
485
  chatStore.onUserInput(userInput).then(() => setIsLoading(false));
486
- setBeforeInput(userInput);
487
  setUserInput("");
488
  setPromptHints([]);
489
  if (!isMobileScreen) inputRef.current?.focus();
@@ -497,22 +492,18 @@ export function Chat() {
497
 
498
  // check if should send message
499
  const onInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
500
- // if ArrowUp and no userInput
501
  if (e.key === "ArrowUp" && userInput.length <= 0) {
502
- setUserInput(beforeInput);
503
  e.preventDefault();
504
  return;
505
  }
506
  if (shouldSubmit(e)) {
507
- onUserSubmit();
508
  e.preventDefault();
509
  }
510
  };
511
  const onRightClick = (e: any, message: Message) => {
512
- // auto fill user input
513
- if (message.role === "user") {
514
- setUserInput(message.content);
515
- }
516
 
517
  // copy to clipboard
518
  if (selectOrCopy(e.currentTarget, message.content)) {
@@ -617,7 +608,12 @@ export function Chat() {
617
  const location = useLocation();
618
  const isChat = location.pathname === Path.Chat;
619
  const autoFocus = !isMobileScreen || isChat; // only focus in chat page
620
-
 
 
 
 
 
621
  return (
622
  <div className={styles.chat} key={session.id}>
623
  <div className="window-header">
@@ -816,7 +812,7 @@ export function Chat() {
816
  text={Locale.Chat.Send}
817
  className={styles["chat-input-send"]}
818
  type="primary"
819
- onClick={onUserSubmit}
820
  />
821
  </div>
822
  </div>
 
26
  SubmitKey,
27
  useChatStore,
28
  BOT_HELLO,
 
29
  createMessage,
30
  useAccessStore,
31
  Theme,
32
  useAppConfig,
 
33
  DEFAULT_TOPIC,
34
  } from "../store";
35
 
 
53
 
54
  import { ListItem, Modal, showModal } from "./ui-lib";
55
  import { useLocation, useNavigate } from "react-router-dom";
56
+ import { LAST_INPUT_KEY, Path } from "../constant";
57
  import { Avatar } from "./emoji";
58
  import { MaskAvatar, MaskConfig } from "./mask";
59
+ import { useMaskStore } from "../store/mask";
60
+ import { useCommand } from "../command";
 
 
 
61
 
62
  const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
63
  loading: () => <LoadingIcon />,
 
474
  };
475
 
476
  // submit user input
477
+ const doSubmit = (userInput: string) => {
478
  if (userInput.trim() === "") return;
479
  setIsLoading(true);
480
  chatStore.onUserInput(userInput).then(() => setIsLoading(false));
481
+ localStorage.setItem(LAST_INPUT_KEY, userInput);
482
  setUserInput("");
483
  setPromptHints([]);
484
  if (!isMobileScreen) inputRef.current?.focus();
 
492
 
493
  // check if should send message
494
  const onInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
495
+ // if ArrowUp and no userInput, fill with last input
496
  if (e.key === "ArrowUp" && userInput.length <= 0) {
497
+ setUserInput(localStorage.getItem(LAST_INPUT_KEY) ?? "");
498
  e.preventDefault();
499
  return;
500
  }
501
  if (shouldSubmit(e)) {
502
+ doSubmit(userInput);
503
  e.preventDefault();
504
  }
505
  };
506
  const onRightClick = (e: any, message: Message) => {
 
 
 
 
507
 
508
  // copy to clipboard
509
  if (selectOrCopy(e.currentTarget, message.content)) {
 
608
  const location = useLocation();
609
  const isChat = location.pathname === Path.Chat;
610
  const autoFocus = !isMobileScreen || isChat; // only focus in chat page
611
+ useCommand({
612
+ fill: setUserInput,
613
+ submit: (text) => {
614
+ doSubmit(text);
615
+ },
616
+ });
617
  return (
618
  <div className={styles.chat} key={session.id}>
619
  <div className="window-header">
 
812
  text={Locale.Chat.Send}
813
  className={styles["chat-input-send"]}
814
  type="primary"
815
+ onClick={() => doSubmit(userInput)}
816
  />
817
  </div>
818
  </div>
app/components/home.module.scss CHANGED
@@ -335,6 +335,7 @@
335
  padding: 20px;
336
  padding-bottom: 40px;
337
  position: relative;
 
338
  }
339
 
340
  .chat-body-title {
 
335
  padding: 20px;
336
  padding-bottom: 40px;
337
  position: relative;
338
+ overscroll-behavior: none;
339
  }
340
 
341
  .chat-body-title {
app/components/home.tsx CHANGED
@@ -23,6 +23,7 @@ import {
23
  } from "react-router-dom";
24
  import { SideBar } from "./sidebar";
25
  import { useAppConfig } from "../store/config";
 
26
 
27
  export function Loading(props: { noLogo?: boolean }) {
28
  return (
 
23
  } from "react-router-dom";
24
  import { SideBar } from "./sidebar";
25
  import { useAppConfig } from "../store/config";
26
+ import { useMaskStore } from "../store/mask";
27
 
28
  export function Loading(props: { noLogo?: boolean }) {
29
  return (
app/components/markdown.tsx CHANGED
@@ -5,15 +5,68 @@ import RemarkBreaks from "remark-breaks";
5
  import RehypeKatex from "rehype-katex";
6
  import RemarkGfm from "remark-gfm";
7
  import RehypeHighlight from "rehype-highlight";
 
8
  import { useRef, useState, RefObject, useEffect } from "react";
9
  import { copyToClipboard } from "../utils";
10
 
11
  import LoadingIcon from "../icons/three-dots.svg";
12
  import React from "react";
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  export function PreCode(props: { children: any }) {
15
  const ref = useRef<HTMLPreElement>(null);
 
 
 
 
 
 
 
 
 
16
 
 
 
 
17
  return (
18
  <pre ref={ref}>
19
  <span
@@ -82,10 +135,12 @@ export function Markdown(
82
  const parentBounds = parent.getBoundingClientRect();
83
  const twoScreenHeight = Math.max(500, parentBounds.height * 2);
84
  const mdBounds = md.getBoundingClientRect();
85
- const isInRange = (x: number) =>
86
- x <= parentBounds.bottom + twoScreenHeight &&
87
- x >= parentBounds.top - twoScreenHeight;
88
- inView.current = isInRange(mdBounds.top) || isInRange(mdBounds.bottom);
 
 
89
  }
90
 
91
  if (inView.current && md) {
@@ -96,7 +151,7 @@ export function Markdown(
96
  }
97
  };
98
 
99
- checkInView();
100
 
101
  return (
102
  <div
 
5
  import RehypeKatex from "rehype-katex";
6
  import RemarkGfm from "remark-gfm";
7
  import RehypeHighlight from "rehype-highlight";
8
+ import mermaid from "mermaid";
9
  import { useRef, useState, RefObject, useEffect } from "react";
10
  import { copyToClipboard } from "../utils";
11
 
12
  import LoadingIcon from "../icons/three-dots.svg";
13
  import React from "react";
14
 
15
+ export function Mermaid(props: { code: string; onError: () => void }) {
16
+ const ref = useRef<HTMLDivElement>(null);
17
+
18
+ useEffect(() => {
19
+ if (props.code && ref.current) {
20
+ mermaid
21
+ .run({
22
+ nodes: [ref.current],
23
+ })
24
+ .catch((e) => {
25
+ props.onError();
26
+ console.error("[Mermaid] ", e.message);
27
+ });
28
+ }
29
+ }, [props.code]);
30
+
31
+ function viewSvgInNewWindow() {
32
+ const svg = ref.current?.querySelector("svg");
33
+ if (!svg) return;
34
+ const text = new XMLSerializer().serializeToString(svg);
35
+ const blob = new Blob([text], { type: "image/svg+xml" });
36
+ const url = URL.createObjectURL(blob);
37
+ const win = window.open(url);
38
+ if (win) {
39
+ win.onload = () => URL.revokeObjectURL(url);
40
+ }
41
+ }
42
+
43
+ return (
44
+ <div
45
+ className="no-dark"
46
+ style={{ cursor: "pointer", overflow: "auto" }}
47
+ ref={ref}
48
+ onClick={() => viewSvgInNewWindow()}
49
+ >
50
+ {props.code}
51
+ </div>
52
+ );
53
+ }
54
+
55
  export function PreCode(props: { children: any }) {
56
  const ref = useRef<HTMLPreElement>(null);
57
+ const [mermaidCode, setMermaidCode] = useState("");
58
+
59
+ useEffect(() => {
60
+ if (!ref.current) return;
61
+ const mermaidDom = ref.current.querySelector("code.language-mermaid");
62
+ if (mermaidDom) {
63
+ setMermaidCode((mermaidDom as HTMLElement).innerText);
64
+ }
65
+ }, [props.children]);
66
 
67
+ if (mermaidCode) {
68
+ return <Mermaid code={mermaidCode} onError={() => setMermaidCode("")} />;
69
+ }
70
  return (
71
  <pre ref={ref}>
72
  <span
 
135
  const parentBounds = parent.getBoundingClientRect();
136
  const twoScreenHeight = Math.max(500, parentBounds.height * 2);
137
  const mdBounds = md.getBoundingClientRect();
138
+ const parentTop = parentBounds.top - twoScreenHeight;
139
+ const parentBottom = parentBounds.bottom + twoScreenHeight;
140
+ const isOverlap =
141
+ Math.max(parentTop, mdBounds.top) <=
142
+ Math.min(parentBottom, mdBounds.bottom);
143
+ inView.current = isOverlap;
144
  }
145
 
146
  if (inView.current && md) {
 
151
  }
152
  };
153
 
154
+ setTimeout(() => checkInView(), 1);
155
 
156
  return (
157
  <div
app/components/mask.tsx CHANGED
@@ -14,13 +14,13 @@ import CopyIcon from "../icons/copy.svg";
14
 
15
  import { DEFAULT_MASK_AVATAR, Mask, useMaskStore } from "../store/mask";
16
  import { Message, ModelConfig, ROLES, useChatStore } from "../store";
17
- import { Input, List, ListItem, Modal, Popover, showToast } from "./ui-lib";
18
  import { Avatar, AvatarPicker } from "./emoji";
19
  import Locale, { AllLangs, Lang } from "../locales";
20
  import { useNavigate } from "react-router-dom";
21
 
22
  import chatStyle from "./chat.module.scss";
23
- import { useEffect, useState } from "react";
24
  import { downloadAs, readFromFile } from "../utils";
25
  import { Updater } from "../api/openai/typing";
26
  import { ModelConfigList } from "./model-config";
@@ -106,6 +106,59 @@ export function MaskConfig(props: {
106
  );
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  export function ContextPrompts(props: {
110
  context: Message[];
111
  updateContext: (updater: (context: Message[]) => void) => void;
@@ -128,42 +181,12 @@ export function ContextPrompts(props: {
128
  <>
129
  <div className={chatStyle["context-prompt"]} style={{ marginBottom: 20 }}>
130
  {context.map((c, i) => (
131
- <div className={chatStyle["context-prompt-row"]} key={i}>
132
- <select
133
- value={c.role}
134
- className={chatStyle["context-role"]}
135
- onChange={(e) =>
136
- updateContextPrompt(i, {
137
- ...c,
138
- role: e.target.value as any,
139
- })
140
- }
141
- >
142
- {ROLES.map((r) => (
143
- <option key={r} value={r}>
144
- {r}
145
- </option>
146
- ))}
147
- </select>
148
- <Input
149
- value={c.content}
150
- type="text"
151
- className={chatStyle["context-content"]}
152
- rows={1}
153
- onInput={(e) =>
154
- updateContextPrompt(i, {
155
- ...c,
156
- content: e.currentTarget.value as any,
157
- })
158
- }
159
- />
160
- <IconButton
161
- icon={<DeleteIcon />}
162
- className={chatStyle["context-delete-button"]}
163
- onClick={() => removeContextPrompt(i)}
164
- bordered
165
- />
166
- </div>
167
  ))}
168
 
169
  <div className={chatStyle["context-prompt-row"]}>
@@ -174,7 +197,7 @@ export function ContextPrompts(props: {
174
  className={chatStyle["context-prompt-button"]}
175
  onClick={() =>
176
  addContextPrompt({
177
- role: "system",
178
  content: "",
179
  date: "",
180
  })
 
14
 
15
  import { DEFAULT_MASK_AVATAR, Mask, useMaskStore } from "../store/mask";
16
  import { Message, ModelConfig, ROLES, useChatStore } from "../store";
17
+ import { Input, List, ListItem, Modal, Popover } from "./ui-lib";
18
  import { Avatar, AvatarPicker } from "./emoji";
19
  import Locale, { AllLangs, Lang } from "../locales";
20
  import { useNavigate } from "react-router-dom";
21
 
22
  import chatStyle from "./chat.module.scss";
23
+ import { useState } from "react";
24
  import { downloadAs, readFromFile } from "../utils";
25
  import { Updater } from "../api/openai/typing";
26
  import { ModelConfigList } from "./model-config";
 
106
  );
107
  }
108
 
109
+ function ContextPromptItem(props: {
110
+ prompt: Message;
111
+ update: (prompt: Message) => void;
112
+ remove: () => void;
113
+ }) {
114
+ const [focusingInput, setFocusingInput] = useState(false);
115
+
116
+ return (
117
+ <div className={chatStyle["context-prompt-row"]}>
118
+ {!focusingInput && (
119
+ <select
120
+ value={props.prompt.role}
121
+ className={chatStyle["context-role"]}
122
+ onChange={(e) =>
123
+ props.update({
124
+ ...props.prompt,
125
+ role: e.target.value as any,
126
+ })
127
+ }
128
+ >
129
+ {ROLES.map((r) => (
130
+ <option key={r} value={r}>
131
+ {r}
132
+ </option>
133
+ ))}
134
+ </select>
135
+ )}
136
+ <Input
137
+ value={props.prompt.content}
138
+ type="text"
139
+ className={chatStyle["context-content"]}
140
+ rows={focusingInput ? 5 : 1}
141
+ onFocus={() => setFocusingInput(true)}
142
+ onBlur={() => setFocusingInput(false)}
143
+ onInput={(e) =>
144
+ props.update({
145
+ ...props.prompt,
146
+ content: e.currentTarget.value as any,
147
+ })
148
+ }
149
+ />
150
+ {!focusingInput && (
151
+ <IconButton
152
+ icon={<DeleteIcon />}
153
+ className={chatStyle["context-delete-button"]}
154
+ onClick={() => props.remove()}
155
+ bordered
156
+ />
157
+ )}
158
+ </div>
159
+ );
160
+ }
161
+
162
  export function ContextPrompts(props: {
163
  context: Message[];
164
  updateContext: (updater: (context: Message[]) => void) => void;
 
181
  <>
182
  <div className={chatStyle["context-prompt"]} style={{ marginBottom: 20 }}>
183
  {context.map((c, i) => (
184
+ <ContextPromptItem
185
+ key={i}
186
+ prompt={c}
187
+ update={(prompt) => updateContextPrompt(i, prompt)}
188
+ remove={() => removeContextPrompt(i)}
189
+ />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  ))}
191
 
192
  <div className={chatStyle["context-prompt-row"]}>
 
197
  className={chatStyle["context-prompt-button"]}
198
  onClick={() =>
199
  addContextPrompt({
200
+ role: "user",
201
  content: "",
202
  date: "",
203
  })
app/components/model-config.tsx CHANGED
@@ -1,4 +1,3 @@
1
- import styles from "./settings.module.scss";
2
  import { ALL_MODELS, ModalConfigValidator, ModelConfig } from "../store";
3
 
4
  import Locale from "../locales";
 
 
1
  import { ALL_MODELS, ModalConfigValidator, ModelConfig } from "../store";
2
 
3
  import Locale from "../locales";
app/components/new-chat.tsx CHANGED
@@ -13,6 +13,7 @@ import { Mask, useMaskStore } from "../store/mask";
13
  import Locale from "../locales";
14
  import { useAppConfig, useChatStore } from "../store";
15
  import { MaskAvatar } from "./mask";
 
16
 
17
  function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
18
  const xmin = Math.max(aRect.x, bRect.x);
@@ -108,9 +109,20 @@ export function NewChat() {
108
 
109
  const startChat = (mask?: Mask) => {
110
  chatStore.newSession(mask);
111
- navigate(Path.Chat);
112
  };
113
 
 
 
 
 
 
 
 
 
 
 
 
114
  return (
115
  <div className={styles["new-chat"]}>
116
  <div className={styles["mask-header"]}>
 
13
  import Locale from "../locales";
14
  import { useAppConfig, useChatStore } from "../store";
15
  import { MaskAvatar } from "./mask";
16
+ import { useCommand } from "../command";
17
 
18
  function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
19
  const xmin = Math.max(aRect.x, bRect.x);
 
109
 
110
  const startChat = (mask?: Mask) => {
111
  chatStore.newSession(mask);
112
+ setTimeout(() => navigate(Path.Chat), 1);
113
  };
114
 
115
+ useCommand({
116
+ mask: (id) => {
117
+ try {
118
+ const mask = maskStore.get(parseInt(id));
119
+ startChat(mask ?? undefined);
120
+ } catch {
121
+ console.error("[New Chat] failed to create chat from mask id=", id);
122
+ }
123
+ },
124
+ });
125
+
126
  return (
127
  <div className={styles["new-chat"]}>
128
  <div className={styles["mask-header"]}>
app/components/settings.module.scss CHANGED
@@ -60,18 +60,13 @@
60
  .user-prompt-buttons {
61
  display: flex;
62
  align-items: center;
 
63
 
64
  .user-prompt-button {
65
- height: 100%;
66
-
67
- &:not(:last-child) {
68
- margin-right: 5px;
69
- }
70
  }
71
  }
72
  }
73
  }
74
-
75
- .user-prompt-actions {
76
- }
77
  }
 
60
  .user-prompt-buttons {
61
  display: flex;
62
  align-items: center;
63
+ column-gap: 2px;
64
 
65
  .user-prompt-button {
66
+ // height: 100%;
67
+ padding: 7px;
 
 
 
68
  }
69
  }
70
  }
71
  }
 
 
 
72
  }
app/components/settings.tsx CHANGED
@@ -9,6 +9,7 @@ import CopyIcon from "../icons/copy.svg";
9
  import ClearIcon from "../icons/clear.svg";
10
  import EditIcon from "../icons/edit.svg";
11
  import EyeIcon from "../icons/eye.svg";
 
12
  import { Input, List, ListItem, Modal, PasswordInput, Popover } from "./ui-lib";
13
  import { ModelConfigList } from "./model-config";
14
 
@@ -354,7 +355,7 @@ export function Settings() {
354
  }
355
  >
356
  {checkingUpdate ? (
357
- <div />
358
  ) : hasNewVersion ? (
359
  <Link href={UPDATE_URL} target="_blank" className="link">
360
  {Locale.Settings.Update.GoToUpdate}
 
9
  import ClearIcon from "../icons/clear.svg";
10
  import EditIcon from "../icons/edit.svg";
11
  import EyeIcon from "../icons/eye.svg";
12
+ import LoadingIcon from "../icons/three-dots.svg";
13
  import { Input, List, ListItem, Modal, PasswordInput, Popover } from "./ui-lib";
14
  import { ModelConfigList } from "./model-config";
15
 
 
355
  }
356
  >
357
  {checkingUpdate ? (
358
+ <LoadingIcon />
359
  ) : hasNewVersion ? (
360
  <Link href={UPDATE_URL} target="_blank" className="link">
361
  {Locale.Settings.Update.GoToUpdate}
app/components/sidebar.tsx CHANGED
@@ -32,6 +32,28 @@ const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
32
  loading: () => null,
33
  });
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  function useDragSideBar() {
36
  const limit = (x: number) => Math.min(MAX_SIDEBAR_WIDTH, x);
37
 
@@ -88,6 +110,7 @@ export function SideBar(props: { className?: string }) {
88
  const navigate = useNavigate();
89
 
90
  const config = useAppConfig();
 
91
 
92
  return (
93
  <div
 
32
  loading: () => null,
33
  });
34
 
35
+ function useHotKey() {
36
+ const chatStore = useChatStore();
37
+
38
+ useEffect(() => {
39
+ const onKeyDown = (e: KeyboardEvent) => {
40
+ if (e.metaKey || e.altKey || e.ctrlKey) {
41
+ const n = chatStore.sessions.length;
42
+ const limit = (x: number) => (x + n) % n;
43
+ const i = chatStore.currentSessionIndex;
44
+ if (e.key === "ArrowUp") {
45
+ chatStore.selectSession(limit(i - 1));
46
+ } else if (e.key === "ArrowDown") {
47
+ chatStore.selectSession(limit(i + 1));
48
+ }
49
+ }
50
+ };
51
+
52
+ window.addEventListener("keydown", onKeyDown);
53
+ return () => window.removeEventListener("keydown", onKeyDown);
54
+ });
55
+ }
56
+
57
  function useDragSideBar() {
58
  const limit = (x: number) => Math.min(MAX_SIDEBAR_WIDTH, x);
59
 
 
110
  const navigate = useNavigate();
111
 
112
  const config = useAppConfig();
113
+ useHotKey();
114
 
115
  return (
116
  <div
app/components/ui-lib.module.scss CHANGED
@@ -124,6 +124,19 @@
124
  }
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  .show {
128
  opacity: 1;
129
  transition: all ease 0.3s;
@@ -192,12 +205,3 @@
192
  min-width: 50px;
193
  }
194
 
195
- @media only screen and (max-width: 600px) {
196
- .modal-container {
197
- width: 90vw;
198
-
199
- .modal-content {
200
- max-height: 50vh;
201
- }
202
- }
203
- }
 
124
  }
125
  }
126
 
127
+
128
+ @media screen and (max-width: 600px) {
129
+ .modal-container {
130
+ width: 100vw;
131
+ border-bottom-left-radius: 0;
132
+ border-bottom-right-radius: 0;
133
+
134
+ .modal-content {
135
+ max-height: 50vh;
136
+ }
137
+ }
138
+ }
139
+
140
  .show {
141
  opacity: 1;
142
  transition: all ease 0.3s;
 
205
  min-width: 50px;
206
  }
207
 
 
 
 
 
 
 
 
 
 
app/config/server.ts CHANGED
@@ -8,6 +8,7 @@ declare global {
8
  PROXY_URL?: string;
9
  VERCEL?: string;
10
  HIDE_USER_API_KEY?: string; // disable user's api key input
 
11
  }
12
  }
13
  }
@@ -40,5 +41,6 @@ export const getServerSideConfig = () => {
40
  proxyUrl: process.env.PROXY_URL,
41
  isVercel: !!process.env.VERCEL,
42
  hideUserApiKey: !!process.env.HIDE_USER_API_KEY,
 
43
  };
44
  };
 
8
  PROXY_URL?: string;
9
  VERCEL?: string;
10
  HIDE_USER_API_KEY?: string; // disable user's api key input
11
+ DISABLE_GPT4?: string;
12
  }
13
  }
14
  }
 
41
  proxyUrl: process.env.PROXY_URL,
42
  isVercel: !!process.env.VERCEL,
43
  hideUserApiKey: !!process.env.HIDE_USER_API_KEY,
44
+ enableGPT4: !process.env.DISABLE_GPT4,
45
  };
46
  };
app/constant.ts CHANGED
@@ -38,3 +38,4 @@ export const MIN_SIDEBAR_WIDTH = 230;
38
  export const NARROW_SIDEBAR_WIDTH = 100;
39
 
40
  export const ACCESS_CODE_PREFIX = "ak-";
 
 
38
  export const NARROW_SIDEBAR_WIDTH = 100;
39
 
40
  export const ACCESS_CODE_PREFIX = "ak-";
41
+ export const LAST_INPUT_KEY = "last-input";
app/layout.tsx CHANGED
@@ -35,10 +35,9 @@ export default function RootLayout({
35
  />
36
  <meta name="version" content={buildConfig.commitId} />
37
  <link rel="manifest" href="/site.webmanifest"></link>
38
- <link rel="preconnect" href="https://fonts.googleapis.com"></link>
39
- <link rel="preconnect" href="https://fonts.gstatic.com"></link>
40
  <link
41
- href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
42
  rel="stylesheet"
43
  ></link>
44
  <script src="/serviceWorkerRegister.js" defer></script>
 
35
  />
36
  <meta name="version" content={buildConfig.commitId} />
37
  <link rel="manifest" href="/site.webmanifest"></link>
38
+ <link rel="preconnect" href="https://fonts.proxy.ustclug.org"></link>
 
39
  <link
40
+ href="href=https://fonts.proxy.ustclug.org/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
41
  rel="stylesheet"
42
  ></link>
43
  <script src="/serviceWorkerRegister.js" defer></script>
app/locales/cn.ts CHANGED
@@ -4,7 +4,7 @@ const cn = {
4
  WIP: "该功能仍在开发中……",
5
  Error: {
6
  Unauthorized:
7
- "现在是未授权状态,请点击左下角[设置](/#/settings)按钮输入访问密码。",
8
  },
9
  ChatItem: {
10
  ChatItemCount: (count: number) => `${count} 条对话`,
@@ -148,7 +148,7 @@ const cn = {
148
  },
149
  AccessCode: {
150
  Title: "访问密码",
151
- SubTitle: "已开启加密访问",
152
  Placeholder: "请输入访问密码",
153
  },
154
  Bot: "AI供应商 (bot)",
 
4
  WIP: "该功能仍在开发中……",
5
  Error: {
6
  Unauthorized:
7
+ "访问密码不正确或为空,请前往[设置](/#/settings)页输入正确的访问密码,或者填入你自己的 OpenAI API Key。",
8
  },
9
  ChatItem: {
10
  ChatItemCount: (count: number) => `${count} 条对话`,
 
148
  },
149
  AccessCode: {
150
  Title: "访问密码",
151
+ SubTitle: "管理员已开启加密访问",
152
  Placeholder: "请输入访问密码",
153
  },
154
  Bot: "AI供应商 (bot)",
app/store/access.ts CHANGED
@@ -2,6 +2,7 @@ import { create } from "zustand";
2
  import { persist } from "zustand/middleware";
3
  import { StoreKey } from "../constant";
4
  import { BOT_HELLO } from "./chat";
 
5
 
6
  export interface AccessControlStore {
7
  accessCode: string;
@@ -41,6 +42,7 @@ export const useAccessStore = create<AccessControlStore>()(
41
  set(() => ({ token }));
42
  },
43
  isAuthorized() {
 
44
  // has token or has code or disabled access control
45
  return (
46
  !!get().token || !!get().accessCode || !get().enabledAccessControl()
@@ -58,6 +60,14 @@ export const useAccessStore = create<AccessControlStore>()(
58
  console.log("[Config] got config from server", res);
59
  set(() => ({ ...res }));
60
 
 
 
 
 
 
 
 
 
61
  if ((res as any).botHello) {
62
  BOT_HELLO.content = (res as any).botHello;
63
  }
 
2
  import { persist } from "zustand/middleware";
3
  import { StoreKey } from "../constant";
4
  import { BOT_HELLO } from "./chat";
5
+ import { ALL_MODELS } from "./config";
6
 
7
  export interface AccessControlStore {
8
  accessCode: string;
 
42
  set(() => ({ token }));
43
  },
44
  isAuthorized() {
45
+ get().fetch();
46
  // has token or has code or disabled access control
47
  return (
48
  !!get().token || !!get().accessCode || !get().enabledAccessControl()
 
60
  console.log("[Config] got config from server", res);
61
  set(() => ({ ...res }));
62
 
63
+ if (!res.enableGPT4) {
64
+ ALL_MODELS.forEach((model) => {
65
+ if (model.name.startsWith("gpt-4")) {
66
+ (model as any).available = false;
67
+ }
68
+ });
69
+ }
70
+
71
  if ((res as any).botHello) {
72
  BOT_HELLO.content = (res as any).botHello;
73
  }
app/store/chat.ts CHANGED
@@ -7,11 +7,11 @@ import {
7
  requestChatStream,
8
  requestWithPrompt,
9
  } from "../requests";
10
- import { isMobileScreen, trimTopic } from "../utils";
11
 
12
  import Locale from "../locales";
13
  import { showToast } from "../components/ui-lib";
14
- import { DEFAULT_CONFIG, ModelConfig, ModelType, useAppConfig } from "./config";
15
  import { createEmptyMask, Mask } from "./mask";
16
  import { StoreKey } from "../constant";
17
 
@@ -181,8 +181,9 @@ export const useChatStore = create<ChatStore>()(
181
  const sessions = get().sessions.slice();
182
  sessions.splice(index, 1);
183
 
 
184
  let nextIndex = Math.min(
185
- get().currentSessionIndex,
186
  sessions.length - 1,
187
  );
188
 
@@ -251,10 +252,19 @@ export const useChatStore = create<ChatStore>()(
251
  id: userMessage.id! + 1,
252
  model: modelConfig.model,
253
  });
254
-
 
 
 
 
 
 
255
  // get recent messages
 
256
  const recentMessages = get().getMessagesWithMemory();
257
- const sendMessages = recentMessages.concat(userMessage);
 
 
258
  const sessionIndex = get().currentSessionIndex;
259
  const messageIndex = get().currentSession().messages.length + 1;
260
 
 
7
  requestChatStream,
8
  requestWithPrompt,
9
  } from "../requests";
10
+ import { trimTopic } from "../utils";
11
 
12
  import Locale from "../locales";
13
  import { showToast } from "../components/ui-lib";
14
+ import { ModelType, useAppConfig } from "./config";
15
  import { createEmptyMask, Mask } from "./mask";
16
  import { StoreKey } from "../constant";
17
 
 
181
  const sessions = get().sessions.slice();
182
  sessions.splice(index, 1);
183
 
184
+ const currentIndex = get().currentSessionIndex;
185
  let nextIndex = Math.min(
186
+ currentIndex - Number(index < currentIndex),
187
  sessions.length - 1,
188
  );
189
 
 
252
  id: userMessage.id! + 1,
253
  model: modelConfig.model,
254
  });
255
+ const systemInfo = createMessage({
256
+ role: "system",
257
+ content: `IMPRTANT: You are a virtual assistant powered by the ${
258
+ modelConfig.model
259
+ } model, now time is ${new Date().toLocaleString()}}`,
260
+ id: botMessage.id! + 1,
261
+ });
262
  // get recent messages
263
+ const systemMessages = [systemInfo];
264
  const recentMessages = get().getMessagesWithMemory();
265
+ const sendMessages = systemMessages.concat(
266
+ recentMessages.concat(userMessage),
267
+ );
268
  const sessionIndex = get().currentSessionIndex;
269
  const messageIndex = get().currentSession().messages.length + 1;
270
 
app/store/config.ts CHANGED
@@ -77,6 +77,26 @@ export const ALL_MODELS = [
77
  name: "gpt-3.5-turbo-0301",
78
  available: true,
79
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  ] as const;
81
 
82
  export const ALL_BOT = [
 
77
  name: "gpt-3.5-turbo-0301",
78
  available: true,
79
  },
80
+ {
81
+ name: "qwen-v1", // 通义千问
82
+ available: false,
83
+ },
84
+ {
85
+ name: "ernie", // 文心一言
86
+ available: false,
87
+ },
88
+ {
89
+ name: "spark", // 讯飞星火
90
+ available: false,
91
+ },
92
+ {
93
+ name: "llama", // llama
94
+ available: false,
95
+ },
96
+ {
97
+ name: "chatglm", // chatglm-6b
98
+ available: false,
99
+ },
100
  ] as const;
101
 
102
  export const ALL_BOT = [
app/styles/globals.scss CHANGED
@@ -88,6 +88,8 @@
88
  }
89
  html {
90
  height: var(--full-height);
 
 
91
  }
92
 
93
  body {
@@ -102,8 +104,6 @@ body {
102
  align-items: center;
103
  user-select: none;
104
  touch-action: pan-x pan-y;
105
- font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons",
106
- "PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
107
 
108
  @media only screen and (max-width: 600px) {
109
  background-color: var(--second);
@@ -247,6 +247,9 @@ div.math {
247
  display: flex;
248
  align-items: center;
249
  justify-content: center;
 
 
 
250
  }
251
 
252
  .link {
 
88
  }
89
  html {
90
  height: var(--full-height);
91
+ font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons",
92
+ "PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
93
  }
94
 
95
  body {
 
104
  align-items: center;
105
  user-select: none;
106
  touch-action: pan-x pan-y;
 
 
107
 
108
  @media only screen and (max-width: 600px) {
109
  background-color: var(--second);
 
247
  display: flex;
248
  align-items: center;
249
  justify-content: center;
250
+ @media screen and (max-width: 600px) {
251
+ align-items: flex-end;
252
+ }
253
  }
254
 
255
  .link {
app/utils.ts CHANGED
@@ -158,15 +158,15 @@ export function autoGrowTextArea(dom: HTMLTextAreaElement) {
158
 
159
  const width = getDomContentWidth(dom);
160
  measureDom.style.width = width + "px";
161
- measureDom.innerText = dom.value.trim().length > 0 ? dom.value : "1";
162
-
163
- const lineWrapCount = Math.max(0, dom.value.split("\n").length - 1);
164
  const height = parseFloat(window.getComputedStyle(measureDom).height);
165
  const singleLineHeight = parseFloat(
166
  window.getComputedStyle(singleLineDom).height,
167
  );
168
 
169
- const rows = Math.round(height / singleLineHeight) + lineWrapCount;
 
170
 
171
  return rows;
172
  }
 
158
 
159
  const width = getDomContentWidth(dom);
160
  measureDom.style.width = width + "px";
161
+ measureDom.innerText = dom.value !== "" ? dom.value : "1";
162
+ const endWithEmptyLine = dom.value.endsWith("\n");
 
163
  const height = parseFloat(window.getComputedStyle(measureDom).height);
164
  const singleLineHeight = parseFloat(
165
  window.getComputedStyle(singleLineDom).height,
166
  );
167
 
168
+ const rows =
169
+ Math.round(height / singleLineHeight) + (endWithEmptyLine ? 1 : 0);
170
 
171
  return rows;
172
  }
next.config.mjs CHANGED
@@ -5,7 +5,12 @@ const nextConfig = {
5
  appDir: true,
6
  },
7
  async rewrites() {
8
- const ret = [];
 
 
 
 
 
9
 
10
  const apiUrl = process.env.API_URL;
11
  if (apiUrl) {
@@ -17,7 +22,7 @@ const nextConfig = {
17
  }
18
 
19
  return {
20
- afterFiles: ret,
21
  };
22
  },
23
  webpack(config) {
 
5
  appDir: true,
6
  },
7
  async rewrites() {
8
+ const ret = [
9
+ {
10
+ source: "/api/proxy/:path*",
11
+ destination: "https://api.openai.com/:path*",
12
+ },
13
+ ];
14
 
15
  const apiUrl = process.env.API_URL;
16
  if (apiUrl) {
 
22
  }
23
 
24
  return {
25
+ beforeFiles: ret,
26
  };
27
  },
28
  webpack(config) {
package.json CHANGED
@@ -21,6 +21,7 @@
21
  "emoji-picker-react": "^4.4.7",
22
  "eventsource-parser": "^0.1.0",
23
  "fuse.js": "^6.6.2",
 
24
  "next": "^13.3.1-canary.8",
25
  "node-fetch": "^3.3.1",
26
  "openai": "^3.2.1",
 
21
  "emoji-picker-react": "^4.4.7",
22
  "eventsource-parser": "^0.1.0",
23
  "fuse.js": "^6.6.2",
24
+ "mermaid": "^10.1.0",
25
  "next": "^13.3.1-canary.8",
26
  "node-fetch": "^3.3.1",
27
  "openai": "^3.2.1",
yarn.lock CHANGED
@@ -995,6 +995,11 @@
995
  "@babel/helper-validator-identifier" "^7.19.1"
996
  to-fast-properties "^2.0.0"
997
 
 
 
 
 
 
998
  "@eslint-community/eslint-utils@^4.2.0":
999
  version "4.4.0"
1000
  resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -1099,6 +1104,13 @@
1099
  "@jridgewell/resolve-uri" "3.1.0"
1100
  "@jridgewell/sourcemap-codec" "1.4.14"
1101
 
 
 
 
 
 
 
 
1102
  "@next/env@13.3.1-canary.8":
1103
  version "13.3.1-canary.8"
1104
  resolved "https://registry.yarnpkg.com/@next/env/-/env-13.3.1-canary.8.tgz#9f5cf57999e4f4b59ef6407924803a247cc4e451"
@@ -1399,6 +1411,15 @@
1399
  "@types/scheduler" "*"
1400
  csstype "^3.0.2"
1401
 
 
 
 
 
 
 
 
 
 
1402
  "@types/scheduler@*":
1403
  version "0.16.3"
1404
  resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
@@ -1885,16 +1906,16 @@ comma-separated-tokens@^2.0.0:
1885
  resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee"
1886
  integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
1887
 
 
 
 
 
 
1888
  commander@^10.0.0:
1889
  version "10.0.0"
1890
  resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.0.tgz#71797971162cd3cf65f0b9d24eb28f8d303acdf1"
1891
  integrity sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==
1892
 
1893
- commander@^7.2.0:
1894
- version "7.2.0"
1895
- resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
1896
- integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
1897
-
1898
  commander@^8.0.0:
1899
  version "8.3.0"
1900
  resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@@ -1917,6 +1938,20 @@ core-js-compat@^3.25.1:
1917
  dependencies:
1918
  browserslist "^4.21.5"
1919
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1920
  cosmiconfig@^7.0.1:
1921
  version "7.1.0"
1922
  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
@@ -1987,6 +2022,280 @@ csstype@^3.0.2:
1987
  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
1988
  integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
1989
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1990
  damerau-levenshtein@^1.0.8:
1991
  version "1.0.8"
1992
  resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -1997,6 +2306,11 @@ data-uri-to-buffer@^4.0.0:
1997
  resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
1998
  integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
1999
 
 
 
 
 
 
2000
  debug@^3.2.7:
2001
  version "3.2.7"
2002
  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -2064,6 +2378,13 @@ define-properties@^1.1.3, define-properties@^1.1.4:
2064
  has-property-descriptors "^1.0.0"
2065
  object-keys "^1.1.1"
2066
 
 
 
 
 
 
 
 
2067
  delayed-stream@~1.0.0:
2068
  version "1.0.0"
2069
  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -2121,6 +2442,11 @@ domhandler@^4.2.0, domhandler@^4.3.1:
2121
  dependencies:
2122
  domelementtype "^2.2.0"
2123
 
 
 
 
 
 
2124
  domutils@^2.8.0:
2125
  version "2.8.0"
2126
  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
@@ -2140,6 +2466,11 @@ electron-to-chromium@^1.4.284:
2140
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.345.tgz#c90b7183b39245cddf0e990337469063bfced6f0"
2141
  integrity sha512-znGhOQK2TUYLICgS25uaM0a7pHy66rSxbre7l762vg9AUoCcJK+Bu+HCPWpjL/U/kK8/Hf+6E0szAUJSyVYb3Q==
2142
 
 
 
 
 
 
2143
  emoji-picker-react@^4.4.7:
2144
  version "4.4.8"
2145
  resolved "https://registry.yarnpkg.com/emoji-picker-react/-/emoji-picker-react-4.4.8.tgz#cd18e942720d0d01e3d488a008f5e79aa315ec87"
@@ -2919,6 +3250,11 @@ hastscript@^7.0.0:
2919
  property-information "^6.0.0"
2920
  space-separated-tokens "^2.0.0"
2921
 
 
 
 
 
 
2922
  highlight.js@~11.7.0:
2923
  version "11.7.0"
2924
  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e"
@@ -2941,6 +3277,13 @@ husky@^8.0.0:
2941
  resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
2942
  integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==
2943
 
 
 
 
 
 
 
 
2944
  ignore@^5.2.0:
2945
  version "5.2.4"
2946
  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
@@ -2996,6 +3339,11 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5:
2996
  has "^1.0.3"
2997
  side-channel "^1.0.4"
2998
 
 
 
 
 
 
2999
  is-arguments@^1.1.1:
3000
  version "1.1.1"
3001
  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
@@ -3286,6 +3634,11 @@ katex@^0.15.0:
3286
  dependencies:
3287
  commander "^8.0.0"
3288
 
 
 
 
 
 
3289
  kleur@^4.0.3:
3290
  version "4.1.5"
3291
  resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
@@ -3303,6 +3656,16 @@ language-tags@=1.0.5:
3303
  dependencies:
3304
  language-subtag-registry "~0.3.2"
3305
 
 
 
 
 
 
 
 
 
 
 
3306
  levn@^0.4.1:
3307
  version "0.4.1"
3308
  resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@@ -3361,6 +3724,11 @@ locate-path@^6.0.0:
3361
  dependencies:
3362
  p-locate "^5.0.0"
3363
 
 
 
 
 
 
3364
  lodash.debounce@^4.0.8:
3365
  version "4.0.8"
3366
  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -3371,6 +3739,11 @@ lodash.merge@^4.6.2:
3371
  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
3372
  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
3373
 
 
 
 
 
 
3374
  log-update@^4.0.0:
3375
  version "4.0.0"
3376
  resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
@@ -3588,6 +3961,29 @@ merge2@^1.3.0, merge2@^1.4.1:
3588
  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
3589
  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
3590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3591
  micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1:
3592
  version "1.0.6"
3593
  resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad"
@@ -3989,6 +4385,11 @@ node-releases@^2.0.8:
3989
  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
3990
  integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
3991
 
 
 
 
 
 
3992
  normalize-path@^3.0.0, normalize-path@~3.0.0:
3993
  version "3.0.0"
3994
  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
@@ -4539,6 +4940,11 @@ rimraf@^3.0.2:
4539
  dependencies:
4540
  glob "^7.1.3"
4541
 
 
 
 
 
 
4542
  run-parallel@^1.1.9:
4543
  version "1.2.0"
4544
  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -4546,6 +4952,11 @@ run-parallel@^1.1.9:
4546
  dependencies:
4547
  queue-microtask "^1.2.2"
4548
 
 
 
 
 
 
4549
  rxjs@^7.8.0:
4550
  version "7.8.0"
4551
  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4"
@@ -4569,6 +4980,11 @@ safe-regex-test@^1.0.0:
4569
  get-intrinsic "^1.1.3"
4570
  is-regex "^1.1.4"
4571
 
 
 
 
 
 
4572
  sass@^1.59.2:
4573
  version "1.60.0"
4574
  resolved "https://registry.yarnpkg.com/sass/-/sass-1.60.0.tgz#657f0c23a302ac494b09a5ba8497b739fb5b5a81"
@@ -4803,6 +5219,11 @@ styled-jsx@5.1.1:
4803
  dependencies:
4804
  client-only "0.0.1"
4805
 
 
 
 
 
 
4806
  supports-color@^5.3.0:
4807
  version "5.5.0"
4808
  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -4898,6 +5319,11 @@ trough@^2.0.0:
4898
  resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876"
4899
  integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==
4900
 
 
 
 
 
 
4901
  tsconfig-paths@^3.14.1:
4902
  version "3.14.2"
4903
  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
@@ -5098,6 +5524,11 @@ utf-8-validate@^6.0.3:
5098
  dependencies:
5099
  node-gyp-build "^4.3.0"
5100
 
 
 
 
 
 
5101
  uvu@^0.5.0:
5102
  version "0.5.6"
5103
  resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
@@ -5144,6 +5575,11 @@ web-streams-polyfill@^3.0.3:
5144
  resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
5145
  integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
5146
 
 
 
 
 
 
5147
  which-boxed-primitive@^1.0.2:
5148
  version "1.0.2"
5149
  resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
 
995
  "@babel/helper-validator-identifier" "^7.19.1"
996
  to-fast-properties "^2.0.0"
997
 
998
+ "@braintree/sanitize-url@^6.0.0":
999
+ version "6.0.2"
1000
+ resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz#6110f918d273fe2af8ea1c4398a88774bb9fc12f"
1001
+ integrity sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==
1002
+
1003
  "@eslint-community/eslint-utils@^4.2.0":
1004
  version "4.4.0"
1005
  resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
 
1104
  "@jridgewell/resolve-uri" "3.1.0"
1105
  "@jridgewell/sourcemap-codec" "1.4.14"
1106
 
1107
+ "@khanacademy/simple-markdown@^0.8.6":
1108
+ version "0.8.6"
1109
+ resolved "https://registry.yarnpkg.com/@khanacademy/simple-markdown/-/simple-markdown-0.8.6.tgz#9c9aef1f5ce2ce60292d13849165965a57c26f25"
1110
+ integrity sha512-mAUlR9lchzfqunR89pFvNI51jQKsMpJeWYsYWw0DQcUXczn/T/V6510utgvm7X0N3zN87j1SvuKk8cMbl9IAFw==
1111
+ dependencies:
1112
+ "@types/react" ">=16.0.0"
1113
+
1114
  "@next/env@13.3.1-canary.8":
1115
  version "13.3.1-canary.8"
1116
  resolved "https://registry.yarnpkg.com/@next/env/-/env-13.3.1-canary.8.tgz#9f5cf57999e4f4b59ef6407924803a247cc4e451"
 
1411
  "@types/scheduler" "*"
1412
  csstype "^3.0.2"
1413
 
1414
+ "@types/react@>=16.0.0":
1415
+ version "18.2.6"
1416
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.6.tgz#5cd53ee0d30ffc193b159d3516c8c8ad2f19d571"
1417
+ integrity sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==
1418
+ dependencies:
1419
+ "@types/prop-types" "*"
1420
+ "@types/scheduler" "*"
1421
+ csstype "^3.0.2"
1422
+
1423
  "@types/scheduler@*":
1424
  version "0.16.3"
1425
  resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
 
1906
  resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee"
1907
  integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
1908
 
1909
+ commander@7, commander@^7.2.0:
1910
+ version "7.2.0"
1911
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
1912
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
1913
+
1914
  commander@^10.0.0:
1915
  version "10.0.0"
1916
  resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.0.tgz#71797971162cd3cf65f0b9d24eb28f8d303acdf1"
1917
  integrity sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==
1918
 
 
 
 
 
 
1919
  commander@^8.0.0:
1920
  version "8.3.0"
1921
  resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
 
1938
  dependencies:
1939
  browserslist "^4.21.5"
1940
 
1941
+ cose-base@^1.0.0:
1942
+ version "1.0.3"
1943
+ resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a"
1944
+ integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==
1945
+ dependencies:
1946
+ layout-base "^1.0.0"
1947
+
1948
+ cose-base@^2.2.0:
1949
+ version "2.2.0"
1950
+ resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-2.2.0.tgz#1c395c35b6e10bb83f9769ca8b817d614add5c01"
1951
+ integrity sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==
1952
+ dependencies:
1953
+ layout-base "^2.0.0"
1954
+
1955
  cosmiconfig@^7.0.1:
1956
  version "7.1.0"
1957
  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
 
2022
  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
2023
  integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
2024
 
2025
+ cytoscape-cose-bilkent@^4.1.0:
2026
+ version "4.1.0"
2027
+ resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b"
2028
+ integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==
2029
+ dependencies:
2030
+ cose-base "^1.0.0"
2031
+
2032
+ cytoscape-fcose@^2.1.0:
2033
+ version "2.2.0"
2034
+ resolved "https://registry.yarnpkg.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz#e4d6f6490df4fab58ae9cea9e5c3ab8d7472f471"
2035
+ integrity sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==
2036
+ dependencies:
2037
+ cose-base "^2.2.0"
2038
+
2039
+ cytoscape@^3.23.0:
2040
+ version "3.24.0"
2041
+ resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.24.0.tgz#764e4ca3df37160b1c55244c648afd303a07e109"
2042
+ integrity sha512-W9fJMrAfr/zKFzDCpRR/wn6uoEQ7gfbJmxPK5DadXj69XyAhZYi1QXLOE+UXJfXVXxqGM1o1eeiIrtxrtB43zA==
2043
+ dependencies:
2044
+ heap "^0.2.6"
2045
+ lodash "^4.17.21"
2046
+
2047
+ "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0:
2048
+ version "3.2.3"
2049
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.3.tgz#39f1f4954e4a09ff69ac597c2d61906b04e84740"
2050
+ integrity sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ==
2051
+ dependencies:
2052
+ internmap "1 - 2"
2053
+
2054
+ d3-axis@3:
2055
+ version "3.0.0"
2056
+ resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
2057
+ integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==
2058
+
2059
+ d3-brush@3:
2060
+ version "3.0.0"
2061
+ resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
2062
+ integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==
2063
+ dependencies:
2064
+ d3-dispatch "1 - 3"
2065
+ d3-drag "2 - 3"
2066
+ d3-interpolate "1 - 3"
2067
+ d3-selection "3"
2068
+ d3-transition "3"
2069
+
2070
+ d3-chord@3:
2071
+ version "3.0.1"
2072
+ resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966"
2073
+ integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==
2074
+ dependencies:
2075
+ d3-path "1 - 3"
2076
+
2077
+ "d3-color@1 - 3", d3-color@3:
2078
+ version "3.1.0"
2079
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
2080
+ integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
2081
+
2082
+ d3-contour@4:
2083
+ version "4.0.2"
2084
+ resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc"
2085
+ integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==
2086
+ dependencies:
2087
+ d3-array "^3.2.0"
2088
+
2089
+ d3-delaunay@6:
2090
+ version "6.0.4"
2091
+ resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b"
2092
+ integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==
2093
+ dependencies:
2094
+ delaunator "5"
2095
+
2096
+ "d3-dispatch@1 - 3", d3-dispatch@3:
2097
+ version "3.0.1"
2098
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
2099
+ integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
2100
+
2101
+ "d3-drag@2 - 3", d3-drag@3:
2102
+ version "3.0.0"
2103
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
2104
+ integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
2105
+ dependencies:
2106
+ d3-dispatch "1 - 3"
2107
+ d3-selection "3"
2108
+
2109
+ "d3-dsv@1 - 3", d3-dsv@3:
2110
+ version "3.0.1"
2111
+ resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73"
2112
+ integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==
2113
+ dependencies:
2114
+ commander "7"
2115
+ iconv-lite "0.6"
2116
+ rw "1"
2117
+
2118
+ "d3-ease@1 - 3", d3-ease@3:
2119
+ version "3.0.1"
2120
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
2121
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
2122
+
2123
+ d3-fetch@3:
2124
+ version "3.0.1"
2125
+ resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22"
2126
+ integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==
2127
+ dependencies:
2128
+ d3-dsv "1 - 3"
2129
+
2130
+ d3-force@3:
2131
+ version "3.0.0"
2132
+ resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
2133
+ integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==
2134
+ dependencies:
2135
+ d3-dispatch "1 - 3"
2136
+ d3-quadtree "1 - 3"
2137
+ d3-timer "1 - 3"
2138
+
2139
+ "d3-format@1 - 3", d3-format@3:
2140
+ version "3.1.0"
2141
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
2142
+ integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
2143
+
2144
+ d3-geo@3:
2145
+ version "3.1.0"
2146
+ resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.0.tgz#74fd54e1f4cebd5185ac2039217a98d39b0a4c0e"
2147
+ integrity sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==
2148
+ dependencies:
2149
+ d3-array "2.5.0 - 3"
2150
+
2151
+ d3-hierarchy@3:
2152
+ version "3.1.2"
2153
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6"
2154
+ integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==
2155
+
2156
+ "d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
2157
+ version "3.0.1"
2158
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
2159
+ integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
2160
+ dependencies:
2161
+ d3-color "1 - 3"
2162
+
2163
+ "d3-path@1 - 3", d3-path@3, d3-path@^3.1.0:
2164
+ version "3.1.0"
2165
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
2166
+ integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==
2167
+
2168
+ d3-polygon@3:
2169
+ version "3.0.1"
2170
+ resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398"
2171
+ integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==
2172
+
2173
+ "d3-quadtree@1 - 3", d3-quadtree@3:
2174
+ version "3.0.1"
2175
+ resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
2176
+ integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==
2177
+
2178
+ d3-random@3:
2179
+ version "3.0.1"
2180
+ resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
2181
+ integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==
2182
+
2183
+ d3-scale-chromatic@3:
2184
+ version "3.0.0"
2185
+ resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
2186
+ integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
2187
+ dependencies:
2188
+ d3-color "1 - 3"
2189
+ d3-interpolate "1 - 3"
2190
+
2191
+ d3-scale@4:
2192
+ version "4.0.2"
2193
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
2194
+ integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
2195
+ dependencies:
2196
+ d3-array "2.10.0 - 3"
2197
+ d3-format "1 - 3"
2198
+ d3-interpolate "1.2.0 - 3"
2199
+ d3-time "2.1.1 - 3"
2200
+ d3-time-format "2 - 4"
2201
+
2202
+ "d3-selection@2 - 3", d3-selection@3:
2203
+ version "3.0.0"
2204
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
2205
+ integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
2206
+
2207
+ d3-shape@3:
2208
+ version "3.2.0"
2209
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
2210
+ integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==
2211
+ dependencies:
2212
+ d3-path "^3.1.0"
2213
+
2214
+ "d3-time-format@2 - 4", d3-time-format@4:
2215
+ version "4.1.0"
2216
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
2217
+ integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
2218
+ dependencies:
2219
+ d3-time "1 - 3"
2220
+
2221
+ "d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3:
2222
+ version "3.1.0"
2223
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7"
2224
+ integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==
2225
+ dependencies:
2226
+ d3-array "2 - 3"
2227
+
2228
+ "d3-timer@1 - 3", d3-timer@3:
2229
+ version "3.0.1"
2230
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
2231
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
2232
+
2233
+ "d3-transition@2 - 3", d3-transition@3:
2234
+ version "3.0.1"
2235
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
2236
+ integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
2237
+ dependencies:
2238
+ d3-color "1 - 3"
2239
+ d3-dispatch "1 - 3"
2240
+ d3-ease "1 - 3"
2241
+ d3-interpolate "1 - 3"
2242
+ d3-timer "1 - 3"
2243
+
2244
+ d3-zoom@3:
2245
+ version "3.0.0"
2246
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
2247
+ integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
2248
+ dependencies:
2249
+ d3-dispatch "1 - 3"
2250
+ d3-drag "2 - 3"
2251
+ d3-interpolate "1 - 3"
2252
+ d3-selection "2 - 3"
2253
+ d3-transition "2 - 3"
2254
+
2255
+ d3@^7.4.0, d3@^7.8.2:
2256
+ version "7.8.4"
2257
+ resolved "https://registry.yarnpkg.com/d3/-/d3-7.8.4.tgz#e35d45800e4068cab07e59e5d883a4bb42ab217f"
2258
+ integrity sha512-q2WHStdhiBtD8DMmhDPyJmXUxr6VWRngKyiJ5EfXMxPw+tqT6BhNjhJZ4w3BHsNm3QoVfZLY8Orq/qPFczwKRA==
2259
+ dependencies:
2260
+ d3-array "3"
2261
+ d3-axis "3"
2262
+ d3-brush "3"
2263
+ d3-chord "3"
2264
+ d3-color "3"
2265
+ d3-contour "4"
2266
+ d3-delaunay "6"
2267
+ d3-dispatch "3"
2268
+ d3-drag "3"
2269
+ d3-dsv "3"
2270
+ d3-ease "3"
2271
+ d3-fetch "3"
2272
+ d3-force "3"
2273
+ d3-format "3"
2274
+ d3-geo "3"
2275
+ d3-hierarchy "3"
2276
+ d3-interpolate "3"
2277
+ d3-path "3"
2278
+ d3-polygon "3"
2279
+ d3-quadtree "3"
2280
+ d3-random "3"
2281
+ d3-scale "4"
2282
+ d3-scale-chromatic "3"
2283
+ d3-selection "3"
2284
+ d3-shape "3"
2285
+ d3-time "3"
2286
+ d3-time-format "4"
2287
+ d3-timer "3"
2288
+ d3-transition "3"
2289
+ d3-zoom "3"
2290
+
2291
+ dagre-d3-es@7.0.10:
2292
+ version "7.0.10"
2293
+ resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz#19800d4be674379a3cd8c86a8216a2ac6827cadc"
2294
+ integrity sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==
2295
+ dependencies:
2296
+ d3 "^7.8.2"
2297
+ lodash-es "^4.17.21"
2298
+
2299
  damerau-levenshtein@^1.0.8:
2300
  version "1.0.8"
2301
  resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
 
2306
  resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
2307
  integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==
2308
 
2309
+ dayjs@^1.11.7:
2310
+ version "1.11.7"
2311
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
2312
+ integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
2313
+
2314
  debug@^3.2.7:
2315
  version "3.2.7"
2316
  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
 
2378
  has-property-descriptors "^1.0.0"
2379
  object-keys "^1.1.1"
2380
 
2381
+ delaunator@5:
2382
+ version "5.0.0"
2383
+ resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"
2384
+ integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==
2385
+ dependencies:
2386
+ robust-predicates "^3.0.0"
2387
+
2388
  delayed-stream@~1.0.0:
2389
  version "1.0.0"
2390
  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
 
2442
  dependencies:
2443
  domelementtype "^2.2.0"
2444
 
2445
+ dompurify@2.4.5:
2446
+ version "2.4.5"
2447
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
2448
+ integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
2449
+
2450
  domutils@^2.8.0:
2451
  version "2.8.0"
2452
  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
 
2466
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.345.tgz#c90b7183b39245cddf0e990337469063bfced6f0"
2467
  integrity sha512-znGhOQK2TUYLICgS25uaM0a7pHy66rSxbre7l762vg9AUoCcJK+Bu+HCPWpjL/U/kK8/Hf+6E0szAUJSyVYb3Q==
2468
 
2469
+ elkjs@^0.8.2:
2470
+ version "0.8.2"
2471
+ resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.8.2.tgz#c37763c5a3e24e042e318455e0147c912a7c248e"
2472
+ integrity sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==
2473
+
2474
  emoji-picker-react@^4.4.7:
2475
  version "4.4.8"
2476
  resolved "https://registry.yarnpkg.com/emoji-picker-react/-/emoji-picker-react-4.4.8.tgz#cd18e942720d0d01e3d488a008f5e79aa315ec87"
 
3250
  property-information "^6.0.0"
3251
  space-separated-tokens "^2.0.0"
3252
 
3253
+ heap@^0.2.6:
3254
+ version "0.2.7"
3255
+ resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc"
3256
+ integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==
3257
+
3258
  highlight.js@~11.7.0:
3259
  version "11.7.0"
3260
  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e"
 
3277
  resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
3278
  integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==
3279
 
3280
+ iconv-lite@0.6:
3281
+ version "0.6.3"
3282
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
3283
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
3284
+ dependencies:
3285
+ safer-buffer ">= 2.1.2 < 3.0.0"
3286
+
3287
  ignore@^5.2.0:
3288
  version "5.2.4"
3289
  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
 
3339
  has "^1.0.3"
3340
  side-channel "^1.0.4"
3341
 
3342
+ "internmap@1 - 2":
3343
+ version "2.0.3"
3344
+ resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
3345
+ integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
3346
+
3347
  is-arguments@^1.1.1:
3348
  version "1.1.1"
3349
  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
 
3634
  dependencies:
3635
  commander "^8.0.0"
3636
 
3637
+ khroma@^2.0.0:
3638
+ version "2.0.0"
3639
+ resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.0.0.tgz#7577de98aed9f36c7a474c4d453d94c0d6c6588b"
3640
+ integrity sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==
3641
+
3642
  kleur@^4.0.3:
3643
  version "4.1.5"
3644
  resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
 
3656
  dependencies:
3657
  language-subtag-registry "~0.3.2"
3658
 
3659
+ layout-base@^1.0.0:
3660
+ version "1.0.2"
3661
+ resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2"
3662
+ integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==
3663
+
3664
+ layout-base@^2.0.0:
3665
+ version "2.0.1"
3666
+ resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-2.0.1.tgz#d0337913586c90f9c2c075292069f5c2da5dd285"
3667
+ integrity sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==
3668
+
3669
  levn@^0.4.1:
3670
  version "0.4.1"
3671
  resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
 
3724
  dependencies:
3725
  p-locate "^5.0.0"
3726
 
3727
+ lodash-es@^4.17.21:
3728
+ version "4.17.21"
3729
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
3730
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
3731
+
3732
  lodash.debounce@^4.0.8:
3733
  version "4.0.8"
3734
  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
 
3739
  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
3740
  integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
3741
 
3742
+ lodash@^4.17.21:
3743
+ version "4.17.21"
3744
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
3745
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
3746
+
3747
  log-update@^4.0.0:
3748
  version "4.0.0"
3749
  resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
 
3961
  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
3962
  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
3963
 
3964
+ mermaid@^10.1.0:
3965
+ version "10.1.0"
3966
+ resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.1.0.tgz#6e40d5250174f4750ca6548e4ee00f6ae210855a"
3967
+ integrity sha512-LYekSMNJygI1VnMizAPUddY95hZxOjwZxr7pODczILInO0dhQKuhXeu4sargtnuTwCilSuLS7Uiq/Qn7HTVrmA==
3968
+ dependencies:
3969
+ "@braintree/sanitize-url" "^6.0.0"
3970
+ "@khanacademy/simple-markdown" "^0.8.6"
3971
+ cytoscape "^3.23.0"
3972
+ cytoscape-cose-bilkent "^4.1.0"
3973
+ cytoscape-fcose "^2.1.0"
3974
+ d3 "^7.4.0"
3975
+ dagre-d3-es "7.0.10"
3976
+ dayjs "^1.11.7"
3977
+ dompurify "2.4.5"
3978
+ elkjs "^0.8.2"
3979
+ khroma "^2.0.0"
3980
+ lodash-es "^4.17.21"
3981
+ non-layered-tidy-tree-layout "^2.0.2"
3982
+ stylis "^4.1.2"
3983
+ ts-dedent "^2.2.0"
3984
+ uuid "^9.0.0"
3985
+ web-worker "^1.2.0"
3986
+
3987
  micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1:
3988
  version "1.0.6"
3989
  resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad"
 
4385
  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
4386
  integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
4387
 
4388
+ non-layered-tidy-tree-layout@^2.0.2:
4389
+ version "2.0.2"
4390
+ resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804"
4391
+ integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==
4392
+
4393
  normalize-path@^3.0.0, normalize-path@~3.0.0:
4394
  version "3.0.0"
4395
  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
 
4940
  dependencies:
4941
  glob "^7.1.3"
4942
 
4943
+ robust-predicates@^3.0.0:
4944
+ version "3.0.1"
4945
+ resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
4946
+ integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
4947
+
4948
  run-parallel@^1.1.9:
4949
  version "1.2.0"
4950
  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
 
4952
  dependencies:
4953
  queue-microtask "^1.2.2"
4954
 
4955
+ rw@1:
4956
+ version "1.3.3"
4957
+ resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
4958
+ integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
4959
+
4960
  rxjs@^7.8.0:
4961
  version "7.8.0"
4962
  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4"
 
4980
  get-intrinsic "^1.1.3"
4981
  is-regex "^1.1.4"
4982
 
4983
+ "safer-buffer@>= 2.1.2 < 3.0.0":
4984
+ version "2.1.2"
4985
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
4986
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
4987
+
4988
  sass@^1.59.2:
4989
  version "1.60.0"
4990
  resolved "https://registry.yarnpkg.com/sass/-/sass-1.60.0.tgz#657f0c23a302ac494b09a5ba8497b739fb5b5a81"
 
5219
  dependencies:
5220
  client-only "0.0.1"
5221
 
5222
+ stylis@^4.1.2:
5223
+ version "4.2.0"
5224
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
5225
+ integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
5226
+
5227
  supports-color@^5.3.0:
5228
  version "5.5.0"
5229
  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
 
5319
  resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876"
5320
  integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==
5321
 
5322
+ ts-dedent@^2.2.0:
5323
+ version "2.2.0"
5324
+ resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
5325
+ integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
5326
+
5327
  tsconfig-paths@^3.14.1:
5328
  version "3.14.2"
5329
  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
 
5524
  dependencies:
5525
  node-gyp-build "^4.3.0"
5526
 
5527
+ uuid@^9.0.0:
5528
+ version "9.0.0"
5529
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
5530
+ integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
5531
+
5532
  uvu@^0.5.0:
5533
  version "0.5.6"
5534
  resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
 
5575
  resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
5576
  integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
5577
 
5578
+ web-worker@^1.2.0:
5579
+ version "1.2.0"
5580
+ resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da"
5581
+ integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==
5582
+
5583
  which-boxed-primitive@^1.0.2:
5584
  version "1.0.2"
5585
  resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"