dsh-aha-tutor 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -3
- package/CHANGELOG.md +38 -0
- package/README.en.md +7 -7
- package/README.md +8 -8
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/assets/fonts/OFL-Caveat.txt +93 -0
- package/assets/fonts/OFL-LXGWWenKaiGB.txt +94 -0
- package/assets/fonts/caveat-latin-d0b7b931.woff2 +0 -0
- package/assets/fonts/wenkai-gb-0-88f1a875.woff2 +0 -0
- package/assets/fonts/wenkai-gb-1-78a38e72.woff2 +0 -0
- package/assets/fonts/wenkai-gb-2-2a649892.woff2 +0 -0
- package/assets/fonts/wenkai-gb-3-6949c050.woff2 +0 -0
- package/assets/fonts/wenkai-gb-4-375dc3b3.woff2 +0 -0
- package/assets/fonts/wenkai-gb-5-d0359bbc.woff2 +0 -0
- package/assets/fonts/wenkai-gb-6-a238b41c.woff2 +0 -0
- package/docs/guide.zh-CN.md +26 -14
- package/lib/agent.js +1 -1
- package/lib/client.js +109 -33
- package/lib/index.js +845 -143
- package/lib/{runtime-CiA2I7-X.js → runtime-BCGFUDlg.js} +345 -178
- package/package.json +2 -1
- package/samples/bayes-thinking.aha-course.json +51 -51
- package/samples/harmonic-motion.aha-course.json +56 -56
package/lib/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as courseProgress, A as streamCounter, B as documentParts, C as reworkPrompt, D as generateJson, E as TutorError, F as materialsSummary, G as createConceptState, H as passageRange, I as passagesFor, J as extractJson, K as masteryPercent, L as readMaterials, M as emptyProgress, N as masteryFor, O as generateSteps, P as materialImages, Q as conceptIndex, R as readProfile, S as revisePrompt, T as summaryPrompt, U as spreadPassages, V as formatPassages, W as applyEvidence, X as normalizeBoard, Y as boardToPlainText, Z as blueprintOutline, _ as projectReviewPrompt, _t as newId, a as blueprintPrompt, at as nextLesson, b as quizPrompt, c as detectLanguage, ct as normalizeCheatsheet, d as flashcardsPrompt, dt as normalizeProject, et as findLesson, f as gradePrompt, ft as normalizeQuestionnaire, g as profilePrompt, gt as assertId, h as practicePrompt, ht as text, i as assistPrompt, it as lessonAfter, j as EMPTY_PROFILE, k as generateText, l as digestPartPrompt, lt as normalizeLesson, m as materialBriefPrompt, mt as safeRelativePath, n as publishRuntime, nt as insertLesson, o as cheatsheetPrompt, ot as normalizeBlueprint, p as lessonPrompt, pt as outlineForPrompt, q as recommendNext, r as askPrompt, rt as intakeSummary, s as correctionPrompt, st as normalizeCards, tt as flattenLessons, u as digestPrompt, ut as normalizePractice, v as projectsPrompt, w as shortPrompt, x as reexplainPrompt, y as questionnairePrompt, z as readProgress } from "./runtime-BCGFUDlg.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { dirname, join, relative, sep } from "node:path";
|
|
4
4
|
import { credentialKey } from "@deepseek-ai/dsh-credentials";
|
|
5
|
+
import { lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
6
|
+
import { lookup } from "node:dns";
|
|
7
|
+
import http from "node:http";
|
|
8
|
+
import https from "node:https";
|
|
9
|
+
import { isIP } from "node:net";
|
|
10
|
+
import { pipeline } from "node:stream";
|
|
11
|
+
import zlib from "node:zlib";
|
|
5
12
|
import { spawn } from "node:child_process";
|
|
6
13
|
import { existsSync } from "node:fs";
|
|
7
|
-
import { lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
8
14
|
import { fileURLToPath } from "node:url";
|
|
9
15
|
import { homedir } from "node:os";
|
|
10
16
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -211,6 +217,25 @@ const TIMELINES = [
|
|
|
211
217
|
"balanced",
|
|
212
218
|
"relaxed"
|
|
213
219
|
];
|
|
220
|
+
const SIZES = [
|
|
221
|
+
"auto",
|
|
222
|
+
"short",
|
|
223
|
+
"standard",
|
|
224
|
+
"full"
|
|
225
|
+
];
|
|
226
|
+
function outlineStream(api) {
|
|
227
|
+
let soFar = "";
|
|
228
|
+
const counter = streamCounter("\"estMinutes\"", (count) => {
|
|
229
|
+
api.progress(count, 0, "blueprint");
|
|
230
|
+
try {
|
|
231
|
+
api.preview(blueprintOutline(extractJson(soFar)));
|
|
232
|
+
} catch {}
|
|
233
|
+
});
|
|
234
|
+
return (delta) => {
|
|
235
|
+
soFar += String(delta ?? "");
|
|
236
|
+
counter(delta);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
214
239
|
function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date() }) {
|
|
215
240
|
const stamp = () => now().toISOString();
|
|
216
241
|
async function readCourse(courseId) {
|
|
@@ -259,7 +284,11 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
259
284
|
}
|
|
260
285
|
async function get({ courseId }) {
|
|
261
286
|
const course = await readCourse(courseId);
|
|
262
|
-
const [progress, intake] = await Promise.all([
|
|
287
|
+
const [progress, intake, proposal] = await Promise.all([
|
|
288
|
+
readProgress(store, courseId),
|
|
289
|
+
store.readJson(store.paths.intake(courseId), null),
|
|
290
|
+
store.readJson(store.paths.proposal(courseId), null)
|
|
291
|
+
]);
|
|
263
292
|
const boards = new Set(await store.listIds(store.paths.boardsDir(courseId), "les"));
|
|
264
293
|
const practice = new Set(await store.listIds(store.paths.practiceDir(courseId), "les"));
|
|
265
294
|
const sheets = new Set(await store.listIds(store.paths.sheetsDir(courseId), "unt"));
|
|
@@ -267,7 +296,9 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
267
296
|
course,
|
|
268
297
|
progress,
|
|
269
298
|
intake,
|
|
299
|
+
proposal,
|
|
270
300
|
jobs: {
|
|
301
|
+
questions: jobs.running(`questions:${courseId}`),
|
|
271
302
|
blueprint: jobs.running(`blueprint:${courseId}`),
|
|
272
303
|
confirm: jobs.running(`confirm:${courseId}`)
|
|
273
304
|
},
|
|
@@ -327,9 +358,12 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
327
358
|
courseId,
|
|
328
359
|
questionnaire
|
|
329
360
|
};
|
|
330
|
-
}, {
|
|
361
|
+
}, {
|
|
362
|
+
key: `questions:${courseId}`,
|
|
363
|
+
meta: { courseId }
|
|
364
|
+
});
|
|
331
365
|
}
|
|
332
|
-
function submitIntake({ courseId, answers = {}, timeline = "balanced", weeklyMinutes, deadline }) {
|
|
366
|
+
function submitIntake({ courseId, answers = {}, timeline = "balanced", size = "auto", weeklyMinutes, deadline }) {
|
|
333
367
|
assertId(courseId, "crs");
|
|
334
368
|
return jobs.start("craft/blueprint", async (api) => {
|
|
335
369
|
const course = await readCourse(courseId);
|
|
@@ -343,14 +377,16 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
343
377
|
answers: cleanAnswers,
|
|
344
378
|
at: stamp()
|
|
345
379
|
});
|
|
380
|
+
if (course.materialIds?.length) api.progress(0, 0, "materials");
|
|
346
381
|
const materials = await readMaterials(store, course.materialIds ?? []);
|
|
347
382
|
const profile = await readProfile(store);
|
|
348
383
|
const settings = {
|
|
349
384
|
timeline: TIMELINES.includes(timeline) ? timeline : "balanced",
|
|
385
|
+
size: SIZES.includes(size) ? size : "auto",
|
|
350
386
|
weeklyMinutes: clampMinutes(weeklyMinutes),
|
|
351
387
|
deadline: /^\d{4}-\d{2}-\d{2}$/u.test(String(deadline ?? "")) ? deadline : null
|
|
352
388
|
};
|
|
353
|
-
api.progress(0,
|
|
389
|
+
api.progress(0, 0, "blueprint");
|
|
354
390
|
const blueprint = await generateJson(llm, {
|
|
355
391
|
purpose: "teach",
|
|
356
392
|
prompt: blueprintPrompt({
|
|
@@ -360,11 +396,13 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
360
396
|
materialsSummary: materialsSummary(materials),
|
|
361
397
|
profile,
|
|
362
398
|
timeline: settings.timeline,
|
|
399
|
+
size: settings.size,
|
|
363
400
|
weeklyMinutes: settings.weeklyMinutes
|
|
364
401
|
}),
|
|
365
402
|
images: llm.supportsImages?.("teach") ? await materialImages(store, materials) : void 0,
|
|
366
403
|
maxTokens: 16e3,
|
|
367
404
|
signal: api.signal,
|
|
405
|
+
onText: outlineStream(api),
|
|
368
406
|
normalize: (raw) => attachProjectUnits(raw, normalizeBlueprint(raw, { language: course.language }))
|
|
369
407
|
});
|
|
370
408
|
const next = {
|
|
@@ -375,7 +413,6 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
375
413
|
settings
|
|
376
414
|
};
|
|
377
415
|
await saveCourse(next);
|
|
378
|
-
api.progress(1, 1, "blueprint");
|
|
379
416
|
return { course: next };
|
|
380
417
|
}, {
|
|
381
418
|
key: `blueprint:${courseId}`,
|
|
@@ -388,38 +425,100 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
388
425
|
return jobs.start("craft/revise", async (api) => {
|
|
389
426
|
const course = await readCourse(courseId);
|
|
390
427
|
if (!course.units) throw new TutorError("invalid", "There is no blueprint to revise yet");
|
|
428
|
+
const current = {
|
|
429
|
+
title: course.title,
|
|
430
|
+
subtitle: course.subtitle,
|
|
431
|
+
emoji: course.emoji,
|
|
432
|
+
summary: course.summary,
|
|
433
|
+
level: course.level,
|
|
434
|
+
units: course.units,
|
|
435
|
+
projects: course.projects
|
|
436
|
+
};
|
|
437
|
+
api.progress(0, 0, "blueprint");
|
|
391
438
|
const revised = await generateJson(llm, {
|
|
392
439
|
purpose: "teach",
|
|
393
440
|
prompt: revisePrompt({
|
|
394
|
-
blueprint:
|
|
395
|
-
title: course.title,
|
|
396
|
-
subtitle: course.subtitle,
|
|
397
|
-
emoji: course.emoji,
|
|
398
|
-
summary: course.summary,
|
|
399
|
-
level: course.level,
|
|
400
|
-
units: course.units,
|
|
401
|
-
projects: course.projects
|
|
402
|
-
},
|
|
441
|
+
blueprint: current,
|
|
403
442
|
instruction: request,
|
|
404
443
|
language: course.language
|
|
405
444
|
}),
|
|
406
445
|
maxTokens: 16e3,
|
|
407
446
|
signal: api.signal,
|
|
447
|
+
onText: streamCounter("\"estMinutes\"", (count) => api.progress(count, 0, "blueprint")),
|
|
408
448
|
normalize: (raw) => attachProjectUnits(raw, normalizeBlueprint(raw, { language: course.language }))
|
|
409
449
|
});
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
450
|
+
const proposal = {
|
|
451
|
+
instruction: request,
|
|
452
|
+
at: stamp(),
|
|
453
|
+
blueprint: revised
|
|
454
|
+
};
|
|
455
|
+
await store.writeJson(store.paths.proposal(courseId), proposal);
|
|
456
|
+
return {
|
|
457
|
+
course,
|
|
458
|
+
proposal
|
|
415
459
|
};
|
|
416
|
-
await saveCourse(next);
|
|
417
|
-
return { course: next };
|
|
418
460
|
}, {
|
|
419
461
|
key: `blueprint:${courseId}`,
|
|
420
462
|
meta: { courseId }
|
|
421
463
|
});
|
|
422
464
|
}
|
|
465
|
+
async function applyProposal({ courseId }) {
|
|
466
|
+
const course = await readCourse(courseId);
|
|
467
|
+
const proposal = await store.readJson(store.paths.proposal(courseId), null);
|
|
468
|
+
if (!proposal?.blueprint?.units) throw new TutorError("not-found", "There is no proposed change");
|
|
469
|
+
const next = {
|
|
470
|
+
...course,
|
|
471
|
+
...proposal.blueprint,
|
|
472
|
+
language: course.language,
|
|
473
|
+
status: course.status === "ready" ? "ready" : "blueprint"
|
|
474
|
+
};
|
|
475
|
+
await saveCourse(next);
|
|
476
|
+
await store.removeDir(store.paths.proposal(courseId));
|
|
477
|
+
return { course: next };
|
|
478
|
+
}
|
|
479
|
+
async function discardProposal({ courseId }) {
|
|
480
|
+
assertId(courseId, "crs");
|
|
481
|
+
await store.removeDir(store.paths.proposal(courseId));
|
|
482
|
+
return { ok: true };
|
|
483
|
+
}
|
|
484
|
+
function reworkLesson({ courseId, lesson: raw, unitTitle, lectureTitle, mode }) {
|
|
485
|
+
const split = mode === "split";
|
|
486
|
+
const lesson = normalizeLesson(raw);
|
|
487
|
+
if (!lesson) throw new TutorError("invalid", "Unknown lesson");
|
|
488
|
+
return jobs.start("craft/rework", async (api) => {
|
|
489
|
+
const course = await readCourse(courseId);
|
|
490
|
+
return { lessons: await generateJson(llm, {
|
|
491
|
+
purpose: "teach",
|
|
492
|
+
prompt: reworkPrompt({
|
|
493
|
+
outline: outlineForPrompt(course, { maxChars: 4e3 }),
|
|
494
|
+
unitTitle: text(unitTitle, 120),
|
|
495
|
+
lectureTitle: text(lectureTitle, 120),
|
|
496
|
+
lesson: {
|
|
497
|
+
title: lesson.title,
|
|
498
|
+
summary: lesson.summary,
|
|
499
|
+
objectives: lesson.objectives,
|
|
500
|
+
concepts: lesson.concepts.map((concept) => concept.name),
|
|
501
|
+
estMinutes: lesson.estMinutes
|
|
502
|
+
},
|
|
503
|
+
mode: split ? "split" : "deepen",
|
|
504
|
+
language: course.language
|
|
505
|
+
}),
|
|
506
|
+
maxTokens: 3e3,
|
|
507
|
+
signal: api.signal,
|
|
508
|
+
normalize: (value) => {
|
|
509
|
+
const list = (Array.isArray(value?.lessons) ? value.lessons : [value]).map((entry) => normalizeLesson({
|
|
510
|
+
...entry,
|
|
511
|
+
id: void 0
|
|
512
|
+
})).filter(Boolean).slice(0, split ? 3 : 1);
|
|
513
|
+
if (split ? list.length < 2 : !list.length) throw new Error("no usable lessons");
|
|
514
|
+
return list;
|
|
515
|
+
}
|
|
516
|
+
}) };
|
|
517
|
+
}, {
|
|
518
|
+
key: `rework:${courseId}:${lesson.id}`,
|
|
519
|
+
meta: { courseId }
|
|
520
|
+
});
|
|
521
|
+
}
|
|
423
522
|
async function saveBlueprint({ courseId, blueprint }) {
|
|
424
523
|
const course = await readCourse(courseId);
|
|
425
524
|
const normalized = normalizeBlueprint({
|
|
@@ -438,11 +537,40 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
438
537
|
await saveCourse(next);
|
|
439
538
|
return { course: next };
|
|
440
539
|
}
|
|
540
|
+
async function writeLecturePractice({ course, lecture, lessons = lecture.lessons, materials, signal }) {
|
|
541
|
+
const query = lessons.map((lesson) => `${lesson.title} ${lesson.objectives.join(" ")}`).join(" ");
|
|
542
|
+
const sources = materials ?? await readMaterials(store, course.materialIds ?? []);
|
|
543
|
+
const sets = await generateJson(llm, {
|
|
544
|
+
purpose: "teach",
|
|
545
|
+
prompt: practicePrompt({
|
|
546
|
+
course,
|
|
547
|
+
lecture,
|
|
548
|
+
lessons,
|
|
549
|
+
language: course.language,
|
|
550
|
+
passages: passagesFor(sources, query, 5e3)
|
|
551
|
+
}),
|
|
552
|
+
maxTokens: Math.min(16e3, 3e3 + lessons.length * 2600),
|
|
553
|
+
signal,
|
|
554
|
+
normalize: (raw) => raw?.lessons ?? raw
|
|
555
|
+
});
|
|
556
|
+
const written = {};
|
|
557
|
+
for (const lesson of lessons) {
|
|
558
|
+
const set = normalizePractice(sets?.[lesson.id] ?? sets?.[lesson.title] ?? (lessons.length === 1 ? Object.values(sets ?? {})[0] : void 0) ?? { items: [] }, lesson.concepts.map((concept) => concept.id));
|
|
559
|
+
if (!set.items.length) continue;
|
|
560
|
+
written[lesson.id] = {
|
|
561
|
+
lessonId: lesson.id,
|
|
562
|
+
...set,
|
|
563
|
+
createdAt: stamp()
|
|
564
|
+
};
|
|
565
|
+
await store.writeJson(store.paths.practice(course.id, lesson.id), written[lesson.id]);
|
|
566
|
+
}
|
|
567
|
+
return written;
|
|
568
|
+
}
|
|
441
569
|
function confirm({ courseId }) {
|
|
442
570
|
return jobs.start("craft/confirm", async (api) => {
|
|
443
571
|
const course = await readCourse(courseId);
|
|
444
572
|
if (!course.units) throw new TutorError("invalid", "Generate a blueprint first");
|
|
445
|
-
const lectures = course.units.flatMap((unit) => unit.lectures.map((lecture) => ({
|
|
573
|
+
const lectures = course.units.slice(0, 1).flatMap((unit) => unit.lectures.map((lecture) => ({
|
|
446
574
|
unit,
|
|
447
575
|
lecture
|
|
448
576
|
})));
|
|
@@ -489,29 +617,12 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
489
617
|
api.signal.throwIfAborted();
|
|
490
618
|
const { lecture } = queue.shift();
|
|
491
619
|
try {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
lecture,
|
|
498
|
-
lessons: lecture.lessons,
|
|
499
|
-
language: course.language,
|
|
500
|
-
passages: passagesFor(materials, query, 5e3)
|
|
501
|
-
}),
|
|
502
|
-
maxTokens: 9e3,
|
|
503
|
-
signal: api.signal,
|
|
504
|
-
normalize: (raw) => raw?.lessons ?? raw
|
|
620
|
+
await writeLecturePractice({
|
|
621
|
+
course,
|
|
622
|
+
lecture,
|
|
623
|
+
materials,
|
|
624
|
+
signal: api.signal
|
|
505
625
|
});
|
|
506
|
-
for (const lesson of lecture.lessons) {
|
|
507
|
-
const conceptIds = lesson.concepts.map((concept) => concept.id);
|
|
508
|
-
const set = normalizePractice(sets?.[lesson.id] ?? sets?.[lesson.title] ?? { items: [] }, conceptIds);
|
|
509
|
-
if (set.items.length) await store.writeJson(store.paths.practice(course.id, lesson.id), {
|
|
510
|
-
lessonId: lesson.id,
|
|
511
|
-
...set,
|
|
512
|
-
createdAt: stamp()
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
626
|
} catch (error) {
|
|
516
627
|
if (api.signal.aborted) throw error;
|
|
517
628
|
warnings.push(lecture.id);
|
|
@@ -617,7 +728,11 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
|
|
|
617
728
|
startCraft,
|
|
618
729
|
submitIntake,
|
|
619
730
|
revise,
|
|
731
|
+
applyProposal,
|
|
732
|
+
discardProposal,
|
|
733
|
+
reworkLesson,
|
|
620
734
|
saveBlueprint,
|
|
735
|
+
writeLecturePractice,
|
|
621
736
|
confirm,
|
|
622
737
|
update,
|
|
623
738
|
remove,
|
|
@@ -663,12 +778,297 @@ function safeFileName(value) {
|
|
|
663
778
|
return /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/iu.test(cleaned) || !cleaned ? "course" : cleaned;
|
|
664
779
|
}
|
|
665
780
|
//#endregion
|
|
781
|
+
//#region src/core/board-fonts.js
|
|
782
|
+
const BOARD_FONT_FILES = Object.freeze([
|
|
783
|
+
Object.freeze({
|
|
784
|
+
family: "Aha Hand Latin",
|
|
785
|
+
file: "caveat-latin-d0b7b931.woff2",
|
|
786
|
+
bytes: 48836,
|
|
787
|
+
unicodeRange: "U+0,U+D,U+20-7E,U+A0-FF,U+131,U+152-153,U+20AC,U+2122"
|
|
788
|
+
}),
|
|
789
|
+
Object.freeze({
|
|
790
|
+
family: "Aha Hand",
|
|
791
|
+
file: "wenkai-gb-0-88f1a875.woff2",
|
|
792
|
+
bytes: 93632,
|
|
793
|
+
unicodeRange: "U+20-7E,U+A0-AC,U+AE-FF,U+101,U+113,U+11B,U+12B,U+14D,U+16B,U+1CE,U+1D0,U+1D2,U+1D4,U+1D6,U+1D8,U+1DA,U+1DC,U+2C7,U+2C9,U+391-3A1,U+3A3-3A9,U+3B1-3C1,U+3C3-3C9,U+401,U+410-44F,U+451,U+2010-2016,U+2018-2022,U+2025-2027,U+2030-2037,U+2039-203F,U+2042,U+2044,U+2047-2049,U+2051-2052,U+205A,U+205D,U+2100-2101,U+2103,U+2105-2106,U+2109-210A,U+210E-210F,U+2113,U+2116-2117,U+211E,U+2120-2122,U+2126-2127,U+2129-212B,U+212E,U+2132,U+2135,U+213B,U+2141-2144,U+214B,U+214D-214E,U+2150-218B,U+2190-2199,U+21B6-21B9,U+21C4-21C6,U+21CB-21D0,U+21D2,U+21D4,U+21E6-21EA,U+21F5,U+2200-220D,U+220F,U+2211-2213,U+2215-2216,U+2219-2220,U+2223-2230,U+2234-2237,U+223C-223E,U+2242-2243,U+2245,U+2248,U+224B-224C,U+2251-2253,U+225C,U+2260-2262,U+2264-226B,U+226E-226F,U+2272-2273,U+2276-2277,U+2282-228B,U+2295-2299,U+229C-229E,U+22A0,U+22A2-22A5,U+22BF-22C5,U+22DA-22DB,U+22EE-22F1,U+2312,U+2460-249F,U+2500-25AB,U+25B1-25B3,U+25B6-25B7,U+25BC-25BD,U+25C0-25C1,U+25C6-25C7,U+25C9-25CC,U+25CE-25D3,U+25E2-25E6,U+25EF,U+25FB-25FC,U+2605-2606,U+2640,U+2642,U+3000-302D,U+3030,U+3033-303F,U+3041-3093,U+30A1-30F6,U+30FB,U+3105-3129,U+3220-3229,U+FF01-FF5E,U+FFE0-FFE1,U+FFE3,U+FFE5"
|
|
794
|
+
}),
|
|
795
|
+
Object.freeze({
|
|
796
|
+
family: "Aha Hand",
|
|
797
|
+
file: "wenkai-gb-1-78a38e72.woff2",
|
|
798
|
+
bytes: 315108,
|
|
799
|
+
unicodeRange: "U+4E01,U+4E0D,U+4E11,U+4E19,U+4E1B-4E1C,U+4E22,U+4E2A,U+4E30,U+4E32,U+4E39,U+4E4E-4E4F,U+4E56,U+4E58,U+4E8C,U+4E92,U+4EA4-4EA5,U+4EA7-4EA8,U+4EC7,U+4ECE,U+4ED3,U+4ED8,U+4EE3,U+4EF6-4EF7,U+4EFD,U+4EFF,U+4F0E-4F10,U+4F19-4F1A,U+4F20,U+4F2F-4F30,U+4F34,U+4F43,U+4F46,U+4F4E,U+4F55,U+4F5B,U+4F70,U+4F73,U+4F88,U+4F97,U+4F9B,U+4FA7,U+4FAF,U+4FBF,U+4FC3-4FC4,U+4FD8,U+4FDD,U+4FED,U+4FEF,U+4FFA,U+500D,U+5012,U+5019,U+5021,U+5047,U+5065,U+507F,U+5085,U+508D,U+50A3,U+50A8,U+50AC,U+50B2,U+50F5,U+513F,U+5145,U+5149,U+5151,U+515A,U+515C,U+516B-516C,U+5171,U+5173,U+5175,U+5178,U+517C,U+5180,U+5188,U+518C,U+51A0,U+51AC,U+51AF-51B0,U+51B2,U+51BB,U+51CB,U+51CF,U+51D1,U+51E0-51E1,U+51E4,U+51F0,U+51F3,U+51F9-51FB,U+51FD,U+5200-5201,U+5206,U+5212,U+521A-521B,U+521D,U+522B,U+522E,U+5230,U+523A,U+523D,U+5241-5242,U+5250-5251,U+5265,U+526A,U+526F,U+5272,U+529E-52A0,U+52A8,U+52C3,U+52FE,U+5305-5306,U+5316-5317,U+5319,U+5320,U+532A,U+5349-534A,U+534E,U+5351,U+5355,U+535A,U+535C,U+535E,U+5373,U+5382,U+5384,U+5395,U+539A,U+53A8,U+53C2,U+53C9-53CA,U+53CD,U+53D1,U+53D8,U+53E0,U+53E4,U+53ED-53EE,U+53F7,U+53FC,U+5403-5404,U+5408-540A,U+540E,U+5420,U+5426-5429,U+542B,U+5435,U+5439,U+543C,U+5446,U+5448,U+544A,U+5475,U+547C,U+548C,U+5490,U+5495,U+54C0,U+54C4,U+54C6,U+54C8,U+54CE,U+54D7,U+54E5,U+54FA,U+54FC,U+5507,U+5509,U+5524,U+552C,U+5531,U+554A,U+5561,U+5589-558A,U+5598,U+559D,U+5609,U+560E,U+5632,U+563F,U+5676,U+568E,U+56DE,U+56E4,U+56F1,U+56FA,U+56FD,U+572D,U+5730,U+573A,U+573E,U+574A,U+574F,U+575A,U+575D,U+575F,U+5782,U+579B,U+57A2,U+57AB,U+57C2-57C3,U+57CE,U+57E0,U+57FA,U+5806,U+5815,U+5821,U+5824,U+5835,U+58A9,U+58C1,U+58D5,U+58F6,U+5904,U+5907,U+590D,U+591A,U+591F,U+5927,U+592B,U+592F,U+5939-593A,U+5949,U+594B,U+5954,U+5956,U+5960,U+5965,U+5978,U+597D,U+5987,U+5992-5993,U+59A8,U+59D1,U+59DC,U+59EC,U+5A25,U+5A5A,U+5AC1,U+5AC9,U+5AE1,U+5B58,U+5B63-5B64,U+5B69,U+5B75,U+5B89,U+5B8F,U+5B98,U+5B9A,U+5B9D,U+5BA0,U+5BA6,U+5BAB,U+5BB3,U+5BB6,U+5BBE,U+5BC2,U+5BC4,U+5BCC,U+5BD2,U+5BDF,U+5BE1,U+5BF8-5BF9,U+5BFC,U+5C01,U+5C06,U+5C14,U+5C16,U+5C18,U+5C1D,U+5C3A,U+5C42,U+5C94,U+5C97,U+5C9B,U+5CB8,U+5CE8,U+5CF0,U+5D07,U+5D14,U+5D29,U+5DDD,U+5DE2,U+5DE5,U+5DE9,U+5DEE,U+5DF1,U+5DF4,U+5E01,U+5E03,U+5E06,U+5E1B,U+5E1D,U+5E26,U+5E2E,U+5E38,U+5E45,U+5E4C,U+5E62,U+5E72,U+5E76,U+5E7B,U+5E7F,U+5E87,U+5E8A,U+5E95,U+5E97,U+5E9A,U+5E9C,U+5E9F,U+5EA6,U+5EFA,U+5F0A,U+5F13,U+5F17-5F18,U+5F1B,U+5F1F,U+5F27,U+5F39,U+5F52-5F53,U+5F69-5F6A,U+5F6C,U+5F7B-5F7C,U+5F85,U+5F88,U+5F8A,U+5F97,U+5FB7,U+5FBD,U+5FC5,U+5FCC,U+5FF1,U+5FFD,U+5FFF-6000,U+6016,U+6020,U+6025,U+602A,U+604D,U+6052,U+6062,U+6068-6069,U+606B,U+606D,U+6076,U+608D,U+6094,U+60A3,U+60B2,U+60B8,U+60BC,U+60D1,U+60E0,U+60E6,U+60E8-60E9,U+60EB,U+60ED-60F0,U+60F6,U+6101,U+611F,U+6124,U+6148,U+614C,U+6167,U+618B,U+61A8,U+61BE,U+61C2,U+61CA,U+6208,U+6210,U+6216,U+6233-6234,U+6237,U+623F,U+6241,U+624D,U+6252-6253,U+626E-626F,U+6273,U+6276,U+627C,U+627F-6280,U+6284,U+628A,U+6296,U+629A,U+62A4-62A5,U+62B1,U+62B5,U+62BD,U+62C2,U+62C5-62C6,U+62CC,U+62D0,U+62D4,U+62DC,U+62E3,U+62E8,U+62F1,U+6301-6302,U+6309,U+6321,U+6324-6325,U+6328,U+632B,U+634C-634D,U+6355,U+6361-6363,U+6376,U+6382,U+6387,U+6389,U+63A3,U+63AA,U+63B8,U+63BA,U+63D2,U+63E3,U+6400-6401,U+640F-6410,U+6413,U+641E,U+642C-642D,U+643D,U+6446,U+6448,U+6467,U+6491,U+64A4,U+64AD-64AE,U+64BC,U+64CD,U+64E6,U+6539,U+653B,U+653E,U+6545,U+654C,U+6556,U+655D-655E,U+6562,U+6566,U+6577,U+658C,U+6591,U+6597,U+65A5,U+65A7,U+65AD,U+65B9,U+65E2,U+65E6,U+65F1,U+6602,U+660C,U+660F,U+6625,U+6643,U+6666,U+6668,U+6697,U+66B4,U+66F4,U+66F9,U+670D,U+671D,U+672C,U+6735,U+673A,U+6746,U+6750-6751,U+675C,U+6760,U+676D,U+676F,U+677F,U+6781,U+6784,U+679C,U+67AB,U+67B6-67B7,U+67C4,U+67CF,U+67D1,U+67DC,U+67E5,U+67EC,U+67F4,U+6807,U+680B,U+6838-6839,U+683C,U+6842,U+6848,U+6853,U+6863,U+6868,U+6886,U+6897,U+68C0,U+68CD,U+68D2,U+68D8,U+68FA,U+6912,U+693D,U+693F,U+695A,U+6982,U+699C,U+69D0,U+69DB,U+69FD,U+6A0A,U+6A2A,U+6A59,U+6A71,U+6B21-6B22,U+6B4C,U+6B64-6B65,U+6B79,U+6B7C,U+6B86,U+6B8B,U+6BB5,U+6BBF,U+6BC1,U+6BD2,U+6BD4-6BD6,U+6BD9,U+6BEB,U+6C1B,U+6C1F,U+6C26,U+6C28,U+6C2E,U+6C47,U+6C49,U+6C57,U+6C5E-6C60,U+6C72,U+6C7E,U+6C89,U+6C9F,U+6CA7,U+6CAA,U+6CB3,U+6CB8,U+6CBD,U+6CCA,U+6CD5,U+6CDB,U+6CE2,U+6CF5,U+6D1E,U+6D2A,U+6D31,U+6D3B,U+6D46-6D47,U+6D4B,U+6D4E,U+6D51,U+6D69,U+6D6E,U+6D77,U+6DA3-6DA4,U+6DA7,U+6DAA,U+6DB5,U+6DB8,U+6DC0,U+6DE1,U+6DEC,U+6DEE,U+6DF3,U+6DF7,U+6E10,U+6E21,U+6E24,U+6E2F,U+6E56,U+6E85,U+6E89,U+6EC1,U+6EC7,U+6ED1,U+6EDA,U+6EE8,U+6EF4,U+6F6E,U+6F84,U+6F88,U+6FB3,U+6FC0,U+6FD2,U+704C,U+706B,U+706F-7070,U+707F,U+708A,U+7092,U+70B3,U+70B9,U+70BD,U+70D8,U+70E6,U+70E9,U+70FD,U+710A,U+7115,U+7119-711A,U+7126,U+714C,U+714E,U+71AC,U+7206,U+7231,U+7236,U+7238-7239,U+7248,U+728A,U+72AF,U+72C4,U+72C8,U+72D0,U+72D7,U+72E0,U+72EC,U+7316,U+731C,U+7334,U+733E,U+73AF,U+73BB,U+73D0,U+73ED,U+745A,U+7470,U+74DC,U+74E3,U+74F7,U+7518,U+752B,U+752D,U+7532,U+7535,U+7538,U+753B,U+7545,U+756A,U+7574,U+7578,U+7586,U+7599,U+75A4,U+75AE-75AF,U+75B5,U+75BE,U+75C5,U+75D5,U+75D8,U+75EA,U+75F4,U+75F9,U+7601,U+7629-762A,U+764C,U+7678,U+767B,U+767D-767E,U+7684,U+7687,U+768B,U+7691,U+76CE,U+76D1-76D2,U+76D6-76D7,U+76EF,U+76FE,U+7763,U+776C,U+7779,U+7785,U+77AA,U+77D7,U+77ED-77EE,U+77FE,U+7840,U+7845,U+7877,U+7889,U+788D,U+7891,U+7898,U+789F,U+78A7,U+78B1,U+78B4,U+78C1,U+78C5,U+78CB,U+78FA,U+7901,U+796D,U+7977-7978,U+798F,U+79BE,U+79C6,U+79C9,U+79E4,U+79EF-79F0,U+79FD,U+7A0B,U+7A17,U+7A20,U+7A3B-7A3D,U+7A3F,U+7A7F,U+7A97,U+7A9C,U+7AEF,U+7AFF,U+7B06,U+7B14,U+7B1B,U+7B26,U+7B28,U+7B2C,U+7B3A,U+7B49,U+7B4F,U+7B54,U+7B56,U+7B79,U+7B80,U+7B8D,U+7B94-7B95,U+7BA1,U+7BAD,U+7BD9,U+7BE1,U+7C07,U+7C27,U+7C3F,U+7C4D,U+7C89,U+7C97,U+7CAA,U+7CB9,U+7CCA,U+7CD5,U+7CD9,U+7E41,U+7EA2,U+7EA7,U+7EAA,U+7EAF,U+7EB2,U+7EB7,U+7EBA,U+7ECA,U+7ED1,U+7ED8-7ED9,U+7EE7,U+7EE9,U+7EF0,U+7EF7-7EF8,U+7F04,U+7F09,U+7F0E,U+7F13-7F14,U+7F16,U+7F1A,U+7F1D,U+7F20,U+7F38,U+7F50,U+7F55,U+7F5A,U+7F62,U+7F94,U+7FB9,U+7FC5,U+7FDF-7FE0,U+7FF0-7FF1,U+7FFB,U+800C,U+8015,U+8017,U+8019,U+8033,U+803B,U+803D,U+803F,U+806A,U+808C,U+809A-809B,U+809D,U+80A0-80A1,U+80A4-80A5,U+80A9-80AA,U+80AE,U+80BA,U+80C6,U+80CC,U+80DE,U+80E1,U+80F3,U+80F6,U+80FA,U+8106,U+810A,U+8116,U+812F,U+8150-8151,U+8179,U+8180,U+818A,U+818F,U+8198,U+81C2,U+81E3,U+81ED,U+822A,U+822C,U+8230-8231,U+8235-8236,U+8239,U+8270,U+827E,U+82AC-82AD,U+82B1,U+82B3,U+82CD,U+82DE-82DF,U+82EF,U+8303,U+8327-8328,U+832C,U+8336,U+8349,U+8350,U+8352,U+835A,U+8361,U+8364,U+8377,U+83B7,U+83C7,U+83CF,U+83DC,U+83E0,U+83F2,U+845B,U+8463,U+846B,U+8471,U+8482,U+848B,U+84D6,U+84DF,U+8521,U+853C-853D,U+8549,U+8584,U+85CF,U+85E9,U+864E,U+866B,U+8679,U+868C,U+8695,U+86CA-86CB,U+86D4,U+86E4,U+86FE,U+8702,U+8749,U+8757,U+8774,U+8776,U+8822,U+8861,U+8865,U+8868,U+886C,U+8884,U+888B,U+88AB,U+88B1,U+88C1,U+88F9,U+8902,U+8910,U+8912,U+8986,U+89C1-89C2,U+89C4,U+89E6,U+8BA1-8BA3,U+8BA5,U+8BB0,U+8BB2-8BB3,U+8BB9,U+8BBD,U+8BBF,U+8BCD,U+8BDA,U+8BDD-8BDE,U+8BE1,U+8BE5,U+8BE7,U+8BF2,U+8BFB,U+8BFD,U+8C03,U+8C0D-8C0E,U+8C17,U+8C24,U+8C37,U+8C41,U+8C46,U+8C62,U+8C6A,U+8C79-8C7A,U+8C89,U+8D1D,U+8D1F,U+8D21-8D22,U+8D25,U+8D27,U+8D29,U+8D2C-8D2D,U+8D2F-8D31,U+8D35,U+8D37,U+8D39-8D3A,U+8D3E-8D3F,U+8D4B-8D4C,U+8D50,U+8D63-8D64,U+8D6B,U+8D74,U+8D76,U+8D81,U+8D85,U+8DCB-8DCC,U+8DDF,U+8DEA,U+8DF5,U+8DFA,U+8E0C,U+8E29,U+8E48,U+8E66,U+8E6C-8E6D,U+8E72,U+8E7F,U+8E87,U+8EAC,U+8EB2,U+8F66,U+8F68,U+8F70,U+8F85,U+8F88-8F8A,U+8F90-8F91,U+8F9C,U+8F9E-8F9F,U+8FA8-8FA9,U+8FAB,U+8FB0,U+8FB9,U+8FBE,U+8FC7,U+8FD4,U+8FD8,U+8FDF,U+8FEA,U+8FED,U+8FF8-8FF9,U+9012,U+9017,U+901B,U+901E,U+9022,U+902E,U+903C,U+9041,U+904D,U+904F,U+9053,U+907F,U+9093,U+90A6,U+90AF,U+90CA,U+90DD,U+90E8,U+90ED,U+90F4,U+90F8,U+90FD,U+9102,U+9119,U+915A,U+9163,U+916C,U+9171,U+9187,U+918B,U+91C7,U+91DC,U+9274,U+9489,U+9492-9493,U+9499,U+949D-949E,U+94A1-94A2,U+94A9,U+94B5,U+94BE,U+94C2,U+94EC,U+94F2,U+9504-9505,U+950B,U+9519,U+9524,U+952D-952E,U+953B,U+9540,U+9550-9551,U+957F,U+95ED,U+95EF,U+95F4,U+95FA,U+9600-9602,U+9610,U+961C,U+961F,U+9632,U+963F,U+9644-9645,U+9648,U+964D,U+965B,U+9661,U+9664,U+9694,U+9698,U+96C6-96C7,U+96CC,U+96CF,U+96D5,U+96F9,U+970D,U+9738,U+975B,U+975E,U+9769,U+9776,U+978D,U+97AD,U+97E9,U+9876,U+987E-987F,U+9881,U+988A,U+989D,U+98A0,U+98A4,U+98CE,U+98DE,U+9910,U+9965,U+996D,U+996F,U+9971,U+9975,U+997C,U+997F,U+9986,U+998B,U+9A70,U+9A73,U+9A7E,U+9A84,U+9A87,U+9A8B,U+9AA8,U+9AB8,U+9AD8,U+9B3C,U+9B42,U+9C8D,U+9CD6,U+9E21,U+9E3D,U+9E3F,U+9E45,U+9E64,U+9EC4,U+9ED1,U+9F0E,U+9F13,U+9F3B,U+9F7F,U+9F9A,U+9F9F"
|
|
800
|
+
}),
|
|
801
|
+
Object.freeze({
|
|
802
|
+
family: "Aha Hand",
|
|
803
|
+
file: "wenkai-gb-2-2a649892.woff2",
|
|
804
|
+
bytes: 317648,
|
|
805
|
+
unicodeRange: "U+4E03,U+4E09-4E0A,U+4E14,U+4E16,U+4E18,U+4E24,U+4E27,U+4E34,U+4E3D-4E3E,U+4E43,U+4E45,U+4E48,U+4E50,U+4E52-4E54,U+4E5D-4E5E,U+4E70-4E71,U+4E73,U+4E7E,U+4E86,U+4E8B,U+4E8F,U+4E95,U+4EA2,U+4EA9,U+4EAC,U+4EAE,U+4EB2,U+4EBA,U+4EC0-4EC1,U+4EC5-4EC6,U+4ECA-4ECB,U+4ECD,U+4ED1,U+4ED5,U+4EDF,U+4EE4,U+4EEC,U+4EFB,U+4F01,U+4F1E,U+4F24,U+4F26,U+4F36,U+4F38,U+4F60,U+4F69,U+4F6C,U+4F7F,U+4F8B,U+4F8D,U+4FA3,U+4FA5,U+4FA8-4FA9,U+4FB5,U+4FCA,U+4FCF-4FD0,U+4FE9,U+4FF1,U+5014,U+501F,U+5026,U+502A,U+503E,U+504F,U+5076,U+5080,U+5088,U+50BB,U+50DA,U+50E7,U+50FB,U+5112,U+5121,U+514B,U+514D,U+5162,U+5165,U+5168,U+516D,U+5170,U+5176-5177,U+5185,U+5189,U+5192,U+5195,U+5197,U+519B-519C,U+51B3,U+51B5,U+51B7,U+51C0,U+51C4,U+51C9,U+51CC,U+51DB,U+51DD,U+51ED,U+51EF,U+5203,U+5207,U+520A,U+5217-5218,U+5220,U+5224,U+5228-5229,U+5238-5239,U+523B,U+524D,U+5256,U+5267,U+5269,U+527F,U+5288,U+529B,U+529D,U+52A3,U+52AA-52AB,U+52B1-52B3,U+52BF,U+52C9,U+52D2,U+52D8,U+52DF,U+52E4,U+52FA,U+5321,U+5339-533A,U+533F,U+5341,U+5343,U+5347,U+5356-5357,U+5361-5362,U+5364,U+536F,U+5374-5375,U+5377,U+537F,U+5386,U+5389,U+5398,U+53A9,U+53BB,U+53C1,U+53D6-53D7,U+53DB,U+53E3,U+53E5-53E6,U+53EB,U+53EF,U+53F2,U+540D,U+540F,U+5415,U+5417,U+541B,U+541D,U+542D,U+542F,U+5450,U+5455,U+545B,U+5462,U+5478,U+547B,U+547D,U+5480,U+5486,U+548E,U+5496,U+5499,U+54AF,U+54B3,U+54C1,U+54E6,U+54E8-54EA,U+54ED,U+552E,U+5543,U+5546,U+5564-5566,U+556A,U+556E,U+5580,U+5584,U+5587,U+55B7,U+55D3,U+55DC,U+561B,U+5668,U+566C,U+56B7,U+56BC,U+56CA,U+56DA,U+56F0,U+5703,U+5708,U+5723,U+5747,U+574E,U+5751,U+5757,U+5761,U+5764,U+576A,U+576F,U+5777,U+5783-5784,U+5792,U+57A6,U+57AE,U+57CB,U+57D4,U+57F9,U+5811,U+582A,U+585E,U+5883,U+5892-5893,U+5899,U+58A8,U+58E4,U+58EB-58EC,U+58F0,U+58F3,U+5931,U+5938,U+5947-5948,U+594E,U+5951,U+5962,U+5973-5974,U+5976,U+5982,U+5988,U+598A,U+5999,U+59AE,U+59B9,U+59BB,U+59C6,U+59CB,U+59D0,U+59E5,U+5A04,U+5A07,U+5A18,U+5A1C,U+5A1F-5A20,U+5A29,U+5A36,U+5A46,U+5A6A,U+5A76,U+5A92,U+5A9A,U+5AC2,U+5AE9,U+5B54,U+5B5F,U+5B6A,U+5B7A,U+5B7D,U+5B81,U+5B88,U+5B9E,U+5BA1-5BA2,U+5BA4,U+5BB9,U+5BBD,U+5BC6-5BC7,U+5BD0,U+5BDD-5BDE,U+5BE5,U+5BFF,U+5C04,U+5C11,U+5C1A,U+5C31,U+5C38,U+5C3C-5C3D,U+5C3F-5C41,U+5C45,U+5C48,U+5C4A,U+5C4E-5C4F,U+5C61,U+5C65,U+5C71,U+5C82,U+5CAD,U+5CBF,U+5CE6,U+5CED,U+5CFB,U+5D0E,U+5D4C,U+5DE7-5DE8,U+5DFE,U+5E02,U+5E08,U+5E15,U+5E18,U+5E3D,U+5E42,U+5E55,U+5E73-5E74,U+5E86,U+5E90,U+5E93,U+5E99,U+5E9E,U+5EB7,U+5EC9-5ECA,U+5ED3,U+5ED6,U+5F00,U+5F03-5F04,U+5F0F,U+5F25,U+5F31,U+5F3A,U+5F55,U+5F6D,U+5F84,U+5F8B,U+5F98,U+5FCD,U+5FD9,U+5FEB,U+5FF5,U+6012,U+6015,U+601C,U+602F,U+6043,U+604B,U+6050,U+6070,U+6073,U+607C,U+6084,U+60A8,U+60AF,U+60C5,U+60CA,U+60E7,U+60F9,U+6127,U+614E,U+6151,U+6155,U+6162,U+6168,U+6177,U+61D2,U+61E6,U+620E,U+6212,U+621A,U+622A,U+622E,U+6247,U+624B,U+6251,U+6254,U+625B,U+6263,U+6266,U+6269,U+626B,U+626D,U+6270,U+6279,U+6289,U+6297,U+629B,U+62A0-62A2,U+62A8,U+62AB,U+62B9,U+62BF,U+62C7-62C9,U+62CD-62CE,U+62D2,U+62D8,U+62DF,U+62E2,U+62E6-62E7,U+62EC-62ED,U+62F3,U+62F7,U+62FC,U+62FE-62FF,U+630E,U+631B,U+6320,U+632A,U+6346,U+634E-6350,U+635E,U+6367,U+636E,U+6377,U+637B,U+6388,U+6390,U+6392,U+6398,U+63A0,U+63A5,U+63A7,U+63B3,U+63C9,U+63CF,U+63E9-63EA,U+63ED,U+63FD,U+6402,U+6405,U+6414,U+6444,U+6469,U+6478-6479,U+6482,U+6485,U+6487,U+6492,U+64A9,U+64AC,U+64B5,U+64C2,U+64C5,U+64CE,U+64D2,U+6500,U+6518,U+652B,U+6536,U+654F,U+6551,U+6559,U+655B,U+6563,U+656C,U+6572,U+6599,U+65A4,U+65BD,U+65C1,U+65C5,U+65D7,U+65E5,U+65E7,U+65F6-65F7,U+6606,U+660E,U+6627,U+662F,U+664B-664C,U+6652,U+666E-666F,U+6674,U+6676,U+667E,U+6696,U+66AE,U+66DD,U+66F2,U+66FC,U+670B,U+6717,U+671F,U+6728,U+672B,U+6734,U+6740,U+6743,U+6749,U+674E,U+6765,U+6770,U+6797,U+679A,U+67AA,U+67AF,U+67D0,U+67D2-67D4,U+67E0,U+67EF,U+67F3,U+67FF,U+680F,U+6816-6817,U+6846,U+6851,U+6854,U+6865,U+6881,U+6885,U+68A2,U+68A6,U+68A8,U+68C9,U+68CB,U+68DA,U+68EE,U+68F1,U+68F5,U+695E,U+6977,U+697C,U+6994,U+69B4,U+69B7,U+6A21,U+6A47,U+6AAC,U+6B20,U+6B27,U+6B3A,U+6B3E,U+6B49,U+6B67,U+6BB4,U+6BCD,U+6BCF,U+6BD7,U+6BDB,U+6C0F,U+6C11,U+6C13-6C14,U+6C16,U+6C22,U+6C2F-6C30,U+6C42,U+6C55,U+6C5D,U+6C7D,U+6C81,U+6C88,U+6C8F,U+6C99,U+6C9B,U+6CA1,U+6CA4-6CA6,U+6CAB,U+6CAE,U+6CC5,U+6CC9,U+6CCC,U+6CDE,U+6CE1,U+6CE3,U+6CE5,U+6CEA,U+6CFC,U+6D01,U+6D12,U+6D1B,U+6D25,U+6D3D-6D3E,U+6D41,U+6D45,U+6D53,U+6D5A,U+6D66,U+6D6A,U+6D78,U+6D85,U+6D89,U+6D9D,U+6D9F,U+6DA6,U+6DA9,U+6DCB,U+6DD6,U+6DF1,U+6E05,U+6E17,U+6E20,U+6E34,U+6E3A,U+6E43,U+6E7F,U+6E83,U+6E9C,U+6EB6,U+6EBA,U+6EE1,U+6EE4-6EE6,U+6F02,U+6F06,U+6F0F,U+6F13,U+6F20,U+6F2B,U+6F58,U+6F5C,U+6F5E,U+6F66,U+6F8E,U+6F9C,U+7011,U+706D,U+7075,U+7078,U+7089,U+7094-7095,U+70AC,U+70AE-70AF,U+70BC,U+70C2,U+70C8,U+70D9,U+70E4,U+70E7,U+70EC-70ED,U+70F9,U+7136,U+715E,U+7164,U+717D,U+7194,U+71C3,U+71CE,U+722C,U+7235,U+7247,U+724C,U+725B,U+725F,U+7261-7262,U+7267,U+7272,U+7275,U+7281,U+72AC,U+72C2,U+72D9,U+72DE,U+72E1,U+72EE,U+72F8,U+72FC,U+730E,U+731B,U+732B,U+7387,U+7396,U+739B,U+73AB,U+73B2,U+73CA,U+7403,U+7405-7406,U+7409,U+7433-7436,U+743C,U+745E-745F,U+7483,U+74E2,U+74E4,U+74F6,U+751A,U+751F,U+7525,U+7533,U+7537,U+754C,U+7554,U+7559,U+7565-7566,U+7597,U+759A,U+759F,U+75A5,U+75B2,U+75BD,U+75C9-75CA,U+75DE,U+75E2,U+7624,U+7638,U+7686,U+76AE,U+76BF,U+76C6,U+76D4,U+76D8,U+76DB,U+76DF,U+76EE,U+76F2,U+76FC,U+7701,U+7709,U+770B,U+7720,U+772F,U+7736-7737,U+775B,U+7766,U+776B,U+7784,U+7792,U+77A5,U+77A7,U+77DB,U+77E2,U+77E9,U+77EB,U+77F3,U+77FF,U+7801-7802,U+780C-780D,U+7812,U+7830,U+7834,U+7837,U+783E,U+786B,U+786E,U+787C,U+788C,U+78B0,U+78BE,U+78CA,U+78D0,U+78D5,U+78E8,U+78F7,U+793A,U+793C,U+793E,U+7941,U+7948,U+795E,U+7968,U+7981,U+7984,U+79BB,U+79BD,U+79CB,U+79D1-79D2,U+79D8,U+79E6,U+79F8,U+7A0D,U+7A46,U+7A76-7A77,U+7A7A,U+7A83,U+7A8D,U+7A96,U+7A98,U+7A9F,U+7AA5,U+7ABF,U+7ACB,U+7ADE-7ADF,U+7AE3,U+7AED,U+7B3C,U+7B4B,U+7B50,U+7B5B,U+7B77,U+7B7E,U+7BA9,U+7BC7,U+7BD3,U+7BEE,U+7BF1,U+7BF7,U+7C73,U+7C7B,U+7C92,U+7C95,U+7CAE,U+7CB1,U+7CB3,U+7CBE,U+7CDC,U+7CE0,U+7CEF,U+7D27,U+7D2F,U+7EA0,U+7EAB,U+7EB1,U+7EB3,U+7EB6,U+7EBD,U+7EC3,U+7EC5,U+7ECD,U+7ECF,U+7ED2-7ED3,U+7ED5,U+7EDC-7EDE,U+7EE2,U+7EF3,U+7EF5,U+7EFF,U+7F05-7F06,U+7F15,U+7F2E,U+7F34,U+7F3A,U+7F57,U+7F8C,U+7F8E,U+7F9A,U+7FA4,U+7FD8,U+8001,U+8003,U+8010,U+802A,U+8042,U+804A-804B,U+8054,U+8058,U+805A,U+8089,U+808B,U+80AF,U+80BE,U+80D6,U+80DA,U+80DC,U+80EF,U+80FD,U+8109,U+8110-8111,U+8113,U+811A,U+8138,U+813E,U+814A,U+8154,U+816E,U+817B,U+819C,U+81A8,U+81B3,U+81FC,U+8205,U+820C-820D,U+826F,U+8272,U+8282,U+828D,U+8292,U+82A5-82A6,U+82B9,U+82D7,U+82DB,U+82E5-82E6,U+82EB,U+82F9,U+8302,U+8304-8305,U+830E,U+832B,U+8338-8339,U+8346,U+8354,U+8363,U+8386,U+8389,U+838E,U+83AB,U+83B1-83B2,U+83BD,U+83CA,U+83CC,U+83E9,U+83F1,U+840C-840D,U+841D,U+8428,U+843D,U+8461,U+8475,U+8499,U+84B2,U+84C9,U+84DD,U+84EC,U+8511,U+8513,U+852B,U+8537,U+854A,U+857E,U+85C9,U+85D0,U+85D5,U+8611,U+864F-8651,U+8671,U+8680,U+8682,U+86C6-86C7,U+86EE,U+871C,U+8721,U+878D,U+879F,U+87BA,U+8815,U+8857,U+886B,U+888D,U+88C2,U+88D9,U+88E4,U+88F3-88F4,U+88F8,U+8925,U+895F,U+89C5-89C6,U+89C8-89C9,U+89D2,U+89E3,U+8A93,U+8B66,U+8B6C,U+8BA4,U+8BA9,U+8BAB,U+8BBA,U+8BBE,U+8BC0,U+8BC4,U+8BC6,U+8BD5,U+8BD7,U+8BEB,U+8BF7,U+8BFA,U+8BFE,U+8C05,U+8C0B,U+8C1C,U+8C26,U+8C28-8C29,U+8C2C,U+8C30-8C31,U+8C34,U+8C8C,U+8D2B,U+8D38,U+8D41-8D42,U+8D4A,U+8D4F,U+8D54,U+8D56,U+8D5B,U+8D61,U+8D66,U+8D77,U+8D8B,U+8DA3,U+8DB4,U+8DD1,U+8DDD,U+8DE8,U+8DEF,U+8E1E,U+8EAB,U+8EAF,U+8F6E-8F6F,U+8F7B,U+8F7F,U+8F83,U+8F86,U+8FA3,U+8FB1,U+8FBD,U+8FC1,U+8FC4,U+8FC8,U+8FD1,U+8FDB,U+8FDE,U+8FEB,U+8FF7,U+9002,U+9006,U+901D,U+903B,U+9063,U+90A3,U+90B1,U+90B5,U+90BB,U+90CE,U+90E1,U+914B,U+914D,U+9152,U+916A,U+9175-9177,U+917F,U+919A-919B,U+91CA,U+91CC,U+91CF,U+91D1,U+948E,U+94A0,U+94A6-94A7,U+94AE,U+94B1,U+94B3,U+94C3,U+94C5-94C6,U+94DD,U+94ED,U+94F0,U+94FA,U+94FE,U+9510,U+951A,U+9523,U+9526,U+952F-9530,U+9539,U+9541,U+954A,U+954D,U+955C,U+9563,U+956D,U+9570,U+95E8,U+95EA,U+95F0,U+95F7,U+95F9,U+95FD,U+9611,U+9614,U+962E,U+9636,U+9646-9647,U+964B-964C,U+9655,U+966A,U+9675,U+9686,U+96B6,U+96BE,U+96C0,U+96F6-96F7,U+9709,U+9713,U+9716,U+9732,U+9739,U+9752,U+9756,U+9759,U+9760-9762,U+9773,U+9798,U+97A0,U+97E7,U+97ED,U+97F6,U+9877,U+9885-9888,U+9891,U+9897,U+98A7,U+98D8,U+98DF,U+9970,U+9976,U+997A,U+9981,U+9988,U+998F,U+9992,U+9996,U+9A6C,U+9A71,U+9A74,U+9A76,U+9A79,U+9A82,U+9A86,U+9A8F,U+9A91,U+9A97,U+9A9A,U+9AA1,U+9B41,U+9B44,U+9B54,U+9C81,U+9CA4,U+9CB8,U+9CC3,U+9CDE,U+9E1F,U+9E23,U+9E25,U+9E43,U+9E4A,U+9E4F,U+9E7F,U+9E93,U+9EA6,U+9EBB,U+9ECE,U+9ED4,U+9ED8,U+9F50,U+9F84,U+9F8B,U+9F99"
|
|
806
|
+
}),
|
|
807
|
+
Object.freeze({
|
|
808
|
+
family: "Aha Hand",
|
|
809
|
+
file: "wenkai-gb-3-6949c050.woff2",
|
|
810
|
+
bytes: 311704,
|
|
811
|
+
unicodeRange: "U+4E00,U+4E07-4E08,U+4E0B,U+4E0E,U+4E13,U+4E1A,U+4E1D,U+4E25,U+4E2B,U+4E2D,U+4E38,U+4E3A-4E3B,U+4E49,U+4E4B-4E4D,U+4E59,U+4E5F-4E61,U+4E66,U+4E88-4E89,U+4E8E,U+4E91,U+4E94,U+4E9A-4E9B,U+4EA1,U+4EA6,U+4EAB,U+4EAD,U+4EBF,U+4ED4,U+4ED6-4ED7,U+4ED9,U+4EE5,U+4EEA,U+4EF0,U+4EF2,U+4F0A,U+4F0D,U+4F11,U+4F17-4F18,U+4F1F,U+4F2A,U+4F3A,U+4F3C,U+4F4D,U+4F4F-4F51,U+4F53,U+4F59,U+4F5C,U+4F63,U+4F6F,U+4F84,U+4F9D,U+4FA0,U+4FA6,U+4FAE,U+4FD7,U+4FDE,U+4FE1,U+4FEE,U+5018,U+501A,U+503A,U+503C,U+505A,U+505C,U+5077,U+50CF,U+50F3,U+5141,U+5143-5144,U+5146,U+5148,U+5154,U+5174,U+5179,U+517B,U+517D,U+518D,U+5199,U+51A4,U+51B6,U+51C6,U+51F6,U+51F8,U+51FF,U+5211,U+5219,U+5236-5237,U+5243,U+524A,U+5254,U+52A1,U+52A9,U+52C7,U+52CB,U+52FF-5300,U+5308,U+531D,U+5323,U+533B,U+5348,U+534F,U+5352-5353,U+5360,U+5367,U+536B,U+5370-5371,U+5378,U+5385,U+538B-538C,U+539F,U+53A2,U+53A6,U+53BF,U+53C8,U+53CB-53CC,U+53D4,U+53D9,U+53EA,U+53EC,U+53F0,U+53F3,U+53F6,U+53F8-53F9,U+5401,U+540C,U+5410-5411,U+5413,U+541E-541F,U+542C,U+542E,U+5431,U+5434,U+5438,U+543B,U+543E,U+5440,U+5458,U+545C,U+5468,U+5473,U+548B,U+548F,U+5492,U+54A8,U+54AC,U+54B1,U+54B8,U+54BD,U+54C7,U+54C9,U+54CD,U+54D1,U+54DF,U+54EE,U+54F2,U+5501,U+5506,U+5510,U+552F,U+553E,U+5544,U+5578,U+557C,U+5582,U+559C,U+55A7,U+55B3,U+55BB,U+55C5,U+55E1,U+55E3,U+55FD,U+5618,U+5631,U+5634,U+5636,U+563B,U+564E,U+566A,U+568F,U+56A3,U+56DB,U+56E0,U+56E2,U+56ED,U+56F4,U+56FE,U+5706,U+571F,U+5728,U+5740,U+574D,U+5750,U+575B,U+575E,U+5760,U+5766,U+578B,U+57A3,U+57DF,U+5802,U+5830,U+584C,U+5851,U+5854,U+5858,U+586B,U+5885,U+589E-589F,U+58EE,U+58F9,U+590F,U+5915-5916,U+591C,U+5929-592A,U+592E,U+5934,U+5937,U+5944,U+594F,U+5957,U+5979,U+5984,U+5986,U+5996,U+59A5,U+59D3-59D4,U+59DA,U+59E8,U+59FB,U+59FF,U+5A01,U+5A03,U+5A31,U+5A49,U+5A74,U+5A7F,U+5AB3,U+5ACC,U+5B50,U+5B55,U+5B57,U+5B59,U+5B5C-5B5D,U+5B66,U+5B70,U+5B83,U+5B85,U+5B87,U+5B8B-5B8C,U+5B97,U+5B99,U+5B9B-5B9C,U+5BA3,U+5BAA,U+5BB0,U+5BB4-5BB5,U+5BBF,U+5BC5,U+5BD3,U+5BE8,U+5BFA-5BFB,U+5C09-5C0A,U+5C0F,U+5C24,U+5C27,U+5C39,U+5C3E,U+5C49,U+5C4B,U+5C51,U+5C55,U+5C5E,U+5C60,U+5C6F,U+5C79,U+5C7F,U+5C81,U+5CA9,U+5CB3,U+5CD9,U+5CE1,U+5CEA,U+5D16,U+5D2D,U+5DCD,U+5DDE,U+5DE1,U+5DE6,U+5DEB,U+5DF2-5DF3,U+5DF7,U+5E05,U+5E0C,U+5E10,U+5E16,U+5E1A,U+5E1C,U+5E27,U+5E2D,U+5E78,U+5E7C-5E7D,U+5E84,U+5E8F,U+5E94,U+5EA7,U+5EAD,U+5EB6,U+5EB8,U+5EF6-5EF7,U+5F02,U+5F15,U+5F20,U+5F26,U+5F2F,U+5F5D,U+5F62,U+5F64,U+5F66,U+5F70-5F71,U+5F79,U+5F80-5F81,U+5F90,U+5F92,U+5FA1,U+5FAA,U+5FAE,U+5FC3,U+5FC6,U+5FD7-5FD8,U+5FE0,U+5FE7,U+5FFB,U+6001-6002,U+600E,U+6014,U+601D,U+6027-6028,U+603B,U+6055,U+6064,U+606C,U+606F,U+607F,U+6089,U+609F-60A0,U+60A6,U+60AC,U+60CB,U+60D5,U+60DC,U+60DF,U+60F3,U+60FA,U+6108-6109,U+610F,U+611A,U+613F,U+6170,U+618E,U+61C8,U+620A,U+620C-620D,U+620F,U+6211,U+6218,U+6240,U+624E,U+6258,U+6267,U+626C,U+627E,U+6291-6293,U+6295,U+6298,U+62AC,U+62BC,U+62C4,U+62D3,U+62D6,U+62D9,U+62DB,U+62E5,U+62E9,U+62EF,U+62F4,U+62FD,U+6307,U+6311,U+6316,U+631A,U+631D-631F,U+6323,U+632F,U+633A,U+633D,U+6342,U+6345,U+6349,U+635F,U+6380,U+638C,U+638F,U+6396,U+63A2,U+63A8-63A9,U+63B7,U+63CD,U+63D0,U+63D6,U+63E1,U+63F4,U+641C,U+642A,U+643A,U+6447,U+644A,U+6454,U+6458,U+6495,U+649E,U+64B0,U+64DE,U+6512,U+652F,U+653F,U+6548,U+6570,U+6574,U+6587,U+658B,U+659C,U+659F,U+65A1,U+65A9,U+65AF-65B0,U+65CB,U+65CF,U+65E0,U+65E8-65E9,U+65EC-65ED,U+65FA,U+6613-6614,U+661F-6620,U+6628,U+662D,U+663C,U+663E,U+6653,U+6655,U+665A,U+6664,U+6670,U+667A,U+6682,U+6687,U+6691,U+66D9,U+66F0,U+66F3,U+66FE-6700,U+6708-6709,U+6714,U+671B,U+672A,U+672D,U+672F,U+6731,U+673D,U+6742,U+674F,U+6756,U+675F,U+6761,U+6768,U+677E,U+6789,U+6790,U+6795,U+679D,U+67A2-67A3,U+67DE,U+67F1,U+6805,U+6808,U+6811,U+6813,U+6821,U+682A,U+6837,U+683D,U+6843,U+6845,U+684C,U+6850,U+6869,U+6876,U+68A7,U+68AD,U+68AF-68B0,U+68B3,U+68D5,U+68E0,U+6905,U+690D-690E,U+692D,U+6930,U+6954,U+6986,U+69A8,U+6A1F,U+6A31,U+6A61,U+6A80,U+6A84,U+6B23,U+6B32,U+6B47,U+6B62-6B63,U+6B66,U+6B6A,U+6B7B,U+6B83,U+6B89-6B8A,U+6B96,U+6BB7,U+6BC5,U+6BCB,U+6BE1,U+6BEF,U+6C27,U+6C34,U+6C38,U+6C40-6C41,U+6C50,U+6C5B,U+6C61,U+6C64,U+6C6A,U+6C70,U+6C79,U+6C82-6C83,U+6CB9,U+6CBB-6CBC,U+6CBE-6CBF,U+6CC4,U+6CE8,U+6CF0,U+6CF3,U+6CFB,U+6CFD,U+6D0B,U+6D17,U+6D32,U+6D3C,U+6D4A,U+6D59,U+6D74,U+6D82,U+6D88,U+6D8C,U+6D8E,U+6D95,U+6D9B,U+6DA1,U+6DA8,U+6DAF,U+6DB2,U+6DC4,U+6DC6,U+6DCC,U+6DD1,U+6DD8,U+6DE4,U+6DEB,U+6DF9,U+6DFB,U+6E0A,U+6E0D,U+6E14,U+6E1D,U+6E23,U+6E29,U+6E2D,U+6E38,U+6E4D,U+6E58,U+6E5B,U+6E7E,U+6E90,U+6EA2,U+6EAA,U+6EAF,U+6ECB,U+6ED3-6ED4,U+6EDE,U+6EE9,U+6F14,U+6F31,U+6F33,U+6F3E,U+6F4D,U+6F6D,U+6FA1,U+7076,U+707C,U+707E,U+708E,U+7099,U+70AD,U+70B8,U+70C1,U+70C3,U+70DB,U+70DF,U+70EB,U+70EF,U+70F7,U+7109,U+7130,U+7167,U+716E,U+7184,U+718A,U+718F,U+7199,U+719F,U+71D5,U+71E5,U+722A,U+7237,U+723D,U+7259,U+7269,U+7279-727A,U+7280,U+72B6,U+72B9,U+72ED,U+72F0-72F1,U+7329-732A,U+732E,U+733F,U+736D,U+7384,U+7389,U+738B,U+73A9,U+73B0,U+73CD,U+73E0,U+7410,U+7422,U+7476,U+74E6,U+74EE,U+7504,U+751C,U+7528-7529,U+7530-7531,U+754F,U+755C,U+758F,U+7591,U+75A1,U+75AB,U+75B9,U+75BC,U+75C7-75C8,U+75D2,U+75D4,U+75DB,U+75F0,U+761F,U+7626,U+762B,U+7634,U+7663,U+7682,U+7696,U+76B1,U+76C2,U+76C5,U+76C8,U+76CA,U+76CF-76D0,U+76F4,U+76F8,U+771F,U+7728-7729,U+773A,U+773C,U+7740-7741,U+7761,U+778E,U+77A9,U+77AC,U+77B3,U+77BB,U+77E3,U+77E5,U+77FD,U+7814,U+7816,U+781A,U+7827,U+7838,U+7852,U+7855,U+785D,U+786C,U+788E,U+7897,U+78B3,U+7956,U+795D,U+795F,U+7965,U+79B9,U+79C0-79C1,U+79C3,U+79CD,U+79DF,U+79E7,U+79E9,U+79FB,U+7A00,U+7A0E,U+7A1A,U+7A33,U+7A57,U+7A74,U+7A81,U+7A84,U+7A91-7A92,U+7A9D,U+7AD6,U+7AD9,U+7AE0,U+7AE5,U+7AF9,U+7B0B,U+7B11,U+7B51-7B52,U+7B97,U+7BB1,U+7BC6,U+7C7D,U+7C98,U+7C9F,U+7CA4-7CA5,U+7CD6,U+7CDF,U+7CFB,U+7D0A,U+7D20,U+7D22,U+7D2B,U+7D6E,U+7E82,U+7EA4,U+7EA6,U+7EAC,U+7EB5,U+7EB8-7EB9,U+7EBF,U+7EC4,U+7EC6-7EC8,U+7ECE,U+7EDA,U+7EDF,U+7EE3,U+7EE5-7EE6,U+7EEA,U+7EED,U+7EF4,U+7EFC-7EFD,U+7F00,U+7F18,U+7F28-7F29,U+7F51,U+7F69-7F6A,U+7F6E,U+7F72,U+7F8A,U+7F9E,U+7FA1,U+7FBD,U+7FC1,U+7FCC,U+7FD4,U+7FFC,U+8000,U+8005,U+800D,U+8018,U+8036,U+8038,U+804C,U+8083-8084,U+8086-8087,U+8096,U+8098,U+80A2,U+80B2,U+80BF-80C1,U+80C3,U+80CE,U+80F0,U+80F8,U+8102,U+810F,U+8131,U+8146,U+814B,U+8155,U+8165,U+8170,U+817A,U+817E-817F,U+819B,U+819D,U+81C0,U+81C3,U+81C6,U+81EA,U+81F3-81F4,U+81FB,U+8200,U+8206,U+8212,U+8214,U+821C,U+821E-821F,U+8237,U+8247,U+8258,U+8273,U+827A,U+828B,U+829C-829D,U+82AF,U+82BD,U+82C7,U+82CF,U+82D1,U+82D4,U+82F1,U+8301,U+8335,U+8367,U+836B,U+836F,U+83B9,U+8404,U+840E,U+8424-8425,U+8427,U+8457,U+846C,U+849C,U+84B8,U+84C4,U+84D1,U+8517,U+851A,U+852C,U+8574,U+859B,U+85AA,U+85AF,U+85E4,U+85FB,U+8638,U+865A,U+865E,U+867D-867E,U+8681,U+868A,U+869C,U+86A4,U+86C0,U+86D9,U+86DB,U+86F0,U+86F9,U+8700,U+8712,U+8715,U+8717-8718,U+8747,U+874E,U+87F9,U+8840,U+8845,U+884C-884D,U+8854,U+8859,U+8863,U+8870,U+8877,U+8881,U+8892,U+8896,U+889C,U+88AD,U+88C5,U+88D4-88D5,U+892A,U+8944,U+897F,U+8981,U+8A00,U+8A79,U+8A89-8A8A,U+8BA8,U+8BAD-8BAF,U+8BB6,U+8BB8,U+8BBC,U+8BC1,U+8BC5,U+8BC8-8BCA,U+8BCC,U+8BD1,U+8BDB,U+8BE2-8BE3,U+8BE6,U+8BEC-8BED,U+8BEF,U+8BF1,U+8BF4-8BF5,U+8BF8,U+8C01,U+8C06,U+8C08,U+8C0A,U+8C10,U+8C13,U+8C1A,U+8C22-8C23,U+8C2D,U+8C4C,U+8C61,U+8C6B,U+8D1E,U+8D23-8D24,U+8D26,U+8D28,U+8D2A,U+8D2E,U+8D34,U+8D3C,U+8D43-8D44,U+8D4E,U+8D58,U+8D5A,U+8D5E,U+8D60,U+8D62,U+8D70,U+8D75,U+8D8A,U+8D9F,U+8DB3,U+8DBE,U+8DC3,U+8DF3,U+8E0A,U+8E0F,U+8E22,U+8E2A,U+8E44,U+8E4B,U+8E81,U+8EBA,U+8F67,U+8F69,U+8F6C,U+8F74,U+8F7D,U+8F93,U+8F95-8F97,U+8F99,U+8F9B,U+8FC2,U+8FC5,U+8FCE,U+8FD0,U+8FD9,U+8FDC-8FDD,U+8FE2,U+8FF0,U+8FFD,U+9000-9001,U+9003,U+9009-900A,U+900F-9010,U+9014,U+901A,U+901F-9020,U+9038,U+903E,U+9042,U+9047,U+9057,U+9065,U+906D-906E,U+9075,U+9080,U+9091,U+90A2,U+90AA,U+90AE,U+90B9,U+90C1,U+90D1,U+90E7,U+9149,U+914C,U+9157,U+915D-915E,U+9165,U+916E,U+9178,U+9189,U+9192,U+91C9,U+91CD-91CE,U+9488,U+949F,U+94A5,U+94A8,U+94BB,U+94C0-94C1,U+94DC,U+94E1,U+94E3,U+94F1,U+94F6,U+94F8,U+9500-9501,U+9508,U+950C,U+9511,U+9517,U+9521,U+9525,U+9528,U+9547,U+9576,U+95EE,U+95F2,U+95F8,U+95FB,U+9605,U+9609,U+960E,U+9633-9635,U+963B,U+9640,U+9650,U+9662,U+9668-9669,U+9676-9677,U+9685,U+968B,U+968F-9690,U+9699,U+969C,U+96A7,U+96C1,U+96C4-96C5,U+96CD,U+96E8,U+96EA,U+96FE,U+9700,U+9704,U+9707,U+971C,U+971E,U+9774,U+978B,U+97E6,U+97F3,U+97F5,U+9875,U+9879-987B,U+987D,U+9882,U+9884,U+9890,U+9893,U+9896,U+9898,U+989C,U+996E,U+9972,U+9985,U+9999,U+9A6D-9A6F,U+9A7B-9A7C,U+9A8C,U+9AA4,U+9AD3,U+9B03,U+9B4F,U+9C7C,U+9C9C,U+9E26,U+9E2D,U+9E2F,U+9E33,U+9E35,U+9E70,U+9ECD,U+9F20"
|
|
812
|
+
}),
|
|
813
|
+
Object.freeze({
|
|
814
|
+
family: "Aha Hand",
|
|
815
|
+
file: "wenkai-gb-4-375dc3b3.woff2",
|
|
816
|
+
bytes: 257596,
|
|
817
|
+
unicodeRange: "U+4E0C,U+4E10,U+4E15,U+4E1E,U+4E28,U+4E36,U+4E3F,U+4E47,U+4E5C,U+4E69,U+4E8D,U+4E93,U+4E98,U+4E9F-4EA0,U+4EB3,U+4EB5,U+4EBB,U+4EC2-4EC4,U+4EC9,U+4EDD-4EDE,U+4EE1,U+4EE8,U+4EEB,U+4EF3,U+4EF5,U+4F09,U+4F1B,U+4F22,U+4F25,U+4F27,U+4F2B,U+4F32,U+4F3D,U+4F57-4F58,U+4F5A,U+4F5D-4F5F,U+4F64-4F65,U+4F67,U+4F74,U+4F76,U+4F7B-4F7C,U+4F7E,U+4F83,U+4F89,U+4F8F,U+4F91,U+4F94,U+4FAA,U+4FAC,U+4FC5,U+4FCE,U+4FD1,U+4FDA,U+4FDC,U+4FDF,U+4FE3,U+4FE6,U+4FE8,U+4FEA,U+4FF3,U+4FF8,U+4FFE,U+500C,U+500F,U+501C,U+5025,U+5028-5029,U+502C-502E,U+5043,U+5048,U+504C,U+504E,U+5055,U+506C,U+507B,U+507E,U+50A5,U+50A7,U+50A9,U+50BA,U+50D6,U+50E6,U+50EC-50EE,U+5106-5107,U+510B,U+5140,U+5155-5156,U+516E,U+5181-5182,U+5196,U+51A2,U+51A5,U+51AB,U+51B1,U+51BC-51BD,U+51C7,U+51EB,U+51F5,U+51FC,U+5202,U+5208,U+520D-520E,U+522D,U+5233,U+523F-5240,U+524C,U+525C,U+525E,U+5261,U+527D,U+5281-5282,U+5290,U+5293,U+52A2,U+52AC-52AD,U+52BE,U+52D0,U+52D6,U+52F0,U+52F9,U+530D,U+530F-5310,U+5315,U+531A,U+5326,U+532E,U+533E,U+5345,U+535F,U+5363,U+5366,U+5369,U+536E,U+537A,U+538D,U+539D,U+53A3,U+53A5,U+53AE,U+53B6,U+53DF,U+53E8-53E9,U+53F1,U+53F5,U+53FB,U+53FD,U+5406,U+5412,U+5416,U+5421,U+5423,U+5432,U+5443,U+544B,U+5452-5454,U+5456-5457,U+5459,U+5464,U+5466,U+5471-5472,U+5476-5477,U+5482,U+5484,U+5494,U+549A-549B,U+549D,U+54A3-54A4,U+54A6-54A7,U+54A9-54AA,U+54AD,U+54B4,U+54BB,U+54BF,U+54C2,U+54CC,U+54CF-54D0,U+54D2-54D5,U+54D9-54DA,U+54DC-54DE,U+54E7,U+54F3,U+54FD,U+54FF,U+550F,U+5511,U+5514,U+551B,U+5520,U+5522-5523,U+5527,U+552A,U+5530,U+5533,U+5537,U+553C,U+553F,U+5541,U+5549,U+5550,U+5555-5556,U+555C,U+5567,U+556C-556D,U+5575-5577,U+557B,U+557E,U+5581,U+5583,U+5588,U+558B,U+558F,U+5591,U+5594,U+5599,U+559F,U+55B1,U+55B5,U+55B9,U+55BD-55BE,U+55C4,U+55C9,U+55CC-55CD,U+55D1-55D2,U+55D4,U+55D6,U+55DD,U+55DF,U+55E4-55E6,U+55E8,U+55EA-55EC,U+55EF,U+55F2-55F3,U+55F5,U+55F7,U+55FE,U+5600-5601,U+5608,U+560C,U+560F,U+561E-561F,U+5623-5624,U+5627,U+562C-562D,U+5639,U+564C-564D,U+5654,U+5657-5659,U+565C,U+5662,U+5664,U+5669,U+566B,U+5671,U+567B-567C,U+5685-5686,U+5693,U+56AF,U+56D4,U+56D7,U+56DD,U+56DF,U+56E1,U+56EB,U+56F5,U+56F9,U+56FF,U+5704,U+5709-570A,U+571C,U+5729-572A,U+572C,U+572E-572F,U+5733,U+5739,U+573B,U+5742,U+574C,U+575C,U+5768-5769,U+576B,U+576D,U+5773,U+5776,U+577B-577C,U+5785-5786,U+578C,U+5793,U+57A0-57A1,U+57A4,U+57A7,U+57A9,U+57AD,U+57B2,U+57B4,U+57B8,U+57CF,U+57D2,U+57D5,U+57D8-57DA,U+57DD,U+57E4,U+57ED,U+57EF,U+57F4,U+57F8,U+57FD,U+5800,U+5807,U+580B,U+580D,U+5819,U+581E,U+5820,U+5844,U+5865,U+586C,U+587E,U+5880-5881,U+5889,U+589A,U+58BC,U+58C5,U+58D1,U+5902,U+5914,U+5919,U+5924-5925,U+592D,U+593C,U+5941-5942,U+5955,U+5958,U+595A,U+5B34,U+5B5B,U+5B6C,U+5C22,U+5C25,U+5C2C,U+5C34,U+5C7A,U+5C88,U+5C8C-5C8D,U+5C90-5C91,U+5C96,U+5C98-5C9A,U+5C9C,U+5CA2-5CA3,U+5CAB-5CAC,U+5CB1,U+5CB5,U+5CB7,U+5CBD,U+5CC1,U+5CC4,U+5CCB,U+5CD2,U+5CE4-5CE5,U+5D02-5D03,U+5D06,U+5D1B,U+5D1E,U+5D24,U+5D26-5D27,U+5D2E,U+5D34,U+5D3D-5D3E,U+5D4A-5D4B,U+5D58,U+5D5B,U+5D5D,U+5D69,U+5D6B-5D6C,U+5D6F,U+5D74,U+5D82,U+5D99,U+5D9D,U+5DB7,U+5DC5,U+5DEF,U+5DFD,U+5E0F,U+5E11,U+5E14,U+5E19,U+5E31,U+5E37,U+5E3B-5E3C,U+5E44,U+5E54,U+5E5B,U+5E5E,U+5E61,U+5E80,U+5E8B,U+5E91,U+5E96,U+5EA0,U+5EA5,U+5EB3,U+5EB5,U+5EB9,U+5EBE,U+5ED1-5ED2,U+5EDB,U+5EE8,U+5EEA,U+5EF4,U+5EFE-5EFF,U+5F01,U+5F08,U+5F0B,U+5F11,U+5F61,U+5F73,U+5F77,U+5F82,U+5F87,U+5F89,U+5F8C,U+5F95,U+5F99,U+5F9C,U+5FA8,U+5FAD,U+5FB5,U+5FBC,U+5FD2,U+61FF,U+624C,U+626A,U+629F,U+62BB,U+62CA,U+62D7,U+62DA,U+62EE,U+62F6,U+6322,U+6339,U+6343,U+634B,U+6369,U+636D,U+6371,U+637A,U+638A,U+638E,U+63AC-63AE,U+63B4,U+63BC,U+63BE,U+63C4,U+63C6,U+63CE,U+63DE,U+63E0,U+63F2,U+63F6,U+63F8,U+63FF,U+640B-640C,U+641B,U+6420-6421,U+6426,U+6441,U+6445,U+6452,U+645E,U+646D,U+647A,U+6484,U+6496,U+6499,U+64B7-64B8,U+64BA,U+64C0,U+64D0,U+64D7,U+64E2,U+64E4,U+6509,U+6525,U+652E,U+6538,U+6BD3,U+6C10,U+6C3D,U+6C46,U+71EE,U+723B,U+72AD,U+72B0,U+72B4,U+72B7-72B8,U+72C1,U+72C3,U+72CD-72CE,U+72D2,U+72E8-72E9,U+72EF,U+72F2-72F4,U+72F7,U+72FA-72FB,U+7301,U+7303,U+730A,U+7313,U+7315,U+7317,U+731D-731E,U+7321-7322,U+7325,U+732C,U+7331,U+7338-7339,U+734D,U+7350,U+7357,U+7360,U+736C,U+736F,U+737E,U+750D,U+7519,U+755A,U+777E,U+77A2,U+77CD,U+7980,U+79BA,U+7C74,U+7F54,U+7FB8,U+8037,U+80E4,U+8114,U+81BA,U+821B,U+8279,U+827D,U+827F,U+8284,U+8288,U+828A,U+828E-828F,U+8291,U+8297-8299,U+829F,U+82A1,U+82A4,U+82A8-82AB,U+82AE,U+82B0,U+82B4,U+82B7-82B8,U+82BE,U+82C1,U+82C4,U+82C8,U+82CA-82CC,U+82CE,U+82D2-82D3,U+82D5,U+82D8,U+82DC,U+82E0-82E1,U+82E3-82E4,U+82F4,U+82F7,U+82FB,U+8306-8309,U+830C,U+830F,U+8311,U+8314-8315,U+8317,U+831A-831C,U+832D,U+832F,U+8331,U+8333-8334,U+833A,U+833C,U+8340,U+8343,U+8347,U+834F,U+8351,U+835B-835C,U+835E-8360,U+8365-8366,U+8368-836A,U+836C-836E,U+8378,U+837B-837D,U+8385,U+8392-8393,U+8398,U+839B-839C,U+839E,U+83A0,U+83A8-83AA,U+83B0,U+83B3-83B4,U+83B6,U+83B8,U+83BA,U+83BC,U+83C0-83C1,U+83C5,U+83D4,U+83D6,U+83D8,U+83DD,U+83DF,U+83E1,U+83E5,U+83EA,U+83F0,U+83F8-83F9,U+83FD,U+8401,U+8403,U+8406,U+840B,U+840F,U+8411,U+8418,U+841C,U+8426,U+8431,U+8438,U+843C,U+8446,U+8451,U+8459-845A,U+845C,U+8469,U+846D,U+8473,U+8476,U+8478,U+847A,U+8487-8489,U+848C,U+848E,U+8497,U+84A1,U+84AF,U+84B4,U+84B9-84BA,U+84BD,U+84BF,U+84C1,U+84CA,U+84CD,U+84D0,U+84D3,U+84E0,U+84E3,U+84E5-84E6,U+84F0,U+84FC,U+84FF,U+850C,U+851F,U+8538-853B,U+8543,U+8548,U+8556,U+8559,U+855E,U+8564,U+8568,U+8572,U+8579-857B,U+8585,U+8587,U+858F,U+859C,U+85A4,U+85A8,U+85AE,U+85B0,U+85B7,U+85B9,U+85C1,U+85D3,U+85DC,U+85FF,U+8605,U+8616,U+8627,U+8629,U+863C,U+8803,U+8862,U+886E,U+88A4,U+88D2,U+8A07,U+8BA0,U+8BA6-8BA7,U+8BAA,U+8BB4-8BB5,U+8BB7,U+8BC2-8BC3,U+8BCB,U+8BCE-8BCF,U+8BD2-8BD4,U+8BD6,U+8BD8-8BD9,U+8BDC,U+8BDF-8BE0,U+8BE4,U+8BE8-8BE9,U+8BEE,U+8BF0,U+8BF3,U+8BF6,U+8BF9,U+8BFC,U+8BFF-8C00,U+8C02,U+8C04,U+8C07,U+8C0C,U+8C0F,U+8C11-8C12,U+8C14-8C16,U+8C18-8C19,U+8C1B,U+8C1D,U+8C1F-8C21,U+8C25,U+8C27,U+8C2A-8C2B,U+8C2E-8C2F,U+8C32-8C33,U+8C35-8C36,U+8C73,U+8D53,U+8D5C-8D5D,U+8F94,U+9097,U+9099,U+909B,U+909D,U+90A1,U+90AC,U+90B0,U+90B3-90B4,U+90B6,U+90B8,U+90BA,U+90BE,U+90C4-90C5,U+90C7,U+90CF-90D0,U+90D3,U+90D7,U+90DB-90DC,U+90E2,U+90E6,U+90EB,U+90EF,U+90FE,U+9104,U+911E,U+9122-9123,U+912F,U+9131,U+9139,U+9143,U+9146,U+961D,U+9621-9622,U+962A,U+9631,U+963C-963D,U+9642,U+9649,U+9654,U+965F,U+9667,U+966C,U+9672,U+9674,U+9688,U+968D,U+9697,U+96B0,U+9765,U+98E7,U+9963,U+9967-996C,U+9974,U+9977,U+997D,U+9980,U+9984,U+9987,U+998A,U+998D,U+9990-9991,U+9993-9995,U+9997-9998,U+99A8,U+9B2F,U+9B32,U+9EC9,U+9F10,U+9F17,U+9F19,U+9FA0"
|
|
818
|
+
}),
|
|
819
|
+
Object.freeze({
|
|
820
|
+
family: "Aha Hand",
|
|
821
|
+
file: "wenkai-gb-5-d0359bbc.woff2",
|
|
822
|
+
bytes: 278908,
|
|
823
|
+
unicodeRange: "U+4E2C,U+5216,U+54AB,U+584D,U+5981,U+5983,U+598D,U+5997,U+599E,U+59A3-59A4,U+59A9-59AB,U+59AF,U+59B2,U+59BE,U+59CA,U+59D2,U+59D7-59D8,U+59DD,U+59E3,U+59F9,U+5A05-5A06,U+5A08-5A09,U+5A0C,U+5A11,U+5A13,U+5A23,U+5A32,U+5A34,U+5A3C,U+5A40,U+5A4A,U+5A55,U+5A62,U+5A67,U+5A75,U+5A77,U+5A7A,U+5A9B,U+5AAA,U+5AB2,U+5AB5,U+5AB8,U+5ABE,U+5AD2,U+5AD4,U+5AD6,U+5AD8,U+5ADC,U+5AE0,U+5AE3,U+5AE6,U+5AEB,U+5AF1,U+5B09,U+5B16-5B17,U+5B32,U+5B37,U+5B40,U+5B51,U+5B53,U+5B5A,U+5B62,U+5B65,U+5B71,U+5B73,U+5B80,U+5B84,U+5B93,U+5B95,U+5BA5,U+5BB8,U+5BE4,U+5BEE,U+5BF0,U+5C15,U+5C1C,U+5C3B,U+5C50,U+5C59,U+5C63,U+5C66,U+5C6E,U+5DDB,U+5E7A,U+5F29-5F2A,U+5F2D,U+5F3C,U+5F40,U+5F50,U+5F56-5F58,U+5FC4,U+5FC9,U+5FCF-5FD1,U+5FD6,U+5FDD,U+5FE1,U+5FE4,U+5FEA,U+5FED-5FEE,U+5FF8,U+5FFE,U+6003-6006,U+600A,U+600D,U+600F,U+6019,U+601B,U+6021,U+6026,U+6029,U+602B,U+6035,U+603C,U+603F,U+6041-6042,U+6059-605A,U+605D,U+6063,U+6067,U+606A,U+6078-607B,U+607D,U+6083,U+608C,U+6092,U+6096,U+609A-609B,U+609D,U+60AB,U+60AD,U+60B1,U+60B4,U+60BB,U+60C6,U+60D8,U+60DA,U+60DD,U+60EC,U+60F4,U+6100,U+6106,U+610D-610E,U+6115,U+6120,U+6123,U+6126,U+612B,U+614A,U+615D,U+6175,U+6194,U+619D,U+61A7,U+61A9,U+61AC,U+61B7,U+61CB,U+61D1,U+61D4,U+61F5,U+6206,U+620B,U+6215,U+6217,U+621B,U+621F,U+6221-6222,U+6224-6225,U+622C,U+623D-623E,U+6243,U+6248-6249,U+6308,U+6332,U+63B0,U+6434,U+643F,U+64D8,U+6534-6535,U+6555,U+656B,U+6590,U+6593,U+65AB,U+65BC,U+65C3-65C4,U+65C6,U+65CC,U+65CE,U+65D2,U+65D6,U+65EE-65F0,U+6600,U+6603,U+660A,U+6615,U+6619,U+661D,U+6631,U+6634-6636,U+6641,U+664F,U+6654,U+6656-6657,U+665F,U+6661,U+6677,U+6684,U+668C,U+669D,U+66A7,U+66B9,U+66BE,U+66DB-66DC,U+66E6,U+66E9,U+66F7,U+670A,U+6710,U+6715,U+6726,U+6748,U+674C,U+6753,U+675E,U+6769-676A,U+6772-6773,U+6775,U+6777,U+677C,U+6787,U+678B,U+6798,U+679E,U+67A5,U+67A7-67A8,U+67AD,U+67B0,U+67B3,U+67B5,U+67B8,U+67C1,U+67C3,U+67D8-67DA,U+67DD,U+67E2,U+67E9,U+67F0,U+67FD,U+6800,U+6809-680A,U+680C,U+680E,U+681D,U+6829,U+6832-6833,U+683E,U+6840-6841,U+6844,U+6849-684A,U+684E,U+6855,U+6860-6862,U+6864,U+6866-6867,U+686B,U+6874,U+6877,U+6883,U+688F,U+6893,U+68B5,U+68C2,U+68E3,U+68F0,U+68F9,U+68FC,U+6901,U+690B,U+6910,U+691F-6920,U+6924,U+6934,U+6939,U+6942,U+6957,U+695D,U+6960,U+6963,U+6966,U+696B,U+696E,U+6971,U+6978-6979,U+6980,U+6984,U+6987-6989,U+698D,U+6995,U+6998,U+699B,U+69A7,U+69AB,U+69AD,U+69B1,U+69BB,U+69C1,U+69CA,U+69CC,U+69CE,U+69D4,U+69DF-69E0,U+69ED,U+69F2,U+69FF,U+6A17-6A18,U+6A28,U+6A2F,U+6A35,U+6A3D-6A3E,U+6A44,U+6A50,U+6A58,U+6A5B,U+6A65,U+6A79,U+6A7C,U+6A8E,U+6A90-6A91,U+6A97,U+6AA0,U+6AA9,U+6AAB,U+6B24,U+6B37,U+6B39,U+6B43,U+6B46,U+6B59,U+6B81-6B82,U+6B84,U+6B87,U+6B8D,U+6B92-6B93,U+6B9A-6B9B,U+6BA1,U+6BAA,U+6BB3,U+6BC2,U+6BEA,U+6BF3,U+6BF5,U+6BF9,U+6BFD,U+6C05-6C07,U+6C0D,U+6C15,U+6C18-6C1A,U+6C21,U+6C24,U+6C29-6C2A,U+6C32,U+6C35,U+6C4A,U+6C54,U+6C5C,U+6C68-6C69,U+6C74,U+6C76,U+6C85-6C86,U+6C8C,U+6C90,U+6C93-6C94,U+6CA3,U+6CA9,U+6CAD,U+6CB1-6CB2,U+6CD0,U+6CD3-6CD4,U+6CD6-6CD7,U+6CE0,U+6CEB,U+6CEE-6CEF,U+6CF1,U+6CF6-6CF8,U+6CFA,U+6CFE,U+6D04,U+6D07,U+6D0C,U+6D0E,U+6D19-6D1A,U+6D27,U+6D2B,U+6D2E,U+6D33,U+6D35,U+6D39,U+6D43,U+6D48,U+6D4D,U+6D4F,U+6D52,U+6D54,U+6D5C,U+6D5E,U+6D60,U+6D63,U+6D6F,U+6D7C,U+6D91,U+6D93-6D94,U+6D9E,U+6DA0,U+6DAB,U+6DAE,U+6DBF,U+6DC5,U+6DC7,U+6DD9,U+6DDD-6DDE,U+6DE0,U+6DE6,U+6DFC,U+6E0C,U+6E0E,U+6E11,U+6E16,U+6E1A,U+6E25,U+6E2B,U+6E32,U+6E44,U+6E4E,U+6E53-6E54,U+6E5F,U+6E6B,U+6E6E,U+6E86,U+6E8F,U+6E98,U+6E9F,U+6EA5,U+6EA7,U+6EB1-6EB2,U+6EB4,U+6EB7,U+6EBB,U+6EBD,U+6EC2,U+6ECF,U+6ED5,U+6ED7,U+6EDF-6EE0,U+6EE2,U+6EF9,U+6F09,U+6F15,U+6F24,U+6F29-6F2A,U+6F2D,U+6F2F,U+6F36,U+6F46-6F47,U+6F4B,U+6F62,U+6F72,U+6F74,U+6F78,U+6F7A,U+6F7C,U+6F89,U+6F8C-6F8D,U+6FA7,U+6FB6,U+6FB9,U+6FC2,U+6FC9,U+6FD1,U+6FDE,U+6FE0-6FE1,U+6FEE-6FEF,U+701A-701B,U+7023,U+7035,U+7039,U+704F,U+705E,U+706C,U+7080,U+7085,U+7096,U+709C-709D,U+70AB,U+70B1,U+70B7,U+70BB,U+70C0,U+70CA,U+70E8,U+7110,U+7113,U+7116,U+7118,U+712F,U+7131,U+7145,U+714A,U+715C,U+7166,U+7168,U+7172-7173,U+7178,U+717A,U+7198,U+71A0,U+71A8,U+71B3,U+71B5,U+71B9,U+71D4,U+71E0,U+71E7,U+71F9,U+721D,U+7228,U+7230,U+723F,U+724D,U+7252,U+7256,U+725D,U+7266,U+726E-726F,U+727E-727F,U+7284,U+728B,U+728D,U+728F,U+7292,U+729F,U+7337,U+7352,U+738E,U+7391,U+739F,U+73A2,U+73AE,U+73B3,U+73B7,U+73BA,U+73C0,U+73C2,U+73C8-73C9,U+73CF,U+73D1,U+73D9,U+73DE,U+73E5,U+73E7,U+73E9,U+73F2,U+740A,U+740F,U+741A-741B,U+7425-7426,U+7428,U+742A,U+742C,U+742E,U+7430,U+7441,U+7455,U+7457,U+7459,U+745B-745C,U+746D,U+7477,U+747E,U+7480-7481,U+7487,U+748B,U+748E,U+7490,U+749C,U+749E,U+74A7-74A9,U+74BA,U+74D2,U+74EF,U+74F4,U+74FF,U+750F,U+7511,U+7513,U+752F,U+753E,U+757F,U+77F6,U+77F8,U+7800,U+7809,U+7811,U+7817-7818,U+781C-781D,U+782D,U+793B,U+7940,U+7946,U+7949,U+7953,U+7957,U+795A-795C,U+7960,U+7962,U+7967,U+796F,U+797A,U+7985,U+798A,U+799A,U+79A7,U+79B3,U+7E9F,U+7EA1,U+7EA3,U+7EA5,U+7EA8-7EA9,U+7EAD,U+7EB0,U+7EBE,U+7EC0-7EC2,U+7EC9,U+7ECB-7ECC,U+7ED0,U+7ED4,U+7ED7,U+7EDB,U+7EE0-7EE1,U+7EE8,U+7EEB,U+7EEE-7EEF,U+7EF1-7EF2,U+7EF6,U+7EFA-7EFB,U+7EFE,U+7F01-7F03,U+7F07-7F08,U+7F0B-7F0D,U+7F0F,U+7F11-7F12,U+7F17,U+7F19,U+7F1B-7F1C,U+7F1F,U+7F21-7F27,U+7F2A-7F2D,U+7F2F-7F33,U+7F35,U+7FBC,U+8004,U+8006,U+807F-8080,U+8093,U+809C,U+809F,U+80AB,U+80AD,U+80B1,U+80B4,U+80B7,U+80BC-80BD,U+80C2,U+80C4,U+80CD,U+80D7,U+80D9,U+80DB,U+80DD,U+80E7-80ED,U+80F1-80F2,U+80F4,U+80FC,U+810D-810E,U+8112,U+8118,U+811E,U+812C,U+8132,U+8136,U+8148,U+814C,U+8153,U+8159-815A,U+8160,U+8167,U+8169,U+816D,U+8171,U+8174,U+817C-817D,U+8182,U+8188,U+8191,U+81A3,U+81A6,U+81AA,U+81BB,U+81C1,U+81CA,U+81CC,U+81E7,U+8274,U+8662,U+8930,U+89C7,U+89CA-89CC,U+89CE-89D1,U+89F3,U+8B07,U+8C5A,U+8D32-8D33,U+8D36,U+8D3B,U+8D3D,U+8D40,U+8D45-8D49,U+8D4D,U+8D55,U+8D59,U+8E47,U+8ECE,U+8F6B,U+8F6D,U+8F71-8F73,U+8F75-8F7A,U+8F7C,U+8F7E,U+8F81-8F82,U+8F84,U+8F87,U+8F8B,U+8F8D-8F8F,U+8F98,U+8F9A,U+8FB6,U+8FD3,U+8FD5,U+8FE4-8FE6,U+8FE8-8FE9,U+8FEE,U+8FF3,U+9004-9005,U+900B,U+900D,U+9011,U+9016,U+9021,U+9026,U+902D,U+902F,U+9035-9036,U+9044,U+9050-9052,U+9058,U+905B,U+9062,U+9068,U+9074,U+907D,U+9082-9083,U+9088,U+908B,U+9095,U+95E9,U+95EB,U+95F1,U+95F3,U+95F5-95F6,U+95FC,U+95FE,U+9603-9604,U+9606,U+9608,U+960A-960D,U+960F,U+9612,U+9615-9617,U+9619-961A,U+96B3,U+97EA-97EC,U+987C,U+98D1-98D3,U+98D5,U+98D9-98DA,U+9A75,U+9A77-9A78,U+9A7A,U+9A7D,U+9A7F-9A81,U+9A85,U+9A88,U+9A8A,U+9A90,U+9A92-9A93,U+9A96,U+9A98,U+9A9B-9AA0,U+9AA2-9AA3,U+9AA5,U+9AA7,U+9B3B,U+9F51"
|
|
824
|
+
}),
|
|
825
|
+
Object.freeze({
|
|
826
|
+
family: "Aha Hand",
|
|
827
|
+
file: "wenkai-gb-6-a238b41c.woff2",
|
|
828
|
+
bytes: 307604,
|
|
829
|
+
unicodeRange: "U+5D47,U+6549,U+659B,U+66A8,U+74DE,U+74E0,U+752C,U+753A,U+7540,U+7548,U+754B,U+754E,U+755B,U+7572,U+7579,U+7583,U+758B,U+7592,U+7594,U+7596,U+759D,U+75A0,U+75A3,U+75AC,U+75B0-75B1,U+75B3-75B4,U+75B8,U+75C2-75C4,U+75CD,U+75D6,U+75E3-75E4,U+75E6-75E8,U+75EB,U+75F1,U+75FC,U+75FF-7600,U+7603,U+7605,U+760A,U+760C,U+7610,U+7615,U+7617-7619,U+761B,U+7620,U+7622,U+7625,U+762D,U+7630,U+7633,U+7635,U+763C,U+763E-7640,U+7643,U+764D,U+7654,U+7656,U+765C,U+765E,U+766B,U+766F,U+7688,U+768E,U+7693,U+7699,U+76A4,U+76B2,U+76B4,U+76CD,U+76E5,U+76F1,U+76F9,U+7704,U+7707-7708,U+770D,U+7719-771A,U+7722,U+7726,U+772D,U+7735,U+7738,U+7743,U+7747,U+7750-7751,U+775A,U+7762,U+7765,U+7768,U+777D,U+777F-7780,U+778C-778D,U+7791,U+779F-77A0,U+77B0,U+77B5,U+77BD,U+77BF,U+77DC,U+77E7,U+77EC,U+781F,U+7823,U+7825-7826,U+7829,U+782C,U+7839-783C,U+7847,U+784C,U+784E,U+7850,U+7856-7857,U+786A,U+786D,U+7887,U+7893,U+789A-789C,U+78A1,U+78A3,U+78A5,U+78B2,U+78B9,U+78C9,U+78D4,U+78D9,U+78EC,U+78F2,U+78F4,U+7905,U+7913,U+791E,U+7924,U+7934,U+79D5,U+79E3,U+79EB,U+79ED,U+7A02-7A03,U+7A06,U+7A14,U+7A1E,U+7A23,U+7A37,U+7A39,U+7A51,U+7A70,U+7A78-7A79,U+7A80,U+7A86,U+7A88,U+7A95,U+7AA0,U+7AA6,U+7AA8,U+7AAC-7AAD,U+7AB3,U+7AE6,U+7AFA,U+7AFD,U+7B03-7B04,U+7B08,U+7B0A,U+7B0F,U+7B15,U+7B19,U+7B1E,U+7B20,U+7B24-7B25,U+7B2A-7B2B,U+7B2E,U+7B31,U+7B33,U+7B38,U+7B3E,U+7B45,U+7B47,U+7B4C,U+7B58,U+7B5A,U+7B5D,U+7B60,U+7B62,U+7B6E,U+7B71-7B72,U+7B75,U+7B7B,U+7B85,U+7B90,U+7B9C-7B9D,U+7BA2,U+7BA6-7BA8,U+7BAA-7BAC,U+7BB4,U+7BB8,U+7BC1,U+7BCC,U+7BD1,U+7BDA,U+7BDD,U+7BE5-7BE6,U+7BEA,U+7BFC,U+7BFE,U+7C0B-7C0C,U+7C0F,U+7C16,U+7C1F,U+7C26,U+7C2A,U+7C38,U+7C40-7C41,U+7C7C,U+7C91,U+7C9C-7C9E,U+7CA2,U+7CB2,U+7CBC-7CBD,U+7CC1,U+7CC5,U+7CC7-7CC8,U+7CCC-7CCD,U+7CD7,U+7CE8,U+7CF8,U+7D77,U+7DA6,U+7DAE,U+7E3B,U+7E47,U+7E9B,U+7F36,U+7F42,U+7F44-7F45,U+7F58,U+7F5F,U+7F61,U+7F68,U+7F71,U+7F74,U+7F79,U+7F7E,U+7F81,U+7F9D,U+7F9F,U+7FA7,U+7FAF-7FB0,U+7FB2,U+7FBF,U+7FCA,U+7FCE,U+7FD5,U+7FE1,U+7FE5-7FE6,U+7FE9,U+7FEE,U+7FF3,U+800B,U+8012,U+8014,U+8016,U+801C,U+8020,U+8022,U+8025-8029,U+8031,U+8035,U+8043,U+8046,U+804D,U+8052,U+8069,U+8071,U+80E5,U+81EC,U+81FE,U+8201-8202,U+8204,U+8210,U+8221-8223,U+8228,U+822B,U+822D,U+822F,U+8233-8234,U+8238,U+823B,U+823E,U+8244,U+8249,U+824B,U+824F,U+825A,U+825F,U+8268,U+826E,U+864D,U+8654,U+866C,U+866E,U+867A-867C,U+867F,U+868B,U+868D,U+8693,U+869D,U+86A3,U+86A7-86AA,U+86AC,U+86AF-86B1,U+86B4-86B6,U+86BA,U+86C4,U+86C9,U+86CE-86D1,U+86D8,U+86DE-86DF,U+86E9,U+86ED,U+86F1-86F4,U+86F8,U+8703,U+8707-870A,U+870D,U+8713,U+871A,U+871E,U+8722-8723,U+8725,U+8729,U+872E,U+8731,U+8734,U+8737,U+873B,U+873E-873F,U+8748,U+874C,U+8753,U+8759,U+8760,U+8763-8765,U+876E,U+8770,U+877B-877E,U+8782-8783,U+8785,U+8788,U+878B,U+8793,U+8797,U+87A8,U+87AB-87AD,U+87AF,U+87B3,U+87B5,U+87BD,U+87C0,U+87C6,U+87CA-87CB,U+87D1-87D3,U+87DB,U+87E0,U+87E5,U+87EA,U+87EE,U+87FE,U+880A,U+8813,U+8816,U+881B,U+8821,U+8832,U+8839,U+883C,U+8844,U+8864,U+8869,U+8872,U+887D-887F,U+8882,U+8885,U+8888,U+88A2,U+88B7,U+88BC,U+88C6,U+88C9,U+88CE,U+88D8,U+88DF,U+88E2-88E3,U+88E5,U+88E8,U+88F0-88F1,U+88FC,U+88FE,U+890A,U+8913,U+8919-891B,U+8921,U+892B,U+8934,U+8936,U+8941,U+895E,U+8966,U+897B,U+8983,U+89D6,U+89DA,U+89DC,U+89DE,U+89E5,U+89EB,U+89EF,U+8A3E,U+8A48,U+8B26,U+8C47,U+8C49,U+8C55,U+8C78,U+8C82,U+8C85,U+8C8A,U+8C94,U+8C98,U+8D67,U+8D6D,U+8D73,U+8D84,U+8D91,U+8D94,U+8DB1,U+8DB5,U+8DB8,U+8DBA,U+8DBC,U+8DBF,U+8DC4,U+8DC6,U+8DCE-8DCF,U+8DD6-8DD7,U+8DDA-8DDB,U+8DDE,U+8DE3-8DE4,U+8DEB-8DEC,U+8DF7-8DF9,U+8DFB,U+8DFD,U+8E05,U+8E09,U+8E14,U+8E1D,U+8E1F,U+8E23,U+8E2C,U+8E2E-8E2F,U+8E31,U+8E35,U+8E39-8E3A,U+8E3D,U+8E40-8E42,U+8E49-8E4A,U+8E51-8E52,U+8E59,U+8E69,U+8E6F-8E70,U+8E74,U+8E76,U+8E7C,U+8E85,U+8E8F-8E90,U+8E94,U+8E9C,U+8E9E,U+914A,U+914E-9150,U+9161-9162,U+9164,U+9169,U+916F-9170,U+9172,U+9174,U+9179,U+917D-917E,U+9185,U+918C-918D,U+9190-9191,U+91A2-91A3,U+91AA,U+91AD-91AF,U+91B4-91B5,U+91BA,U+928E,U+92AE,U+92C8,U+933E,U+936A,U+938F,U+93CA,U+93D6,U+943E,U+946B,U+9485-9487,U+948A-948D,U+948F-9490,U+9494-9495,U+9497,U+949A-949C,U+94A3-94A4,U+94AA-94AD,U+94AF-94B0,U+94B2,U+94B4,U+94B6-94BA,U+94BC-94BD,U+94BF,U+94C4,U+94C8-94CE,U+94D0-94D2,U+94D5-94D9,U+94DB,U+94DE-94E0,U+94E2,U+94E4-94E5,U+94E7-94EB,U+94EE-94EF,U+94F3-94F5,U+94F7,U+94F9,U+94FC-94FD,U+94FF,U+9502-9503,U+9506-9507,U+9509-950A,U+950D-950F,U+9512-9516,U+9518,U+951B,U+951D-951F,U+9522,U+9529-952C,U+9531-9532,U+9534-9538,U+953A,U+953C,U+953E-953F,U+9542,U+9544-9546,U+9549,U+954C,U+954E-954F,U+9552-9554,U+9556-9559,U+955B,U+955D-955F,U+9561-9562,U+9564-956C,U+956F,U+9571-9573,U+96B9,U+96BC-96BD,U+96C9,U+96CE,U+96D2,U+96E0,U+96E9,U+96EF,U+96F3,U+9701,U+9706,U+9708,U+970E-970F,U+972A,U+972D,U+9730,U+973E,U+9753,U+977C,U+9785,U+9791-9792,U+9794,U+97A3,U+97AB,U+97AF,U+97B2,U+97B4,U+9878,U+9880,U+9883,U+9889,U+988C-988D,U+988F,U+9894,U+989A-989B,U+989E-989F,U+98A1-98A2,U+98A5-98A6,U+98E8,U+990D,U+992E,U+9954-9955,U+99A5,U+9AB0-9AB1,U+9AB6-9AB7,U+9ABA,U+9ABC,U+9AC0-9AC2,U+9AC5,U+9ACB-9ACC,U+9AD1,U+9ADF,U+9AE1,U+9AE6,U+9AEB,U+9AED,U+9AEF,U+9AF9,U+9AFB,U+9B08,U+9B0F,U+9B13,U+9B1F,U+9B23,U+9B43,U+9B45,U+9B47-9B49,U+9B4D,U+9B51,U+9C7F,U+9C82,U+9C85-9C88,U+9C8B,U+9C8E,U+9C90-9C92,U+9C94-9C95,U+9C9A-9C9B,U+9C9E-9CA3,U+9CA5-9CA9,U+9CAB,U+9CAD-9CAE,U+9CB0-9CB7,U+9CBA-9CBD,U+9CC4-9CC7,U+9CCA-9CD0,U+9CD3-9CD5,U+9CD7-9CD9,U+9CDC-9CDD,U+9CDF,U+9CE2,U+9E20,U+9E22,U+9E28-9E2C,U+9E31-9E32,U+9E36-9E3A,U+9E3E,U+9E41-9E42,U+9E44,U+9E46-9E49,U+9E4B-9E4C,U+9E4E,U+9E51,U+9E55,U+9E57-9E58,U+9E5A-9E5C,U+9E5E,U+9E63,U+9E66-9E6D,U+9E71,U+9E73,U+9E7E,U+9E82,U+9E87-9E88,U+9E8B,U+9E92,U+9E9D,U+9E9F,U+9EB4,U+9EB8,U+9EBD-9EBE,U+9ECF,U+9EDB-9EDD,U+9EDF-9EE0,U+9EE2,U+9EE5,U+9EE7,U+9EE9-9EEA,U+9EEF,U+9EF9,U+9EFB-9EFC,U+9EFE,U+9F0B,U+9F0D,U+9F22,U+9F2C,U+9F2F,U+9F37,U+9F39,U+9F3D-9F3E,U+9F44,U+9F80,U+9F83,U+9F85-9F8A,U+9F8C,U+9F9B"
|
|
830
|
+
})
|
|
831
|
+
]);
|
|
832
|
+
//#endregion
|
|
833
|
+
//#region src/host/web-fetch.js
|
|
834
|
+
const LOCAL_ADDRESS_MESSAGE = "Local network addresses are not supported";
|
|
835
|
+
var AddressError = class extends Error {
|
|
836
|
+
constructor(message = LOCAL_ADDRESS_MESSAGE) {
|
|
837
|
+
super(message);
|
|
838
|
+
this.name = "AddressError";
|
|
839
|
+
this.code = "bad-url";
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
const V4_BLOCKED = [
|
|
843
|
+
["0.0.0.0", 8],
|
|
844
|
+
["10.0.0.0", 8],
|
|
845
|
+
["100.64.0.0", 10],
|
|
846
|
+
["127.0.0.0", 8],
|
|
847
|
+
["169.254.0.0", 16],
|
|
848
|
+
["172.16.0.0", 12],
|
|
849
|
+
["192.0.0.0", 24],
|
|
850
|
+
["192.0.2.0", 24],
|
|
851
|
+
["192.88.99.0", 24],
|
|
852
|
+
["192.168.0.0", 16],
|
|
853
|
+
["198.18.0.0", 15],
|
|
854
|
+
["198.51.100.0", 24],
|
|
855
|
+
["203.0.113.0", 24],
|
|
856
|
+
["224.0.0.0", 4],
|
|
857
|
+
["240.0.0.0", 4]
|
|
858
|
+
].map(([base, bits]) => [v4Number(base), bits]);
|
|
859
|
+
const V6_BLOCKED = [
|
|
860
|
+
["fc00::", 7],
|
|
861
|
+
["fe80::", 10],
|
|
862
|
+
["fec0::", 10],
|
|
863
|
+
["ff00::", 8],
|
|
864
|
+
["100::", 64],
|
|
865
|
+
["64:ff9b:1::", 48],
|
|
866
|
+
["2001::", 32],
|
|
867
|
+
["2001:2::", 48],
|
|
868
|
+
["2001:10::", 28],
|
|
869
|
+
["2001:20::", 28],
|
|
870
|
+
["2001:db8::", 32]
|
|
871
|
+
].map(([base, bits]) => [v6Bytes(base), bits]);
|
|
872
|
+
function v4Number(address) {
|
|
873
|
+
const parts = address.split(".").map(Number);
|
|
874
|
+
return (parts[0] << 24 >>> 0) + (parts[1] << 16) + (parts[2] << 8) + parts[3] >>> 0;
|
|
875
|
+
}
|
|
876
|
+
function v4Public(address) {
|
|
877
|
+
const value = v4Number(address);
|
|
878
|
+
return !V4_BLOCKED.some(([base, bits]) => bits === 0 ? true : value >>> 32 - bits === base >>> 32 - bits);
|
|
879
|
+
}
|
|
880
|
+
function v6Bytes(address) {
|
|
881
|
+
let text = String(address).toLowerCase();
|
|
882
|
+
const zone = text.indexOf("%");
|
|
883
|
+
if (zone >= 0) text = text.slice(0, zone);
|
|
884
|
+
const groups = [];
|
|
885
|
+
const dotted = text.match(/(\d+\.\d+\.\d+\.\d+)$/u);
|
|
886
|
+
if (dotted) {
|
|
887
|
+
const value = v4Number(dotted[1]);
|
|
888
|
+
text = `${text.slice(0, -dotted[1].length)}${(value >>> 16).toString(16)}:${(value & 65535).toString(16)}`;
|
|
889
|
+
}
|
|
890
|
+
const [head, tail] = text.includes("::") ? text.split("::") : [text, null];
|
|
891
|
+
const left = head ? head.split(":") : [];
|
|
892
|
+
const right = tail ? tail.split(":") : [];
|
|
893
|
+
const fill = tail === null ? 0 : 8 - left.length - right.length;
|
|
894
|
+
for (const group of [
|
|
895
|
+
...left,
|
|
896
|
+
...Array(Math.max(0, fill)).fill("0"),
|
|
897
|
+
...right
|
|
898
|
+
]) groups.push(Number.parseInt(group || "0", 16));
|
|
899
|
+
const bytes = /* @__PURE__ */ new Uint8Array(16);
|
|
900
|
+
groups.slice(0, 8).forEach((group, index) => {
|
|
901
|
+
bytes[index * 2] = group >> 8 & 255;
|
|
902
|
+
bytes[index * 2 + 1] = group & 255;
|
|
903
|
+
});
|
|
904
|
+
return bytes;
|
|
905
|
+
}
|
|
906
|
+
function prefixMatches(bytes, base, bits) {
|
|
907
|
+
for (let bit = 0; bit < bits; bit += 8) {
|
|
908
|
+
const mask = 255 << 8 - Math.min(8, bits - bit) & 255;
|
|
909
|
+
if ((bytes[bit / 8] & mask) !== (base[bit / 8] & mask)) return false;
|
|
910
|
+
}
|
|
911
|
+
return true;
|
|
912
|
+
}
|
|
913
|
+
const embeddedV4 = (bytes, at) => `${bytes[at]}.${bytes[at + 1]}.${bytes[at + 2]}.${bytes[at + 3]}`;
|
|
914
|
+
function v6Public(address) {
|
|
915
|
+
const bytes = v6Bytes(address);
|
|
916
|
+
const zeros = (count) => bytes.subarray(0, count).every((byte) => byte === 0);
|
|
917
|
+
if (zeros(12) || zeros(10) && bytes[10] === 255 && bytes[11] === 255) return v4Public(embeddedV4(bytes, 12));
|
|
918
|
+
if (prefixMatches(bytes, v6Bytes("64:ff9b::"), 96)) return v4Public(embeddedV4(bytes, 12));
|
|
919
|
+
if (bytes[0] === 32 && bytes[1] === 2) return v4Public(embeddedV4(bytes, 2));
|
|
920
|
+
return !V6_BLOCKED.some(([base, bits]) => prefixMatches(bytes, base, bits));
|
|
921
|
+
}
|
|
922
|
+
function isPublicAddress(address) {
|
|
923
|
+
const value = String(address ?? "").replace(/^\[|\]$/gu, "");
|
|
924
|
+
const family = isIP(value.split("%")[0]);
|
|
925
|
+
if (family === 4) return v4Public(value);
|
|
926
|
+
if (family === 6) return v6Public(value);
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
const LOCAL_NAME = /(^|\.)(localhost|local|internal|home\.arpa)$/u;
|
|
930
|
+
function assertPublicHostname(hostname) {
|
|
931
|
+
const host = String(hostname ?? "").replace(/^\[|\]$/gu, "").replace(/\.+$/u, "").toLowerCase();
|
|
932
|
+
if (!host) throw new AddressError("This is not a valid web address");
|
|
933
|
+
if (isIP(host)) {
|
|
934
|
+
if (!isPublicAddress(host)) throw new AddressError();
|
|
935
|
+
return true;
|
|
936
|
+
}
|
|
937
|
+
if (LOCAL_NAME.test(host) || !host.includes(".")) throw new AddressError();
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
function createGuardedLookup({ resolve = lookup, allowed = isPublicAddress } = {}) {
|
|
941
|
+
return function guardedLookup(hostname, options, callback) {
|
|
942
|
+
const done = typeof options === "function" ? options : callback;
|
|
943
|
+
const wanted = typeof options === "object" && options ? options : {};
|
|
944
|
+
resolve(hostname, { all: true }, (error, addresses) => {
|
|
945
|
+
if (error) return done(error);
|
|
946
|
+
const list = (Array.isArray(addresses) ? addresses : []).map((entry) => typeof entry === "string" ? {
|
|
947
|
+
address: entry,
|
|
948
|
+
family: isIP(entry)
|
|
949
|
+
} : entry).filter((entry) => entry?.address);
|
|
950
|
+
if (!list.length) return done(Object.assign(/* @__PURE__ */ new Error(`No address for ${hostname}`), { code: "ENOTFOUND" }));
|
|
951
|
+
if (list.some((entry) => !allowed(entry.address))) return done(new AddressError());
|
|
952
|
+
const family = wanted.family === 4 || wanted.family === 6 ? wanted.family : 0;
|
|
953
|
+
const usable = family ? list.filter((entry) => entry.family === family) : list;
|
|
954
|
+
const chosen = usable.length ? usable : list;
|
|
955
|
+
if (wanted.all) return done(null, chosen.map((entry) => ({
|
|
956
|
+
address: entry.address,
|
|
957
|
+
family: entry.family
|
|
958
|
+
})));
|
|
959
|
+
return done(null, chosen[0].address, chosen[0].family);
|
|
960
|
+
});
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
const EMPTY_BODY_STATUS = /* @__PURE__ */ new Set([
|
|
964
|
+
101,
|
|
965
|
+
204,
|
|
966
|
+
205,
|
|
967
|
+
304
|
|
968
|
+
]);
|
|
969
|
+
function decoded(response) {
|
|
970
|
+
const encoding = String(response.headers["content-encoding"] ?? "").trim().toLowerCase();
|
|
971
|
+
const decoder = encoding === "gzip" || encoding === "x-gzip" ? zlib.createGunzip() : encoding === "deflate" ? zlib.createInflate() : encoding === "br" ? zlib.createBrotliDecompress() : null;
|
|
972
|
+
if (!decoder) return response;
|
|
973
|
+
return pipeline(response, decoder, () => void 0);
|
|
974
|
+
}
|
|
975
|
+
function toHeaders(raw) {
|
|
976
|
+
const headers = new Headers();
|
|
977
|
+
for (const [name, value] of Object.entries(raw ?? {})) {
|
|
978
|
+
if (name === "content-encoding" || name === "content-length" || value === void 0) continue;
|
|
979
|
+
for (const entry of Array.isArray(value) ? value : [value]) try {
|
|
980
|
+
headers.append(name, String(entry));
|
|
981
|
+
} catch {}
|
|
982
|
+
}
|
|
983
|
+
return headers;
|
|
984
|
+
}
|
|
985
|
+
function createGuardedFetch({ resolve, allowed = isPublicAddress, maxBytes = 64 * 1024 * 1024 } = {}) {
|
|
986
|
+
const lookup = createGuardedLookup({
|
|
987
|
+
resolve,
|
|
988
|
+
allowed
|
|
989
|
+
});
|
|
990
|
+
return function guardedFetch(input, { headers = {}, signal } = {}) {
|
|
991
|
+
return new Promise((fulfil, reject) => {
|
|
992
|
+
let target;
|
|
993
|
+
try {
|
|
994
|
+
target = input instanceof URL ? input : new URL(String(input));
|
|
995
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") throw new AddressError("Only http and https addresses are supported");
|
|
996
|
+
const literal = target.hostname.replace(/^\[|\]$/gu, "");
|
|
997
|
+
if (isIP(literal) && !allowed(literal)) throw new AddressError();
|
|
998
|
+
} catch (error) {
|
|
999
|
+
reject(error);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
const transport = target.protocol === "https:" ? https : http;
|
|
1003
|
+
let settled = false;
|
|
1004
|
+
const fail = (error) => {
|
|
1005
|
+
if (settled) return;
|
|
1006
|
+
settled = true;
|
|
1007
|
+
reject(error);
|
|
1008
|
+
};
|
|
1009
|
+
const request = transport.request(target, {
|
|
1010
|
+
method: "GET",
|
|
1011
|
+
agent: false,
|
|
1012
|
+
lookup,
|
|
1013
|
+
signal,
|
|
1014
|
+
headers: {
|
|
1015
|
+
...headers,
|
|
1016
|
+
"accept-encoding": "gzip, deflate, br"
|
|
1017
|
+
}
|
|
1018
|
+
}, (response) => {
|
|
1019
|
+
const status = response.statusCode ?? 0;
|
|
1020
|
+
if (status < 200 || status > 599) {
|
|
1021
|
+
response.resume();
|
|
1022
|
+
fail(Object.assign(/* @__PURE__ */ new Error(`Unexpected status ${status}`), { code: "EBADSTATUS" }));
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
if (status >= 300 && status < 400 || EMPTY_BODY_STATUS.has(status)) {
|
|
1026
|
+
response.resume();
|
|
1027
|
+
settled = true;
|
|
1028
|
+
fulfil(new Response(null, {
|
|
1029
|
+
status,
|
|
1030
|
+
headers: toHeaders(response.headers)
|
|
1031
|
+
}));
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
const body = decoded(response);
|
|
1035
|
+
const parts = [];
|
|
1036
|
+
let size = 0;
|
|
1037
|
+
body.on("data", (chunk) => {
|
|
1038
|
+
if (settled) return;
|
|
1039
|
+
size += chunk.length;
|
|
1040
|
+
if (size > maxBytes) {
|
|
1041
|
+
request.destroy();
|
|
1042
|
+
body.destroy?.();
|
|
1043
|
+
fail(Object.assign(/* @__PURE__ */ new Error("Response too large"), { code: "ETOOLARGE" }));
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
parts.push(chunk);
|
|
1047
|
+
});
|
|
1048
|
+
body.on("error", fail);
|
|
1049
|
+
body.on("end", () => {
|
|
1050
|
+
if (settled) return;
|
|
1051
|
+
settled = true;
|
|
1052
|
+
fulfil(new Response(Buffer.concat(parts), {
|
|
1053
|
+
status,
|
|
1054
|
+
headers: toHeaders(response.headers)
|
|
1055
|
+
}));
|
|
1056
|
+
});
|
|
1057
|
+
});
|
|
1058
|
+
request.on("error", fail);
|
|
1059
|
+
request.end();
|
|
1060
|
+
});
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
createGuardedFetch();
|
|
1064
|
+
//#endregion
|
|
666
1065
|
//#region src/host/materials.js
|
|
667
1066
|
const MAX_UPLOAD_BYTES = 60 * 1024 * 1024;
|
|
668
1067
|
const MAX_TEXT_CHARS = 2e6;
|
|
669
1068
|
const CHUNK_CHARS = 1600;
|
|
670
1069
|
const FETCH_TIMEOUT_MS = 2e4;
|
|
671
1070
|
const MAX_PAGE_BYTES = 6 * 1024 * 1024;
|
|
1071
|
+
const pageFetch = createGuardedFetch({ maxBytes: MAX_UPLOAD_BYTES });
|
|
672
1072
|
var MaterialError = class extends Error {
|
|
673
1073
|
constructor(code, message) {
|
|
674
1074
|
super(message);
|
|
@@ -984,7 +1384,6 @@ async function ingestFile({ name, bytes, signal }) {
|
|
|
984
1384
|
const result = extractPlain(bytes, kind);
|
|
985
1385
|
return finish(kind, result.title || baseTitle, result.chunks);
|
|
986
1386
|
}
|
|
987
|
-
const PRIVATE_HOST = /^(localhost|.*\.local|127\.\d+\.\d+\.\d+|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2\d|3[01])\.\d+\.\d+|169\.254\.\d+\.\d+|0\.0\.0\.0|\[?::1\]?|\[?f[cd][0-9a-f]{2}:.*)$/iu;
|
|
988
1387
|
function checkPublicUrl(value) {
|
|
989
1388
|
let url;
|
|
990
1389
|
try {
|
|
@@ -994,10 +1393,14 @@ function checkPublicUrl(value) {
|
|
|
994
1393
|
}
|
|
995
1394
|
if (url.protocol !== "https:" && url.protocol !== "http:") throw new MaterialError("bad-url", "Only http and https addresses are supported");
|
|
996
1395
|
if (url.username || url.password) throw new MaterialError("bad-url", "Addresses with credentials are not supported");
|
|
997
|
-
|
|
1396
|
+
try {
|
|
1397
|
+
assertPublicHostname(url.hostname);
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
throw new MaterialError("bad-url", error.message);
|
|
1400
|
+
}
|
|
998
1401
|
return url;
|
|
999
1402
|
}
|
|
1000
|
-
async function ingestUrl(address, { fetchImpl =
|
|
1403
|
+
async function ingestUrl(address, { fetchImpl = pageFetch, signal } = {}) {
|
|
1001
1404
|
let url = checkPublicUrl(address);
|
|
1002
1405
|
let response;
|
|
1003
1406
|
for (let hop = 0; hop < 6; hop += 1) {
|
|
@@ -1013,6 +1416,8 @@ async function ingestUrl(address, { fetchImpl = globalThis.fetch, signal } = {})
|
|
|
1013
1416
|
});
|
|
1014
1417
|
} catch (error) {
|
|
1015
1418
|
if (signal?.aborted) throw signal.reason ?? error;
|
|
1419
|
+
if (error?.name === "AddressError") throw new MaterialError("bad-url", error.message);
|
|
1420
|
+
if (error?.code === "ETOOLARGE") throw new MaterialError("too-large", "The page is too large");
|
|
1016
1421
|
throw new MaterialError("network", timeout.aborted ? "The page took too long to load" : "The page could not be loaded");
|
|
1017
1422
|
}
|
|
1018
1423
|
if (response.status >= 300 && response.status < 400 && response.headers.get("location")) {
|
|
@@ -1057,6 +1462,7 @@ async function ingestUrl(address, { fetchImpl = globalThis.fetch, signal } = {})
|
|
|
1057
1462
|
//#region src/host/http.js
|
|
1058
1463
|
const UPLOAD_PATH = "/api/aha-tutor/upload";
|
|
1059
1464
|
const TTS_PATH = "/api/aha-tutor/tts";
|
|
1465
|
+
const FONT_PATH = "/api/aha-tutor/font";
|
|
1060
1466
|
async function readCapped(stream, max, signal) {
|
|
1061
1467
|
const parts = [];
|
|
1062
1468
|
let size = 0;
|
|
@@ -1140,6 +1546,34 @@ function ttsRoute({ speak }) {
|
|
|
1140
1546
|
}
|
|
1141
1547
|
};
|
|
1142
1548
|
}
|
|
1549
|
+
function fontsDir() {
|
|
1550
|
+
return join(dirname(createRequire(import.meta.url).resolve("dsh-aha-tutor/package.json")), "assets", "fonts");
|
|
1551
|
+
}
|
|
1552
|
+
const FONT_FILES = new Set(BOARD_FONT_FILES.map((entry) => entry.file));
|
|
1553
|
+
function fontRoute({ dir = fontsDir() } = {}) {
|
|
1554
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
1555
|
+
return {
|
|
1556
|
+
path: FONT_PATH,
|
|
1557
|
+
methods: ["GET"],
|
|
1558
|
+
requestBody: "buffered",
|
|
1559
|
+
fetch: async (request) => {
|
|
1560
|
+
const name = new URL(request.url).searchParams.get("f") ?? "";
|
|
1561
|
+
if (!FONT_FILES.has(name)) return new Response("Not found", { status: 404 });
|
|
1562
|
+
try {
|
|
1563
|
+
if (!loaded.has(name)) loaded.set(name, await readFile(join(dir, name)));
|
|
1564
|
+
} catch {
|
|
1565
|
+
return new Response("Not found", { status: 404 });
|
|
1566
|
+
}
|
|
1567
|
+
return new Response(loaded.get(name), {
|
|
1568
|
+
status: 200,
|
|
1569
|
+
headers: {
|
|
1570
|
+
"content-type": "font/woff2",
|
|
1571
|
+
"cache-control": "public, max-age=31536000, immutable"
|
|
1572
|
+
}
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1143
1577
|
//#endregion
|
|
1144
1578
|
//#region src/host/jobs.js
|
|
1145
1579
|
const KEEP_FINISHED_MS = 10 * 6e4;
|
|
@@ -1162,7 +1596,7 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1162
1596
|
sweep();
|
|
1163
1597
|
if (key && byKey.has(key)) {
|
|
1164
1598
|
const existing = jobs.get(byKey.get(key));
|
|
1165
|
-
if (existing && !existing.finishedAt) return snapshot(existing);
|
|
1599
|
+
if (existing && !existing.finishedAt && !existing.controller.signal.aborted) return snapshot(existing);
|
|
1166
1600
|
}
|
|
1167
1601
|
const controller = new AbortController();
|
|
1168
1602
|
const job = {
|
|
@@ -1177,6 +1611,7 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1177
1611
|
label: ""
|
|
1178
1612
|
},
|
|
1179
1613
|
partial: [],
|
|
1614
|
+
preview: null,
|
|
1180
1615
|
result: void 0,
|
|
1181
1616
|
error: void 0,
|
|
1182
1617
|
startedAt: now(),
|
|
@@ -1196,6 +1631,9 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1196
1631
|
},
|
|
1197
1632
|
push(item) {
|
|
1198
1633
|
job.partial.push(item);
|
|
1634
|
+
},
|
|
1635
|
+
preview(value) {
|
|
1636
|
+
job.preview = value ?? null;
|
|
1199
1637
|
}
|
|
1200
1638
|
};
|
|
1201
1639
|
const aborted = new Promise((_, reject) => {
|
|
@@ -1206,7 +1644,10 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1206
1644
|
job.result = result;
|
|
1207
1645
|
}).catch((error) => {
|
|
1208
1646
|
job.status = controller.signal.aborted ? "cancelled" : "failed";
|
|
1209
|
-
job.error = {
|
|
1647
|
+
job.error = controller.signal.aborted ? {
|
|
1648
|
+
code: "cancelled",
|
|
1649
|
+
message: "Cancelled"
|
|
1650
|
+
} : {
|
|
1210
1651
|
code: error?.code ?? "failed",
|
|
1211
1652
|
message: publicMessage(error)
|
|
1212
1653
|
};
|
|
@@ -1225,6 +1666,7 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1225
1666
|
progress: job.progress,
|
|
1226
1667
|
partial: job.partial.slice(since),
|
|
1227
1668
|
partialCount: job.partial.length,
|
|
1669
|
+
preview: job.preview ?? void 0,
|
|
1228
1670
|
result: job.status === "done" ? job.result : void 0,
|
|
1229
1671
|
error: job.error
|
|
1230
1672
|
};
|
|
@@ -1241,7 +1683,11 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1241
1683
|
function running(key) {
|
|
1242
1684
|
const id = byKey.get(key);
|
|
1243
1685
|
const job = id ? jobs.get(id) : void 0;
|
|
1244
|
-
return job && !job.finishedAt ? snapshot(job) : null;
|
|
1686
|
+
return job && !job.finishedAt && !job.controller.signal.aborted ? snapshot(job) : null;
|
|
1687
|
+
}
|
|
1688
|
+
function cancelKey(key) {
|
|
1689
|
+
const job = running(key);
|
|
1690
|
+
return job ? cancel(job.id) : null;
|
|
1245
1691
|
}
|
|
1246
1692
|
function dispose() {
|
|
1247
1693
|
for (const job of jobs.values()) if (!job.finishedAt) job.controller.abort(/* @__PURE__ */ new Error("plugin stopped"));
|
|
@@ -1252,6 +1698,7 @@ function createJobs({ logger, now = Date.now } = {}) {
|
|
|
1252
1698
|
start,
|
|
1253
1699
|
get,
|
|
1254
1700
|
cancel,
|
|
1701
|
+
cancelKey,
|
|
1255
1702
|
running,
|
|
1256
1703
|
dispose
|
|
1257
1704
|
});
|
|
@@ -1315,6 +1762,7 @@ function buildPlan({ today, settings, courses = [], reviews = [], exams = [] })
|
|
|
1315
1762
|
const queues = courses.map((course) => ({
|
|
1316
1763
|
id: course.id,
|
|
1317
1764
|
title: course.title,
|
|
1765
|
+
emoji: course.emoji || "",
|
|
1318
1766
|
deadline: course.deadline || null,
|
|
1319
1767
|
priority: Number(course.priority) || 0,
|
|
1320
1768
|
remaining: (course.lessons || []).filter((lesson) => !lesson.done).map((lesson) => ({
|
|
@@ -1375,6 +1823,7 @@ function buildPlan({ today, settings, courses = [], reviews = [], exams = [] })
|
|
|
1375
1823
|
courseId: queue.id,
|
|
1376
1824
|
title: lesson.title,
|
|
1377
1825
|
courseTitle: queue.title,
|
|
1826
|
+
courseEmoji: queue.emoji,
|
|
1378
1827
|
minutes: lesson.minutes
|
|
1379
1828
|
});
|
|
1380
1829
|
if (queue.remaining.length === 0) queue.finishDay = day;
|
|
@@ -1583,6 +2032,7 @@ function createLearner({ store, llm, now = () => /* @__PURE__ */ new Date(), log
|
|
|
1583
2032
|
courses: active.map(({ course, progress }) => ({
|
|
1584
2033
|
id: course.id,
|
|
1585
2034
|
title: course.title,
|
|
2035
|
+
emoji: course.emoji ?? "",
|
|
1586
2036
|
deadline: course.settings?.deadline ?? null,
|
|
1587
2037
|
lessons: flattenLessons(course).map(({ lesson }) => ({
|
|
1588
2038
|
id: lesson.id,
|
|
@@ -1637,10 +2087,11 @@ function createLearner({ store, llm, now = () => /* @__PURE__ */ new Date(), log
|
|
|
1637
2087
|
}));
|
|
1638
2088
|
return plan();
|
|
1639
2089
|
}
|
|
1640
|
-
async function reviewSession({ limit = 8 } = {}) {
|
|
2090
|
+
async function reviewSession({ limit = 8, courseId } = {}) {
|
|
1641
2091
|
const at = now().getTime();
|
|
1642
2092
|
const items = [];
|
|
1643
2093
|
for (const { course, progress } of await activeCourses()) {
|
|
2094
|
+
if (courseId && course.id !== courseId) continue;
|
|
1644
2095
|
const index = conceptIndex(course);
|
|
1645
2096
|
const due = Object.entries(progress.reviews ?? {}).filter(([id, card]) => index.has(id) && Date.parse(card.dueAt) <= at).sort((a, b) => Date.parse(a[1].dueAt) - Date.parse(b[1].dueAt));
|
|
1646
2097
|
for (const [conceptId] of due) {
|
|
@@ -1649,7 +2100,7 @@ function createLearner({ store, llm, now = () => /* @__PURE__ */ new Date(), log
|
|
|
1649
2100
|
const lesson = findLesson(course, concept.lessonId)?.lesson;
|
|
1650
2101
|
const set = await store.readJson(store.paths.practice(course.id, concept.lessonId), null);
|
|
1651
2102
|
const board = await store.readJson(store.paths.board(course.id, concept.lessonId), null);
|
|
1652
|
-
const candidates = [...set?.items ?? [], ...(board?.steps ?? []).map((step) => step.check).filter(Boolean)].filter((item) => item.conceptIds?.includes(conceptId) && item.kind !== "short");
|
|
2103
|
+
const candidates = [...set?.items ?? [], ...(board?.steps ?? []).map((step) => step.check).filter(Boolean)].filter((item) => item.conceptIds?.includes(conceptId) && item.kind !== "short" && item.kind !== "work");
|
|
1653
2104
|
const item = candidates[Math.floor(Math.random() * candidates.length)];
|
|
1654
2105
|
if (item) items.push({
|
|
1655
2106
|
courseId: course.id,
|
|
@@ -1768,6 +2219,7 @@ function round2(value) {
|
|
|
1768
2219
|
//#endregion
|
|
1769
2220
|
//#region src/host/lessons.js
|
|
1770
2221
|
const EVENTS_KEPT = 200;
|
|
2222
|
+
const STEP_ID = /^s\d{1,4}$/u;
|
|
1771
2223
|
function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__PURE__ */ new Date() }) {
|
|
1772
2224
|
const stamp = () => now().toISOString();
|
|
1773
2225
|
async function context(courseId, lessonId) {
|
|
@@ -1781,10 +2233,11 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1781
2233
|
}
|
|
1782
2234
|
async function get({ courseId, lessonId }) {
|
|
1783
2235
|
const { course, row } = await context(courseId, lessonId);
|
|
1784
|
-
const [board, practice, progress] = await Promise.all([
|
|
2236
|
+
const [board, practice, progress, asides] = await Promise.all([
|
|
1785
2237
|
store.readJson(store.paths.board(courseId, lessonId), null),
|
|
1786
2238
|
store.readJson(store.paths.practice(courseId, lessonId), null),
|
|
1787
|
-
readProgress(store, courseId)
|
|
2239
|
+
readProgress(store, courseId),
|
|
2240
|
+
store.readJson(store.paths.asides(courseId, lessonId), null)
|
|
1788
2241
|
]);
|
|
1789
2242
|
return {
|
|
1790
2243
|
courseId,
|
|
@@ -1800,6 +2253,7 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1800
2253
|
lesson: row.lesson,
|
|
1801
2254
|
board,
|
|
1802
2255
|
practice,
|
|
2256
|
+
asides: Array.isArray(asides?.items) ? asides.items : [],
|
|
1803
2257
|
state: progress.lessons?.[lessonId] ?? {
|
|
1804
2258
|
status: "new",
|
|
1805
2259
|
stepIndex: 0
|
|
@@ -1821,6 +2275,7 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1821
2275
|
const kindDirective = row.lesson.kind === "remedial" ? "remediate" : row.lesson.kind === "review" ? "review" : row.lesson.kind === "challenge" ? "challenge" : void 0;
|
|
1822
2276
|
return generateSteps(llm, {
|
|
1823
2277
|
purpose: "teach",
|
|
2278
|
+
effort: "low",
|
|
1824
2279
|
prompt: lessonPrompt({
|
|
1825
2280
|
course,
|
|
1826
2281
|
unit: row.unit,
|
|
@@ -1845,6 +2300,11 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1845
2300
|
}
|
|
1846
2301
|
async function prepare({ courseId, lessonId, force = false, style }) {
|
|
1847
2302
|
const { course, row } = await context(courseId, lessonId);
|
|
2303
|
+
ensurePractice(course, row);
|
|
2304
|
+
if (force) {
|
|
2305
|
+
jobs.cancelKey(`board:${courseId}:${lessonId}`);
|
|
2306
|
+
await store.writeJson(store.paths.asides(courseId, lessonId), { items: [] });
|
|
2307
|
+
}
|
|
1848
2308
|
if (!force) {
|
|
1849
2309
|
const existing = await store.readJson(store.paths.board(courseId, lessonId), null);
|
|
1850
2310
|
if (existing) {
|
|
@@ -1939,7 +2399,18 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1939
2399
|
}
|
|
1940
2400
|
throw new TutorError("invalid", "Unknown board");
|
|
1941
2401
|
}
|
|
1942
|
-
function
|
|
2402
|
+
async function keepAside(scope, aside) {
|
|
2403
|
+
if (scope?.kind !== "lesson") return null;
|
|
2404
|
+
const saved = {
|
|
2405
|
+
id: newId("asd"),
|
|
2406
|
+
...aside,
|
|
2407
|
+
at: stamp()
|
|
2408
|
+
};
|
|
2409
|
+
await store.updateJson(store.paths.asides(scope.courseId, scope.lessonId), null, (value) => ({ items: [...Array.isArray(value?.items) ? value.items : [], saved].slice(-30) }));
|
|
2410
|
+
return saved;
|
|
2411
|
+
}
|
|
2412
|
+
const anchorFor = (board, stepIndex, anchorStepId) => STEP_ID.test(String(anchorStepId)) ? anchorStepId : board?.steps?.[Math.max(0, Number(stepIndex) || 0)]?.id ?? "s1";
|
|
2413
|
+
function ask({ scope, stepIndex = 0, question, anchorStepId }) {
|
|
1943
2414
|
const request = text(question, 1500);
|
|
1944
2415
|
if (!request) throw new TutorError("invalid", "Type your question");
|
|
1945
2416
|
return jobs.start("lesson/ask", async (api) => {
|
|
@@ -1963,21 +2434,31 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1963
2434
|
conceptIds: lesson?.concepts?.map((concept) => concept.id) ?? [],
|
|
1964
2435
|
onStep: (step) => api.push(step)
|
|
1965
2436
|
});
|
|
2437
|
+
const aside = await keepAside(scope, {
|
|
2438
|
+
kind: "question",
|
|
2439
|
+
question: request,
|
|
2440
|
+
anchorStepId: anchorFor(board, stepIndex, anchorStepId),
|
|
2441
|
+
steps: answer.steps
|
|
2442
|
+
});
|
|
1966
2443
|
if (scope.kind === "lesson") await logEvent(scope.courseId, {
|
|
1967
2444
|
type: "question",
|
|
1968
2445
|
lessonId: scope.lessonId,
|
|
1969
2446
|
text: request.slice(0, 200)
|
|
1970
2447
|
});
|
|
1971
|
-
return {
|
|
2448
|
+
return {
|
|
2449
|
+
steps: answer.steps,
|
|
2450
|
+
aside
|
|
2451
|
+
};
|
|
1972
2452
|
});
|
|
1973
2453
|
}
|
|
1974
|
-
function reexplain({ scope, stepIndex = 0, style = "example" }) {
|
|
2454
|
+
function reexplain({ scope, stepIndex = 0, style = "example", anchorStepId }) {
|
|
1975
2455
|
return jobs.start("lesson/reexplain", async (api) => {
|
|
1976
2456
|
const { course, lesson, board, language } = await scopeBoard(scope);
|
|
1977
2457
|
if (!board?.steps?.length) throw new TutorError("invalid", "Nothing to re-explain yet");
|
|
1978
2458
|
const index = Math.min(board.steps.length - 1, Math.max(0, Number(stepIndex) || 0));
|
|
1979
2459
|
const answer = await generateSteps(llm, {
|
|
1980
2460
|
purpose: "teach",
|
|
2461
|
+
effort: "low",
|
|
1981
2462
|
prompt: reexplainPrompt({
|
|
1982
2463
|
lesson,
|
|
1983
2464
|
language,
|
|
@@ -1993,6 +2474,12 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
1993
2474
|
conceptIds: lesson?.concepts?.map((concept) => concept.id) ?? [],
|
|
1994
2475
|
onStep: (next) => api.push(next)
|
|
1995
2476
|
});
|
|
2477
|
+
const aside = await keepAside(scope, {
|
|
2478
|
+
kind: "reexplain",
|
|
2479
|
+
style,
|
|
2480
|
+
anchorStepId: anchorFor(board, index, anchorStepId),
|
|
2481
|
+
steps: answer.steps
|
|
2482
|
+
});
|
|
1996
2483
|
if (scope.kind === "lesson" && course) {
|
|
1997
2484
|
const conceptIds = lesson.concepts.map((concept) => concept.id);
|
|
1998
2485
|
await record({
|
|
@@ -2002,7 +2489,10 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2002
2489
|
evidence: { kind: "reexplain" }
|
|
2003
2490
|
});
|
|
2004
2491
|
}
|
|
2005
|
-
return {
|
|
2492
|
+
return {
|
|
2493
|
+
steps: answer.steps,
|
|
2494
|
+
aside
|
|
2495
|
+
};
|
|
2006
2496
|
});
|
|
2007
2497
|
}
|
|
2008
2498
|
async function record({ courseId, lessonId, conceptIds = [], evidence = {} }) {
|
|
@@ -2049,18 +2539,25 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2049
2539
|
}
|
|
2050
2540
|
async function grade({ item, response, language = "zh-CN" }) {
|
|
2051
2541
|
if (!item?.prompt) throw new TutorError("invalid", "Missing question");
|
|
2542
|
+
const work = item.kind === "work";
|
|
2052
2543
|
const answer = text(response, 4e3);
|
|
2053
2544
|
if (!answer) return {
|
|
2054
2545
|
score: 0,
|
|
2055
2546
|
verdict: "incorrect",
|
|
2056
2547
|
feedback: "",
|
|
2057
2548
|
errorTag: "",
|
|
2058
|
-
misconception: false
|
|
2549
|
+
misconception: false,
|
|
2550
|
+
...work ? {
|
|
2551
|
+
wrongStep: "",
|
|
2552
|
+
why: "",
|
|
2553
|
+
fix: ""
|
|
2554
|
+
} : {}
|
|
2059
2555
|
};
|
|
2060
2556
|
return await generateJson(llm, {
|
|
2061
2557
|
purpose: "quick",
|
|
2062
2558
|
prompt: gradePrompt({
|
|
2063
2559
|
item: {
|
|
2560
|
+
kind: work ? "work" : "short",
|
|
2064
2561
|
prompt: text(item.prompt, 2e3),
|
|
2065
2562
|
answer: text(item.answer, 3e3),
|
|
2066
2563
|
rubric: Array.isArray(item.rubric) ? item.rubric.map((entry) => text(entry, 300)) : []
|
|
@@ -2068,7 +2565,7 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2068
2565
|
response: answer,
|
|
2069
2566
|
language
|
|
2070
2567
|
}),
|
|
2071
|
-
maxTokens: 1200,
|
|
2568
|
+
maxTokens: work ? 1800 : 1200,
|
|
2072
2569
|
normalize: (raw) => ({
|
|
2073
2570
|
score: Math.min(1, Math.max(0, Number(raw?.score) || 0)),
|
|
2074
2571
|
verdict: [
|
|
@@ -2078,10 +2575,60 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2078
2575
|
].includes(raw?.verdict) ? raw.verdict : Number(raw?.score) >= .8 ? "correct" : Number(raw?.score) >= .4 ? "partial" : "incorrect",
|
|
2079
2576
|
feedback: text(raw?.feedback, 1200),
|
|
2080
2577
|
errorTag: text(raw?.errorTag, 80),
|
|
2081
|
-
misconception: raw?.misconception === true
|
|
2578
|
+
misconception: raw?.misconception === true,
|
|
2579
|
+
...work ? {
|
|
2580
|
+
wrongStep: text(raw?.wrongStep, 400),
|
|
2581
|
+
why: text(raw?.why, 400),
|
|
2582
|
+
fix: text(raw?.fix, 400)
|
|
2583
|
+
} : {}
|
|
2082
2584
|
})
|
|
2083
2585
|
});
|
|
2084
2586
|
}
|
|
2587
|
+
function correct({ scope, stepIndex = 0, anchorStepId, item, response, grade: graded }) {
|
|
2588
|
+
const working = text(response, 4e3);
|
|
2589
|
+
if (!item?.prompt || !working) throw new TutorError("invalid", "Nothing to correct");
|
|
2590
|
+
const notes = graded && typeof graded === "object" ? graded : {};
|
|
2591
|
+
return jobs.start("lesson/correct", async (api) => {
|
|
2592
|
+
const { course, lesson, board, language } = await scopeBoard(scope);
|
|
2593
|
+
const answer = await generateSteps(llm, {
|
|
2594
|
+
purpose: "quick",
|
|
2595
|
+
prompt: correctionPrompt({
|
|
2596
|
+
course,
|
|
2597
|
+
lesson,
|
|
2598
|
+
language,
|
|
2599
|
+
boardSoFar: board ? boardToPlainText(board, {
|
|
2600
|
+
uptoStep: Number(stepIndex) || 0,
|
|
2601
|
+
maxChars: 5e3
|
|
2602
|
+
}) : "",
|
|
2603
|
+
item: {
|
|
2604
|
+
prompt: text(item.prompt, 2e3),
|
|
2605
|
+
answer: text(item.answer, 3e3)
|
|
2606
|
+
},
|
|
2607
|
+
response: working,
|
|
2608
|
+
grade: {
|
|
2609
|
+
feedback: text(notes.feedback, 1200),
|
|
2610
|
+
wrongStep: text(notes.wrongStep, 400),
|
|
2611
|
+
why: text(notes.why, 400),
|
|
2612
|
+
fix: text(notes.fix, 400)
|
|
2613
|
+
}
|
|
2614
|
+
}),
|
|
2615
|
+
maxTokens: 4e3,
|
|
2616
|
+
signal: api.signal,
|
|
2617
|
+
conceptIds: lesson?.concepts?.map((concept) => concept.id) ?? [],
|
|
2618
|
+
onStep: (step) => api.push(step)
|
|
2619
|
+
});
|
|
2620
|
+
const aside = await keepAside(scope, {
|
|
2621
|
+
kind: "correction",
|
|
2622
|
+
errorTag: text(notes.errorTag, 80),
|
|
2623
|
+
anchorStepId: anchorFor(board, stepIndex, anchorStepId),
|
|
2624
|
+
steps: answer.steps
|
|
2625
|
+
});
|
|
2626
|
+
return {
|
|
2627
|
+
steps: answer.steps,
|
|
2628
|
+
aside
|
|
2629
|
+
};
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2085
2632
|
async function savePosition({ courseId, lessonId, stepIndex = 0 }) {
|
|
2086
2633
|
assertId(lessonId, "les");
|
|
2087
2634
|
await store.updateJson(store.paths.progress(assertId(courseId, "crs")), null, (progress) => {
|
|
@@ -2169,37 +2716,34 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2169
2716
|
const { course, row } = await context(courseId, lessonId);
|
|
2170
2717
|
const existing = await store.readJson(store.paths.practice(courseId, lessonId), null);
|
|
2171
2718
|
if (existing) return { practice: existing };
|
|
2172
|
-
return { job:
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
if (!set.items.length) throw new TutorError("bad-output", "No practice items came back. Try again.");
|
|
2189
|
-
const saved = {
|
|
2190
|
-
lessonId,
|
|
2191
|
-
...set,
|
|
2192
|
-
createdAt: stamp()
|
|
2193
|
-
};
|
|
2194
|
-
await store.writeJson(store.paths.practice(courseId, lessonId), saved);
|
|
2195
|
-
return { practice: saved };
|
|
2719
|
+
return { job: lecturePractice(course, row) };
|
|
2720
|
+
}
|
|
2721
|
+
function lecturePractice(course, row) {
|
|
2722
|
+
return jobs.start("lesson/practice", async (api) => {
|
|
2723
|
+
const missing = [];
|
|
2724
|
+
for (const lesson of row.lecture.lessons) if (!await store.exists(store.paths.practice(course.id, lesson.id))) missing.push(lesson);
|
|
2725
|
+
const written = missing.length ? await courses.writeLecturePractice({
|
|
2726
|
+
course,
|
|
2727
|
+
lecture: row.lecture,
|
|
2728
|
+
lessons: missing,
|
|
2729
|
+
signal: api.signal
|
|
2730
|
+
}) : {};
|
|
2731
|
+
const sets = {};
|
|
2732
|
+
for (const lesson of row.lecture.lessons) sets[lesson.id] = written[lesson.id] ?? await store.readJson(store.paths.practice(course.id, lesson.id), null);
|
|
2733
|
+
if (!Object.values(sets).some(Boolean)) throw new TutorError("bad-output", "No practice items came back. Try again.");
|
|
2734
|
+
return { sets };
|
|
2196
2735
|
}, {
|
|
2197
|
-
key: `practice:${
|
|
2736
|
+
key: `practice:${course.id}:${row.lecture.id}`,
|
|
2198
2737
|
meta: {
|
|
2199
|
-
courseId,
|
|
2200
|
-
|
|
2738
|
+
courseId: course.id,
|
|
2739
|
+
lectureId: row.lecture.id
|
|
2201
2740
|
}
|
|
2202
|
-
})
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
function ensurePractice(course, row) {
|
|
2744
|
+
store.exists(store.paths.practice(course.id, row.lesson.id)).then((exists) => {
|
|
2745
|
+
if (!exists && !jobs.running(`practice:${course.id}:${row.lecture.id}`)) lecturePractice(course, row);
|
|
2746
|
+
}).catch(() => void 0);
|
|
2203
2747
|
}
|
|
2204
2748
|
async function unitSheet({ courseId, unitId, force = false }) {
|
|
2205
2749
|
const course = await courses.readCourse(courseId);
|
|
@@ -2357,6 +2901,7 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
|
|
|
2357
2901
|
reexplain,
|
|
2358
2902
|
record,
|
|
2359
2903
|
grade,
|
|
2904
|
+
correct,
|
|
2360
2905
|
savePosition,
|
|
2361
2906
|
complete,
|
|
2362
2907
|
practice,
|
|
@@ -2394,6 +2939,17 @@ const RETRYABLE$1 = /* @__PURE__ */ new Set([
|
|
|
2394
2939
|
"TIMEOUT",
|
|
2395
2940
|
"TRANSPORT"
|
|
2396
2941
|
]);
|
|
2942
|
+
const REASONING_ROOM = Object.freeze({
|
|
2943
|
+
off: 0,
|
|
2944
|
+
none: 0,
|
|
2945
|
+
minimal: 4e3,
|
|
2946
|
+
low: 8e3,
|
|
2947
|
+
medium: 16e3,
|
|
2948
|
+
high: 24e3,
|
|
2949
|
+
xhigh: 48e3,
|
|
2950
|
+
max: 48e3
|
|
2951
|
+
});
|
|
2952
|
+
const STOPPED_AT_LIMIT = /* @__PURE__ */ new Set(["max-tokens", "length"]);
|
|
2397
2953
|
const CALL_TIMEOUT_MS = 6 * 6e4;
|
|
2398
2954
|
const MAX_RETRIES = 2;
|
|
2399
2955
|
const USER_ERRORS = Object.freeze({
|
|
@@ -2407,6 +2963,7 @@ const USER_ERRORS = Object.freeze({
|
|
|
2407
2963
|
CONTEXT_WINDOW_EXCEEDED: ["llm-context", "The material is too long for this model. Pick fewer materials or a model with a larger context."],
|
|
2408
2964
|
NO_ADAPTER: ["llm-unavailable", "The selected model is not available. Pick another model in Aha settings."],
|
|
2409
2965
|
TIMEOUT: ["llm-timeout", "The model took too long to respond. Try again."],
|
|
2966
|
+
EMPTY_RESPONSE: ["llm-empty", "The model returned nothing this time. Try again."],
|
|
2410
2967
|
ABORTED: ["cancelled", "Cancelled"]
|
|
2411
2968
|
});
|
|
2412
2969
|
function toTutorError(code, fallback) {
|
|
@@ -2414,6 +2971,17 @@ function toTutorError(code, fallback) {
|
|
|
2414
2971
|
if (known) return new TutorError(known[0], known[1]);
|
|
2415
2972
|
return new TutorError("llm-failed", `The model call failed${code ? ` (${code})` : ""}${fallback ? `: ${fallback}` : ""}`);
|
|
2416
2973
|
}
|
|
2974
|
+
function pickEffort(efforts, wanted) {
|
|
2975
|
+
if (!efforts?.length || !wanted) return void 0;
|
|
2976
|
+
if (wanted === "lowest") return efforts[0].id;
|
|
2977
|
+
return (efforts.find((effort) => effort.id === wanted) ?? efforts.find((effort) => effort.id !== "off" && effort.id !== "none") ?? efforts[0]).id;
|
|
2978
|
+
}
|
|
2979
|
+
function outputBudget(maxTokens, effort, model) {
|
|
2980
|
+
const cap = Number(model?.defaultMaxTokens) || 0;
|
|
2981
|
+
if (!cap || !model?.reasoning) return maxTokens;
|
|
2982
|
+
const room = REASONING_ROOM[effort ?? model.reasoning.defaultEffort] ?? REASONING_ROOM.high;
|
|
2983
|
+
return Math.max(Math.min(maxTokens, cap), Math.min(maxTokens + room, cap));
|
|
2984
|
+
}
|
|
2417
2985
|
const sleep$1 = (ms, signal) => new Promise((resolve, reject) => {
|
|
2418
2986
|
const timer = setTimeout(resolve, ms);
|
|
2419
2987
|
signal?.addEventListener("abort", () => {
|
|
@@ -2473,7 +3041,7 @@ function createLlmPort({ getLlm, getDefault, getAttachments, prefs, logger }) {
|
|
|
2473
3041
|
}
|
|
2474
3042
|
return blocks;
|
|
2475
3043
|
}
|
|
2476
|
-
async function attempt({ purpose, system, user, images, maxTokens, signal, onText }) {
|
|
3044
|
+
async function attempt({ purpose, effort, system, user, images, maxTokens, signal, onText }) {
|
|
2477
3045
|
const llm = getLlm();
|
|
2478
3046
|
if (!llm) throw new TutorError("llm-unavailable", "DSH has no model service in this profile.");
|
|
2479
3047
|
const target = route(purpose);
|
|
@@ -2484,13 +3052,14 @@ function createLlmPort({ getLlm, getDefault, getAttachments, prefs, logger }) {
|
|
|
2484
3052
|
prepared = await llm.prepareCall({
|
|
2485
3053
|
...target,
|
|
2486
3054
|
maxTokens
|
|
2487
|
-
}, fused,
|
|
2488
|
-
const
|
|
2489
|
-
return
|
|
3055
|
+
}, fused, (controls, model) => {
|
|
3056
|
+
const chosen = pickEffort(model?.reasoning?.efforts, purpose === "quick" ? "lowest" : effort);
|
|
3057
|
+
return {
|
|
2490
3058
|
...controls,
|
|
2491
|
-
reasoningEffort:
|
|
2492
|
-
|
|
2493
|
-
|
|
3059
|
+
...chosen ? { reasoningEffort: chosen } : {},
|
|
3060
|
+
maxTokens: outputBudget(maxTokens, chosen, model)
|
|
3061
|
+
};
|
|
3062
|
+
});
|
|
2494
3063
|
} catch (error) {
|
|
2495
3064
|
if (signal?.aborted) throw signal.reason ?? error;
|
|
2496
3065
|
throw Object.assign(toTutorError(error?.code, error?.message), { retryable: false });
|
|
@@ -2529,18 +3098,24 @@ function createLlmPort({ getLlm, getDefault, getAttachments, prefs, logger }) {
|
|
|
2529
3098
|
}
|
|
2530
3099
|
if (!textValue.trim()) throw Object.assign(toTutorError("EMPTY_RESPONSE"), {
|
|
2531
3100
|
retryable: true,
|
|
2532
|
-
streamed: false
|
|
3101
|
+
streamed: false,
|
|
3102
|
+
grow: STOPPED_AT_LIMIT.has(finish?.kind)
|
|
2533
3103
|
});
|
|
2534
3104
|
return textValue;
|
|
2535
3105
|
}
|
|
2536
3106
|
async function call(options) {
|
|
2537
3107
|
let lastError;
|
|
3108
|
+
let current = options;
|
|
2538
3109
|
for (let tries = 0; tries <= MAX_RETRIES; tries += 1) try {
|
|
2539
|
-
return await attempt(
|
|
3110
|
+
return await attempt(current);
|
|
2540
3111
|
} catch (error) {
|
|
2541
3112
|
lastError = error;
|
|
2542
3113
|
if (options.signal?.aborted || !error?.retryable || error?.streamed || tries === MAX_RETRIES) throw error;
|
|
2543
|
-
|
|
3114
|
+
if (error.grow) current = {
|
|
3115
|
+
...current,
|
|
3116
|
+
maxTokens: current.maxTokens * 2
|
|
3117
|
+
};
|
|
3118
|
+
else await sleep$1(Math.min(2e4, Number(error.retryAfterMs) || 1500 * (tries + 1)), options.signal);
|
|
2544
3119
|
}
|
|
2545
3120
|
throw lastError;
|
|
2546
3121
|
}
|
|
@@ -2642,12 +3217,14 @@ function createStore({ root }) {
|
|
|
2642
3217
|
course: (id) => join(paths.courseDir(id), "course.json"),
|
|
2643
3218
|
progress: (id) => join(paths.courseDir(id), "progress.json"),
|
|
2644
3219
|
intake: (id) => join(paths.courseDir(id), "intake.json"),
|
|
3220
|
+
proposal: (id) => join(paths.courseDir(id), "proposal.json"),
|
|
2645
3221
|
cards: (id) => join(paths.courseDir(id), "cards.json"),
|
|
2646
3222
|
boardsDir: (id) => join(paths.courseDir(id), "boards"),
|
|
2647
3223
|
practiceDir: (id) => join(paths.courseDir(id), "practice"),
|
|
2648
3224
|
sheetsDir: (id) => join(paths.courseDir(id), "sheets"),
|
|
2649
3225
|
board: (id, lessonId) => join(paths.courseDir(id), "boards", `${assertId(lessonId, "les")}.json`),
|
|
2650
3226
|
practice: (id, lessonId) => join(paths.courseDir(id), "practice", `${assertId(lessonId, "les")}.json`),
|
|
3227
|
+
asides: (id, lessonId) => join(paths.courseDir(id), "asides", `${assertId(lessonId, "les")}.json`),
|
|
2651
3228
|
sheet: (id, unitId) => join(paths.courseDir(id), "sheets", `${assertId(unitId, "unt")}.json`),
|
|
2652
3229
|
unitQuiz: (id, unitId) => join(paths.courseDir(id), "quizzes", `${assertId(unitId, "unt")}.json`),
|
|
2653
3230
|
materials: () => join(root, "materials"),
|
|
@@ -3344,10 +3921,20 @@ function createRoutes({ courses, lessons, learner, studio, projects, jobs, setti
|
|
|
3344
3921
|
quick: payload.quick === true,
|
|
3345
3922
|
language: typeof payload.language === "string" ? payload.language.slice(0, 12) : void 0
|
|
3346
3923
|
}) }),
|
|
3924
|
+
"course/proposal-apply": (payload) => courses.applyProposal({ courseId: need(payload, "courseId", "crs") }),
|
|
3925
|
+
"course/proposal-discard": (payload) => courses.discardProposal({ courseId: need(payload, "courseId", "crs") }),
|
|
3926
|
+
"course/rework-lesson": (payload) => ({ job: courses.reworkLesson({
|
|
3927
|
+
courseId: need(payload, "courseId", "crs"),
|
|
3928
|
+
lesson: payload.lesson,
|
|
3929
|
+
unitTitle: payload.unitTitle,
|
|
3930
|
+
lectureTitle: payload.lectureTitle,
|
|
3931
|
+
mode: payload.mode === "split" ? "split" : "deepen"
|
|
3932
|
+
}) }),
|
|
3347
3933
|
"course/intake": (payload) => ({ job: courses.submitIntake({
|
|
3348
3934
|
courseId: need(payload, "courseId", "crs"),
|
|
3349
3935
|
answers: payload.answers,
|
|
3350
3936
|
timeline: payload.timeline,
|
|
3937
|
+
size: payload.size,
|
|
3351
3938
|
weeklyMinutes: payload.weeklyMinutes,
|
|
3352
3939
|
deadline: payload.deadline
|
|
3353
3940
|
}) }),
|
|
@@ -3401,12 +3988,14 @@ function createRoutes({ courses, lessons, learner, studio, projects, jobs, setti
|
|
|
3401
3988
|
"lesson/ask": (payload) => ({ job: lessons.ask({
|
|
3402
3989
|
scope: scopeOf(payload),
|
|
3403
3990
|
stepIndex: payload.stepIndex,
|
|
3404
|
-
question: payload.question
|
|
3991
|
+
question: payload.question,
|
|
3992
|
+
anchorStepId: payload.anchorStepId
|
|
3405
3993
|
}) }),
|
|
3406
3994
|
"lesson/reexplain": (payload) => ({ job: lessons.reexplain({
|
|
3407
3995
|
scope: scopeOf(payload),
|
|
3408
3996
|
stepIndex: payload.stepIndex,
|
|
3409
|
-
style: STYLES.includes(payload.style) ? payload.style : "example"
|
|
3997
|
+
style: STYLES.includes(payload.style) ? payload.style : "example",
|
|
3998
|
+
anchorStepId: payload.anchorStepId
|
|
3410
3999
|
}) }),
|
|
3411
4000
|
"lesson/record": (payload) => lessons.record({
|
|
3412
4001
|
courseId: need(payload, "courseId", "crs"),
|
|
@@ -3428,6 +4017,14 @@ function createRoutes({ courses, lessons, learner, studio, projects, jobs, setti
|
|
|
3428
4017
|
response: payload.response,
|
|
3429
4018
|
language: typeof payload.language === "string" ? payload.language.slice(0, 12) : void 0
|
|
3430
4019
|
}),
|
|
4020
|
+
"lesson/correct": (payload) => ({ job: lessons.correct({
|
|
4021
|
+
scope: scopeOf(payload),
|
|
4022
|
+
stepIndex: payload.stepIndex,
|
|
4023
|
+
anchorStepId: payload.anchorStepId,
|
|
4024
|
+
item: payload.item,
|
|
4025
|
+
response: payload.response,
|
|
4026
|
+
grade: payload.grade
|
|
4027
|
+
}) }),
|
|
3431
4028
|
"lesson/position": (payload) => lessons.savePosition({
|
|
3432
4029
|
courseId: need(payload, "courseId", "crs"),
|
|
3433
4030
|
lessonId: need(payload, "lessonId", "les"),
|
|
@@ -3479,7 +4076,7 @@ function createRoutes({ courses, lessons, learner, studio, projects, jobs, setti
|
|
|
3479
4076
|
courseId: payload.courseId
|
|
3480
4077
|
}),
|
|
3481
4078
|
"plan/remove-exam": (payload) => learner.removeExam({ id: need(payload, "id", "exm") }),
|
|
3482
|
-
"review/session": () => learner.reviewSession(),
|
|
4079
|
+
"review/session": (payload) => learner.reviewSession({ courseId: optional(payload, "courseId", "crs") }),
|
|
3483
4080
|
"material/upload": (payload) => ({ job: studio.upload({
|
|
3484
4081
|
name: payload.name,
|
|
3485
4082
|
base64: payload.base64
|
|
@@ -4083,6 +4680,7 @@ const PREF_DEFAULTS = Object.freeze({
|
|
|
4083
4680
|
voiceEngine: "browser",
|
|
4084
4681
|
voiceRate: 1,
|
|
4085
4682
|
boardTheme: "auto",
|
|
4683
|
+
boardFont: "hand",
|
|
4086
4684
|
ttsProvider: "openai",
|
|
4087
4685
|
tts: Object.fromEntries(TTS_PROVIDERS.map((provider) => [provider, providerDefaults(provider)]))
|
|
4088
4686
|
});
|
|
@@ -4112,6 +4710,7 @@ function cleanPrefs(input = {}, base = PREF_DEFAULTS) {
|
|
|
4112
4710
|
"light",
|
|
4113
4711
|
"dark"
|
|
4114
4712
|
].includes(input.boardTheme)) next.boardTheme = input.boardTheme;
|
|
4713
|
+
if (["hand", "standard"].includes(input.boardFont)) next.boardFont = input.boardFont;
|
|
4115
4714
|
if (TTS_PROVIDERS.includes(input.ttsProvider)) next.ttsProvider = input.ttsProvider;
|
|
4116
4715
|
for (const provider of TTS_PROVIDERS) {
|
|
4117
4716
|
const patch = input.tts?.[provider];
|
|
@@ -4221,6 +4820,8 @@ const ASSIST_MODES = [
|
|
|
4221
4820
|
"solve",
|
|
4222
4821
|
"visualize"
|
|
4223
4822
|
];
|
|
4823
|
+
const DIGEST_SINGLE_CHARS = 24e3;
|
|
4824
|
+
const DIGEST_NOTES_CHARS = 48e3;
|
|
4224
4825
|
function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(), uiLanguage = () => "zh-CN" }) {
|
|
4225
4826
|
const stamp = () => now().toISOString();
|
|
4226
4827
|
async function saveMaterial(result, { bytes, signal, extra = {} }) {
|
|
@@ -4246,7 +4847,7 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4246
4847
|
purpose: "quick",
|
|
4247
4848
|
prompt: materialBriefPrompt({
|
|
4248
4849
|
title: meta.title,
|
|
4249
|
-
passages: result.chunks
|
|
4850
|
+
passages: formatPassages(spreadPassages(result.chunks, { maxChars: 12e3 }), ""),
|
|
4250
4851
|
language: detectLanguage(result.chunks[0].text, uiLanguage())
|
|
4251
4852
|
}),
|
|
4252
4853
|
maxTokens: 1500,
|
|
@@ -4328,36 +4929,77 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4328
4929
|
return jobs.start("material/digest", async (api) => {
|
|
4329
4930
|
const [material] = await readMaterials(store, [assertId(id, "mat")]);
|
|
4330
4931
|
if (!material?.chunks.length) throw new TutorError("invalid", "This material has no text to digest");
|
|
4932
|
+
const title = material.meta.title;
|
|
4331
4933
|
const language = detectLanguage(material.chunks[0].text, uiLanguage());
|
|
4934
|
+
const size = material.chunks.reduce((sum, chunk) => sum + chunk.text.length, 0);
|
|
4935
|
+
let prompt;
|
|
4936
|
+
let missing = [];
|
|
4937
|
+
if (size <= DIGEST_SINGLE_CHARS) {
|
|
4938
|
+
api.progress(0, 1, "writing");
|
|
4939
|
+
prompt = digestPrompt({
|
|
4940
|
+
title,
|
|
4941
|
+
passages: formatPassages(material.chunks, ""),
|
|
4942
|
+
language
|
|
4943
|
+
});
|
|
4944
|
+
} else {
|
|
4945
|
+
const parts = documentParts(material.chunks);
|
|
4946
|
+
const notes = new Array(parts.length).fill(null);
|
|
4947
|
+
const readPart = async (index) => {
|
|
4948
|
+
try {
|
|
4949
|
+
notes[index] = await generateJson(llm, {
|
|
4950
|
+
purpose: "teach",
|
|
4951
|
+
prompt: digestPartPrompt({
|
|
4952
|
+
title,
|
|
4953
|
+
part: index + 1,
|
|
4954
|
+
parts: parts.length,
|
|
4955
|
+
range: passageRange(parts[index]),
|
|
4956
|
+
passages: formatPassages(parts[index], ""),
|
|
4957
|
+
language
|
|
4958
|
+
}),
|
|
4959
|
+
maxTokens: 6e3,
|
|
4960
|
+
signal: api.signal,
|
|
4961
|
+
normalize: normalizeDigestPart
|
|
4962
|
+
});
|
|
4963
|
+
} catch (error) {
|
|
4964
|
+
if (api.signal.aborted) throw error;
|
|
4965
|
+
}
|
|
4966
|
+
};
|
|
4967
|
+
const queue = parts.map((part, index) => index);
|
|
4968
|
+
let done = 0;
|
|
4969
|
+
api.progress(0, parts.length + 1, "reading");
|
|
4970
|
+
const worker = async () => {
|
|
4971
|
+
while (queue.length) {
|
|
4972
|
+
api.signal.throwIfAborted();
|
|
4973
|
+
await readPart(queue.shift());
|
|
4974
|
+
done += 1;
|
|
4975
|
+
api.progress(done, parts.length + 1, "reading");
|
|
4976
|
+
}
|
|
4977
|
+
};
|
|
4978
|
+
await Promise.all([worker(), worker()]);
|
|
4979
|
+
for (const [index, note] of notes.entries()) if (!note) await readPart(index);
|
|
4980
|
+
const read = notes.map((note, index) => note ? {
|
|
4981
|
+
part: index + 1,
|
|
4982
|
+
of: parts.length,
|
|
4983
|
+
range: passageRange(parts[index]),
|
|
4984
|
+
...note
|
|
4985
|
+
} : null).filter(Boolean);
|
|
4986
|
+
if (read.length < Math.ceil(parts.length / 2)) throw new TutorError("bad-output", "The model could not read enough of this document. Try again or pick a stronger model in settings.");
|
|
4987
|
+
missing = parts.map((part, index) => notes[index] ? null : passageRange(part) || `${index + 1}/${parts.length}`).filter(Boolean);
|
|
4988
|
+
api.progress(parts.length, parts.length + 1, "writing");
|
|
4989
|
+
prompt = digestPrompt({
|
|
4990
|
+
title,
|
|
4991
|
+
notes: digestNotesText(read, DIGEST_NOTES_CHARS),
|
|
4992
|
+
language
|
|
4993
|
+
});
|
|
4994
|
+
}
|
|
4332
4995
|
const result = await generateJson(llm, {
|
|
4333
4996
|
purpose: "teach",
|
|
4334
|
-
prompt
|
|
4335
|
-
title: material.meta.title,
|
|
4336
|
-
passages: passagesFor([material], "", 24e3),
|
|
4337
|
-
language
|
|
4338
|
-
}),
|
|
4997
|
+
prompt,
|
|
4339
4998
|
maxTokens: 9e3,
|
|
4340
4999
|
signal: api.signal,
|
|
4341
|
-
normalize:
|
|
4342
|
-
overview: text(raw?.overview, 2e3),
|
|
4343
|
-
structure: (Array.isArray(raw?.structure) ? raw.structure : []).slice(0, 30).map((item) => ({
|
|
4344
|
-
heading: text(item?.heading, 160),
|
|
4345
|
-
points: (item?.points ?? []).map((point) => text(point, 400)).filter(Boolean).slice(0, 10),
|
|
4346
|
-
pages: text(item?.pages, 30)
|
|
4347
|
-
})).filter((item) => item.heading),
|
|
4348
|
-
keyIdeas: (raw?.keyIdeas ?? []).map((item) => text(item, 400)).filter(Boolean).slice(0, 15),
|
|
4349
|
-
arguments: (raw?.arguments ?? []).slice(0, 15).map((item) => ({
|
|
4350
|
-
claim: text(item?.claim, 400),
|
|
4351
|
-
support: text(item?.support, 600),
|
|
4352
|
-
page: text(item?.page, 20)
|
|
4353
|
-
})).filter((item) => item.claim),
|
|
4354
|
-
glossary: (raw?.glossary ?? []).slice(0, 30).map((item) => ({
|
|
4355
|
-
term: text(item?.term, 80),
|
|
4356
|
-
meaning: text(item?.meaning, 400)
|
|
4357
|
-
})).filter((item) => item.term),
|
|
4358
|
-
questions: (raw?.questions ?? []).map((item) => text(item, 300)).filter(Boolean).slice(0, 8)
|
|
4359
|
-
})
|
|
5000
|
+
normalize: normalizeDigest
|
|
4360
5001
|
});
|
|
5002
|
+
if (missing.length) result.missing = missing;
|
|
4361
5003
|
return { material: await store.updateJson(store.paths.material(id), null, (value) => ({
|
|
4362
5004
|
...value,
|
|
4363
5005
|
digest: {
|
|
@@ -4598,6 +5240,7 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4598
5240
|
const images = await assistImages(ids);
|
|
4599
5241
|
const board = await generateSteps(llm, {
|
|
4600
5242
|
purpose: "teach",
|
|
5243
|
+
effort: "low",
|
|
4601
5244
|
prompt: assistPrompt({
|
|
4602
5245
|
mode: chosen,
|
|
4603
5246
|
request: ask,
|
|
@@ -4618,21 +5261,24 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4618
5261
|
board,
|
|
4619
5262
|
at: stamp()
|
|
4620
5263
|
};
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
5264
|
+
const id = thread?.id ?? (/^thd_[a-z0-9]{6,40}$/u.test(String(newThreadId)) ? newThreadId : newId("thd"));
|
|
5265
|
+
const saved = await store.updateJson(store.paths.item("assist", id), null, (current) => {
|
|
5266
|
+
const next = current ?? {
|
|
5267
|
+
id,
|
|
5268
|
+
title: board.title || ask.slice(0, 60),
|
|
5269
|
+
language,
|
|
5270
|
+
materialIds: [],
|
|
5271
|
+
turns: [],
|
|
5272
|
+
createdAt: stamp()
|
|
5273
|
+
};
|
|
5274
|
+
next.turns = [...next.turns ?? [], turn].slice(-30);
|
|
5275
|
+
next.materialIds = [.../* @__PURE__ */ new Set([...next.materialIds ?? [], ...ids])].slice(0, 8);
|
|
5276
|
+
next.updatedAt = stamp();
|
|
5277
|
+
return next;
|
|
5278
|
+
});
|
|
4633
5279
|
return {
|
|
4634
|
-
threadId:
|
|
4635
|
-
turn:
|
|
5280
|
+
threadId: saved.id,
|
|
5281
|
+
turn: saved.turns.length - 1,
|
|
4636
5282
|
board
|
|
4637
5283
|
};
|
|
4638
5284
|
}, { meta: { threadId: threadId ?? null } });
|
|
@@ -4656,6 +5302,7 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4656
5302
|
const language = detectLanguage(subject || passages, uiLanguage());
|
|
4657
5303
|
const board = await generateSteps(llm, {
|
|
4658
5304
|
purpose: "teach",
|
|
5305
|
+
effort: "low",
|
|
4659
5306
|
prompt: shortPrompt({
|
|
4660
5307
|
topic: subject || sourceTitle,
|
|
4661
5308
|
passages,
|
|
@@ -4702,6 +5349,60 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
|
|
|
4702
5349
|
makeShort
|
|
4703
5350
|
});
|
|
4704
5351
|
}
|
|
5352
|
+
function normalizeDigest(raw) {
|
|
5353
|
+
return {
|
|
5354
|
+
overview: text(raw?.overview, 2e3),
|
|
5355
|
+
structure: (Array.isArray(raw?.structure) ? raw.structure : []).slice(0, 30).map((item) => ({
|
|
5356
|
+
heading: text(item?.heading, 160),
|
|
5357
|
+
points: (item?.points ?? []).map((point) => text(point, 400)).filter(Boolean).slice(0, 10),
|
|
5358
|
+
pages: text(item?.pages, 30)
|
|
5359
|
+
})).filter((item) => item.heading),
|
|
5360
|
+
keyIdeas: (raw?.keyIdeas ?? []).map((item) => text(item, 400)).filter(Boolean).slice(0, 15),
|
|
5361
|
+
arguments: (raw?.arguments ?? []).slice(0, 15).map((item) => ({
|
|
5362
|
+
claim: text(item?.claim, 400),
|
|
5363
|
+
support: text(item?.support, 600),
|
|
5364
|
+
page: text(item?.page, 20)
|
|
5365
|
+
})).filter((item) => item.claim),
|
|
5366
|
+
glossary: (raw?.glossary ?? []).slice(0, 30).map((item) => ({
|
|
5367
|
+
term: text(item?.term, 80),
|
|
5368
|
+
meaning: text(item?.meaning, 400)
|
|
5369
|
+
})).filter((item) => item.term),
|
|
5370
|
+
questions: (raw?.questions ?? []).map((item) => text(item, 300)).filter(Boolean).slice(0, 8)
|
|
5371
|
+
};
|
|
5372
|
+
}
|
|
5373
|
+
function normalizeDigestPart(raw) {
|
|
5374
|
+
const value = {
|
|
5375
|
+
sections: (Array.isArray(raw?.sections) ? raw.sections : []).slice(0, 12).map((item) => ({
|
|
5376
|
+
heading: text(item?.heading, 160),
|
|
5377
|
+
pages: text(item?.pages, 30),
|
|
5378
|
+
points: (Array.isArray(item?.points) ? item.points : []).map((point) => text(point, 300)).filter(Boolean).slice(0, 6)
|
|
5379
|
+
})).filter((item) => item.heading),
|
|
5380
|
+
keyIdeas: (Array.isArray(raw?.keyIdeas) ? raw.keyIdeas : []).map((item) => text(item, 300)).filter(Boolean).slice(0, 8),
|
|
5381
|
+
arguments: (Array.isArray(raw?.arguments) ? raw.arguments : []).slice(0, 8).map((item) => ({
|
|
5382
|
+
claim: text(item?.claim, 300),
|
|
5383
|
+
support: text(item?.support, 400),
|
|
5384
|
+
page: text(item?.page, 20)
|
|
5385
|
+
})).filter((item) => item.claim),
|
|
5386
|
+
glossary: (Array.isArray(raw?.glossary) ? raw.glossary : []).slice(0, 12).map((item) => ({
|
|
5387
|
+
term: text(item?.term, 80),
|
|
5388
|
+
meaning: text(item?.meaning, 300)
|
|
5389
|
+
})).filter((item) => item.term)
|
|
5390
|
+
};
|
|
5391
|
+
if (!value.sections.length && !value.keyIdeas.length) throw new Error("no notes for this part");
|
|
5392
|
+
return value;
|
|
5393
|
+
}
|
|
5394
|
+
function digestNotesText(notes, maxChars) {
|
|
5395
|
+
const share = Math.max(600, Math.floor(maxChars / Math.max(1, notes.length)));
|
|
5396
|
+
return notes.map((note) => {
|
|
5397
|
+
const lines = [`[Part ${note.part}/${note.of}${note.range ? ` · ${note.range}` : ""}]`];
|
|
5398
|
+
for (const section of note.sections) lines.push(`- ${section.heading}${section.pages ? ` (p.${section.pages})` : ""}: ${section.points.join("; ")}`);
|
|
5399
|
+
if (note.keyIdeas.length) lines.push(`Key ideas: ${note.keyIdeas.join("; ")}`);
|
|
5400
|
+
for (const argument of note.arguments) lines.push(`Claim: ${argument.claim}${argument.page ? ` (p.${argument.page})` : ""} — ${argument.support}`);
|
|
5401
|
+
if (note.glossary.length) lines.push(`Terms: ${note.glossary.map((entry) => `${entry.term}: ${entry.meaning}`).join("; ")}`);
|
|
5402
|
+
const block = lines.join("\n");
|
|
5403
|
+
return block.length > share ? `${block.slice(0, share)}…` : block;
|
|
5404
|
+
}).join("\n\n");
|
|
5405
|
+
}
|
|
4705
5406
|
//#endregion
|
|
4706
5407
|
//#region src/index.js
|
|
4707
5408
|
const name = "aha-tutor";
|
|
@@ -4822,6 +5523,7 @@ function apply(ctx) {
|
|
|
4822
5523
|
if (typeof fetchRoutes?.register !== "function") return;
|
|
4823
5524
|
connectionCtx.effect(() => fetchRoutes.register(uploadRoute({ studio })), "aha-tutor: upload route");
|
|
4824
5525
|
connectionCtx.effect(() => fetchRoutes.register(ttsRoute({ speak })), "aha-tutor: tts route");
|
|
5526
|
+
connectionCtx.effect(() => fetchRoutes.register(fontRoute()), "aha-tutor: font route");
|
|
4825
5527
|
});
|
|
4826
5528
|
ctx.effect(() => publishRuntime({
|
|
4827
5529
|
store,
|