dsh-aha-tutor 1.0.0 → 1.2.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/lib/index.js CHANGED
@@ -1,10 +1,16 @@
1
- import { $ as normalizePractice, A as materialImages, B as boardToPlainText, C as TutorError, D as EMPTY_PROFILE, E as generateText, F as readProgress, G as flattenLessons, H as conceptIndex, I as applyEvidence, J as lessonAfter, K as insertLesson, L as createConceptState, M as passagesFor, N as readMaterials, O as emptyProgress, P as readProfile, Q as normalizeCheatsheet, R as masteryPercent, S as summaryPrompt, T as generateSteps, U as courseProgress, V as normalizeBoard, W as findLesson, X as normalizeBlueprint, Y as nextLesson, Z as normalizeCards, _ as questionnairePrompt, a as blueprintPrompt, at as assertId, b as revisePrompt, c as digestPrompt, d as lessonPrompt, et as normalizeProject, f as materialBriefPrompt, g as projectsPrompt, h as projectReviewPrompt, i as assistPrompt, it as text, j as materialsSummary, k as masteryFor, l as flashcardsPrompt, m as profilePrompt, n as publishRuntime, nt as outlineForPrompt, o as cheatsheetPrompt, ot as newId, p as practicePrompt, q as intakeSummary, r as askPrompt, rt as safeRelativePath, s as detectLanguage, tt as normalizeQuestionnaire, u as gradePrompt, v as quizPrompt, w as generateJson, x as shortPrompt, y as reexplainPrompt, z as recommendNext } from "./runtime-CiA2I7-X.js";
1
+ import { $ as intakeSummary, A as emptyProgress, B as passageRange, C as summaryPrompt, D as generateText, E as generateSteps, F as readMaterials, G as recommendNext, H as applyEvidence, I as readProfile, J as conceptIndex, K as boardToPlainText, L as readProgress, M as materialImages, N as materialsSummary, O as streamCounter, P as passagesFor, Q as insertLesson, R as documentParts, S as shortPrompt, T as generateJson, U as createConceptState, V as spreadPassages, W as masteryPercent, X as findLesson, Y as courseProgress, Z as flattenLessons, _ as projectsPrompt, a as blueprintPrompt, at as normalizePractice, b as reexplainPrompt, c as digestPartPrompt, ct as outlineForPrompt, d as gradePrompt, dt as assertId, et as lessonAfter, f as lessonPrompt, ft as newId, g as projectReviewPrompt, h as profilePrompt, i as assistPrompt, it as normalizeCheatsheet, j as masteryFor, k as EMPTY_PROFILE, l as digestPrompt, lt as safeRelativePath, m as practicePrompt, n as publishRuntime, nt as normalizeBlueprint, o as cheatsheetPrompt, ot as normalizeProject, p as materialBriefPrompt, q as normalizeBoard, r as askPrompt, rt as normalizeCards, s as detectLanguage, st as normalizeQuestionnaire, tt as nextLesson, u as flashcardsPrompt, ut as text, v as questionnairePrompt, w as TutorError, x as revisePrompt, y as quizPrompt, z as formatPassages } from "./runtime-ywaTyu56.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";
@@ -268,6 +274,7 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
268
274
  progress,
269
275
  intake,
270
276
  jobs: {
277
+ questions: jobs.running(`questions:${courseId}`),
271
278
  blueprint: jobs.running(`blueprint:${courseId}`),
272
279
  confirm: jobs.running(`confirm:${courseId}`)
273
280
  },
@@ -327,7 +334,10 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
327
334
  courseId,
328
335
  questionnaire
329
336
  };
330
- }, { meta: { courseId } });
337
+ }, {
338
+ key: `questions:${courseId}`,
339
+ meta: { courseId }
340
+ });
331
341
  }
332
342
  function submitIntake({ courseId, answers = {}, timeline = "balanced", weeklyMinutes, deadline }) {
333
343
  assertId(courseId, "crs");
@@ -350,7 +360,7 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
350
360
  weeklyMinutes: clampMinutes(weeklyMinutes),
351
361
  deadline: /^\d{4}-\d{2}-\d{2}$/u.test(String(deadline ?? "")) ? deadline : null
352
362
  };
353
- api.progress(0, 1, "blueprint");
363
+ api.progress(0, 0, "blueprint");
354
364
  const blueprint = await generateJson(llm, {
355
365
  purpose: "teach",
356
366
  prompt: blueprintPrompt({
@@ -365,6 +375,7 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
365
375
  images: llm.supportsImages?.("teach") ? await materialImages(store, materials) : void 0,
366
376
  maxTokens: 16e3,
367
377
  signal: api.signal,
378
+ onText: streamCounter("\"estMinutes\"", (count) => api.progress(count, 0, "blueprint")),
368
379
  normalize: (raw) => attachProjectUnits(raw, normalizeBlueprint(raw, { language: course.language }))
369
380
  });
370
381
  const next = {
@@ -375,7 +386,6 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
375
386
  settings
376
387
  };
377
388
  await saveCourse(next);
378
- api.progress(1, 1, "blueprint");
379
389
  return { course: next };
380
390
  }, {
381
391
  key: `blueprint:${courseId}`,
@@ -388,23 +398,26 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
388
398
  return jobs.start("craft/revise", async (api) => {
389
399
  const course = await readCourse(courseId);
390
400
  if (!course.units) throw new TutorError("invalid", "There is no blueprint to revise yet");
401
+ const current = {
402
+ title: course.title,
403
+ subtitle: course.subtitle,
404
+ emoji: course.emoji,
405
+ summary: course.summary,
406
+ level: course.level,
407
+ units: course.units,
408
+ projects: course.projects
409
+ };
410
+ api.progress(0, 0, "blueprint");
391
411
  const revised = await generateJson(llm, {
392
412
  purpose: "teach",
393
413
  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
- },
414
+ blueprint: current,
403
415
  instruction: request,
404
416
  language: course.language
405
417
  }),
406
418
  maxTokens: 16e3,
407
419
  signal: api.signal,
420
+ onText: streamCounter("\"estMinutes\"", (count) => api.progress(count, 0, "blueprint")),
408
421
  normalize: (raw) => attachProjectUnits(raw, normalizeBlueprint(raw, { language: course.language }))
409
422
  });
410
423
  const next = {
@@ -438,11 +451,40 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
438
451
  await saveCourse(next);
439
452
  return { course: next };
440
453
  }
454
+ async function writeLecturePractice({ course, lecture, lessons = lecture.lessons, materials, signal }) {
455
+ const query = lessons.map((lesson) => `${lesson.title} ${lesson.objectives.join(" ")}`).join(" ");
456
+ const sources = materials ?? await readMaterials(store, course.materialIds ?? []);
457
+ const sets = await generateJson(llm, {
458
+ purpose: "teach",
459
+ prompt: practicePrompt({
460
+ course,
461
+ lecture,
462
+ lessons,
463
+ language: course.language,
464
+ passages: passagesFor(sources, query, 5e3)
465
+ }),
466
+ maxTokens: Math.min(16e3, 3e3 + lessons.length * 2200),
467
+ signal,
468
+ normalize: (raw) => raw?.lessons ?? raw
469
+ });
470
+ const written = {};
471
+ for (const lesson of lessons) {
472
+ 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));
473
+ if (!set.items.length) continue;
474
+ written[lesson.id] = {
475
+ lessonId: lesson.id,
476
+ ...set,
477
+ createdAt: stamp()
478
+ };
479
+ await store.writeJson(store.paths.practice(course.id, lesson.id), written[lesson.id]);
480
+ }
481
+ return written;
482
+ }
441
483
  function confirm({ courseId }) {
442
484
  return jobs.start("craft/confirm", async (api) => {
443
485
  const course = await readCourse(courseId);
444
486
  if (!course.units) throw new TutorError("invalid", "Generate a blueprint first");
445
- const lectures = course.units.flatMap((unit) => unit.lectures.map((lecture) => ({
487
+ const lectures = course.units.slice(0, 1).flatMap((unit) => unit.lectures.map((lecture) => ({
446
488
  unit,
447
489
  lecture
448
490
  })));
@@ -489,29 +531,12 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
489
531
  api.signal.throwIfAborted();
490
532
  const { lecture } = queue.shift();
491
533
  try {
492
- const query = lecture.lessons.map((lesson) => `${lesson.title} ${lesson.objectives.join(" ")}`).join(" ");
493
- const sets = await generateJson(llm, {
494
- purpose: "teach",
495
- prompt: practicePrompt({
496
- course,
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
534
+ await writeLecturePractice({
535
+ course,
536
+ lecture,
537
+ materials,
538
+ signal: api.signal
505
539
  });
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
540
  } catch (error) {
516
541
  if (api.signal.aborted) throw error;
517
542
  warnings.push(lecture.id);
@@ -618,6 +643,7 @@ function createCourses({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(
618
643
  submitIntake,
619
644
  revise,
620
645
  saveBlueprint,
646
+ writeLecturePractice,
621
647
  confirm,
622
648
  update,
623
649
  remove,
@@ -663,12 +689,297 @@ function safeFileName(value) {
663
689
  return /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/iu.test(cleaned) || !cleaned ? "course" : cleaned;
664
690
  }
665
691
  //#endregion
692
+ //#region src/core/board-fonts.js
693
+ const BOARD_FONT_FILES = Object.freeze([
694
+ Object.freeze({
695
+ family: "Aha Hand Latin",
696
+ file: "caveat-latin-d0b7b931.woff2",
697
+ bytes: 48836,
698
+ unicodeRange: "U+0,U+D,U+20-7E,U+A0-FF,U+131,U+152-153,U+20AC,U+2122"
699
+ }),
700
+ Object.freeze({
701
+ family: "Aha Hand",
702
+ file: "wenkai-gb-0-88f1a875.woff2",
703
+ bytes: 93632,
704
+ 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"
705
+ }),
706
+ Object.freeze({
707
+ family: "Aha Hand",
708
+ file: "wenkai-gb-1-78a38e72.woff2",
709
+ bytes: 315108,
710
+ 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"
711
+ }),
712
+ Object.freeze({
713
+ family: "Aha Hand",
714
+ file: "wenkai-gb-2-2a649892.woff2",
715
+ bytes: 317648,
716
+ 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"
717
+ }),
718
+ Object.freeze({
719
+ family: "Aha Hand",
720
+ file: "wenkai-gb-3-6949c050.woff2",
721
+ bytes: 311704,
722
+ 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"
723
+ }),
724
+ Object.freeze({
725
+ family: "Aha Hand",
726
+ file: "wenkai-gb-4-375dc3b3.woff2",
727
+ bytes: 257596,
728
+ 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"
729
+ }),
730
+ Object.freeze({
731
+ family: "Aha Hand",
732
+ file: "wenkai-gb-5-d0359bbc.woff2",
733
+ bytes: 278908,
734
+ 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"
735
+ }),
736
+ Object.freeze({
737
+ family: "Aha Hand",
738
+ file: "wenkai-gb-6-a238b41c.woff2",
739
+ bytes: 307604,
740
+ 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"
741
+ })
742
+ ]);
743
+ //#endregion
744
+ //#region src/host/web-fetch.js
745
+ const LOCAL_ADDRESS_MESSAGE = "Local network addresses are not supported";
746
+ var AddressError = class extends Error {
747
+ constructor(message = LOCAL_ADDRESS_MESSAGE) {
748
+ super(message);
749
+ this.name = "AddressError";
750
+ this.code = "bad-url";
751
+ }
752
+ };
753
+ const V4_BLOCKED = [
754
+ ["0.0.0.0", 8],
755
+ ["10.0.0.0", 8],
756
+ ["100.64.0.0", 10],
757
+ ["127.0.0.0", 8],
758
+ ["169.254.0.0", 16],
759
+ ["172.16.0.0", 12],
760
+ ["192.0.0.0", 24],
761
+ ["192.0.2.0", 24],
762
+ ["192.88.99.0", 24],
763
+ ["192.168.0.0", 16],
764
+ ["198.18.0.0", 15],
765
+ ["198.51.100.0", 24],
766
+ ["203.0.113.0", 24],
767
+ ["224.0.0.0", 4],
768
+ ["240.0.0.0", 4]
769
+ ].map(([base, bits]) => [v4Number(base), bits]);
770
+ const V6_BLOCKED = [
771
+ ["fc00::", 7],
772
+ ["fe80::", 10],
773
+ ["fec0::", 10],
774
+ ["ff00::", 8],
775
+ ["100::", 64],
776
+ ["64:ff9b:1::", 48],
777
+ ["2001::", 32],
778
+ ["2001:2::", 48],
779
+ ["2001:10::", 28],
780
+ ["2001:20::", 28],
781
+ ["2001:db8::", 32]
782
+ ].map(([base, bits]) => [v6Bytes(base), bits]);
783
+ function v4Number(address) {
784
+ const parts = address.split(".").map(Number);
785
+ return (parts[0] << 24 >>> 0) + (parts[1] << 16) + (parts[2] << 8) + parts[3] >>> 0;
786
+ }
787
+ function v4Public(address) {
788
+ const value = v4Number(address);
789
+ return !V4_BLOCKED.some(([base, bits]) => bits === 0 ? true : value >>> 32 - bits === base >>> 32 - bits);
790
+ }
791
+ function v6Bytes(address) {
792
+ let text = String(address).toLowerCase();
793
+ const zone = text.indexOf("%");
794
+ if (zone >= 0) text = text.slice(0, zone);
795
+ const groups = [];
796
+ const dotted = text.match(/(\d+\.\d+\.\d+\.\d+)$/u);
797
+ if (dotted) {
798
+ const value = v4Number(dotted[1]);
799
+ text = `${text.slice(0, -dotted[1].length)}${(value >>> 16).toString(16)}:${(value & 65535).toString(16)}`;
800
+ }
801
+ const [head, tail] = text.includes("::") ? text.split("::") : [text, null];
802
+ const left = head ? head.split(":") : [];
803
+ const right = tail ? tail.split(":") : [];
804
+ const fill = tail === null ? 0 : 8 - left.length - right.length;
805
+ for (const group of [
806
+ ...left,
807
+ ...Array(Math.max(0, fill)).fill("0"),
808
+ ...right
809
+ ]) groups.push(Number.parseInt(group || "0", 16));
810
+ const bytes = /* @__PURE__ */ new Uint8Array(16);
811
+ groups.slice(0, 8).forEach((group, index) => {
812
+ bytes[index * 2] = group >> 8 & 255;
813
+ bytes[index * 2 + 1] = group & 255;
814
+ });
815
+ return bytes;
816
+ }
817
+ function prefixMatches(bytes, base, bits) {
818
+ for (let bit = 0; bit < bits; bit += 8) {
819
+ const mask = 255 << 8 - Math.min(8, bits - bit) & 255;
820
+ if ((bytes[bit / 8] & mask) !== (base[bit / 8] & mask)) return false;
821
+ }
822
+ return true;
823
+ }
824
+ const embeddedV4 = (bytes, at) => `${bytes[at]}.${bytes[at + 1]}.${bytes[at + 2]}.${bytes[at + 3]}`;
825
+ function v6Public(address) {
826
+ const bytes = v6Bytes(address);
827
+ const zeros = (count) => bytes.subarray(0, count).every((byte) => byte === 0);
828
+ if (zeros(12) || zeros(10) && bytes[10] === 255 && bytes[11] === 255) return v4Public(embeddedV4(bytes, 12));
829
+ if (prefixMatches(bytes, v6Bytes("64:ff9b::"), 96)) return v4Public(embeddedV4(bytes, 12));
830
+ if (bytes[0] === 32 && bytes[1] === 2) return v4Public(embeddedV4(bytes, 2));
831
+ return !V6_BLOCKED.some(([base, bits]) => prefixMatches(bytes, base, bits));
832
+ }
833
+ function isPublicAddress(address) {
834
+ const value = String(address ?? "").replace(/^\[|\]$/gu, "");
835
+ const family = isIP(value.split("%")[0]);
836
+ if (family === 4) return v4Public(value);
837
+ if (family === 6) return v6Public(value);
838
+ return false;
839
+ }
840
+ const LOCAL_NAME = /(^|\.)(localhost|local|internal|home\.arpa)$/u;
841
+ function assertPublicHostname(hostname) {
842
+ const host = String(hostname ?? "").replace(/^\[|\]$/gu, "").replace(/\.+$/u, "").toLowerCase();
843
+ if (!host) throw new AddressError("This is not a valid web address");
844
+ if (isIP(host)) {
845
+ if (!isPublicAddress(host)) throw new AddressError();
846
+ return true;
847
+ }
848
+ if (LOCAL_NAME.test(host) || !host.includes(".")) throw new AddressError();
849
+ return false;
850
+ }
851
+ function createGuardedLookup({ resolve = lookup, allowed = isPublicAddress } = {}) {
852
+ return function guardedLookup(hostname, options, callback) {
853
+ const done = typeof options === "function" ? options : callback;
854
+ const wanted = typeof options === "object" && options ? options : {};
855
+ resolve(hostname, { all: true }, (error, addresses) => {
856
+ if (error) return done(error);
857
+ const list = (Array.isArray(addresses) ? addresses : []).map((entry) => typeof entry === "string" ? {
858
+ address: entry,
859
+ family: isIP(entry)
860
+ } : entry).filter((entry) => entry?.address);
861
+ if (!list.length) return done(Object.assign(/* @__PURE__ */ new Error(`No address for ${hostname}`), { code: "ENOTFOUND" }));
862
+ if (list.some((entry) => !allowed(entry.address))) return done(new AddressError());
863
+ const family = wanted.family === 4 || wanted.family === 6 ? wanted.family : 0;
864
+ const usable = family ? list.filter((entry) => entry.family === family) : list;
865
+ const chosen = usable.length ? usable : list;
866
+ if (wanted.all) return done(null, chosen.map((entry) => ({
867
+ address: entry.address,
868
+ family: entry.family
869
+ })));
870
+ return done(null, chosen[0].address, chosen[0].family);
871
+ });
872
+ };
873
+ }
874
+ const EMPTY_BODY_STATUS = /* @__PURE__ */ new Set([
875
+ 101,
876
+ 204,
877
+ 205,
878
+ 304
879
+ ]);
880
+ function decoded(response) {
881
+ const encoding = String(response.headers["content-encoding"] ?? "").trim().toLowerCase();
882
+ const decoder = encoding === "gzip" || encoding === "x-gzip" ? zlib.createGunzip() : encoding === "deflate" ? zlib.createInflate() : encoding === "br" ? zlib.createBrotliDecompress() : null;
883
+ if (!decoder) return response;
884
+ return pipeline(response, decoder, () => void 0);
885
+ }
886
+ function toHeaders(raw) {
887
+ const headers = new Headers();
888
+ for (const [name, value] of Object.entries(raw ?? {})) {
889
+ if (name === "content-encoding" || name === "content-length" || value === void 0) continue;
890
+ for (const entry of Array.isArray(value) ? value : [value]) try {
891
+ headers.append(name, String(entry));
892
+ } catch {}
893
+ }
894
+ return headers;
895
+ }
896
+ function createGuardedFetch({ resolve, allowed = isPublicAddress, maxBytes = 64 * 1024 * 1024 } = {}) {
897
+ const lookup = createGuardedLookup({
898
+ resolve,
899
+ allowed
900
+ });
901
+ return function guardedFetch(input, { headers = {}, signal } = {}) {
902
+ return new Promise((fulfil, reject) => {
903
+ let target;
904
+ try {
905
+ target = input instanceof URL ? input : new URL(String(input));
906
+ if (target.protocol !== "http:" && target.protocol !== "https:") throw new AddressError("Only http and https addresses are supported");
907
+ const literal = target.hostname.replace(/^\[|\]$/gu, "");
908
+ if (isIP(literal) && !allowed(literal)) throw new AddressError();
909
+ } catch (error) {
910
+ reject(error);
911
+ return;
912
+ }
913
+ const transport = target.protocol === "https:" ? https : http;
914
+ let settled = false;
915
+ const fail = (error) => {
916
+ if (settled) return;
917
+ settled = true;
918
+ reject(error);
919
+ };
920
+ const request = transport.request(target, {
921
+ method: "GET",
922
+ agent: false,
923
+ lookup,
924
+ signal,
925
+ headers: {
926
+ ...headers,
927
+ "accept-encoding": "gzip, deflate, br"
928
+ }
929
+ }, (response) => {
930
+ const status = response.statusCode ?? 0;
931
+ if (status < 200 || status > 599) {
932
+ response.resume();
933
+ fail(Object.assign(/* @__PURE__ */ new Error(`Unexpected status ${status}`), { code: "EBADSTATUS" }));
934
+ return;
935
+ }
936
+ if (status >= 300 && status < 400 || EMPTY_BODY_STATUS.has(status)) {
937
+ response.resume();
938
+ settled = true;
939
+ fulfil(new Response(null, {
940
+ status,
941
+ headers: toHeaders(response.headers)
942
+ }));
943
+ return;
944
+ }
945
+ const body = decoded(response);
946
+ const parts = [];
947
+ let size = 0;
948
+ body.on("data", (chunk) => {
949
+ if (settled) return;
950
+ size += chunk.length;
951
+ if (size > maxBytes) {
952
+ request.destroy();
953
+ body.destroy?.();
954
+ fail(Object.assign(/* @__PURE__ */ new Error("Response too large"), { code: "ETOOLARGE" }));
955
+ return;
956
+ }
957
+ parts.push(chunk);
958
+ });
959
+ body.on("error", fail);
960
+ body.on("end", () => {
961
+ if (settled) return;
962
+ settled = true;
963
+ fulfil(new Response(Buffer.concat(parts), {
964
+ status,
965
+ headers: toHeaders(response.headers)
966
+ }));
967
+ });
968
+ });
969
+ request.on("error", fail);
970
+ request.end();
971
+ });
972
+ };
973
+ }
974
+ createGuardedFetch();
975
+ //#endregion
666
976
  //#region src/host/materials.js
667
977
  const MAX_UPLOAD_BYTES = 60 * 1024 * 1024;
668
978
  const MAX_TEXT_CHARS = 2e6;
669
979
  const CHUNK_CHARS = 1600;
670
980
  const FETCH_TIMEOUT_MS = 2e4;
671
981
  const MAX_PAGE_BYTES = 6 * 1024 * 1024;
982
+ const pageFetch = createGuardedFetch({ maxBytes: MAX_UPLOAD_BYTES });
672
983
  var MaterialError = class extends Error {
673
984
  constructor(code, message) {
674
985
  super(message);
@@ -984,7 +1295,6 @@ async function ingestFile({ name, bytes, signal }) {
984
1295
  const result = extractPlain(bytes, kind);
985
1296
  return finish(kind, result.title || baseTitle, result.chunks);
986
1297
  }
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
1298
  function checkPublicUrl(value) {
989
1299
  let url;
990
1300
  try {
@@ -994,10 +1304,14 @@ function checkPublicUrl(value) {
994
1304
  }
995
1305
  if (url.protocol !== "https:" && url.protocol !== "http:") throw new MaterialError("bad-url", "Only http and https addresses are supported");
996
1306
  if (url.username || url.password) throw new MaterialError("bad-url", "Addresses with credentials are not supported");
997
- if (PRIVATE_HOST.test(url.hostname)) throw new MaterialError("bad-url", "Local network addresses are not supported");
1307
+ try {
1308
+ assertPublicHostname(url.hostname);
1309
+ } catch (error) {
1310
+ throw new MaterialError("bad-url", error.message);
1311
+ }
998
1312
  return url;
999
1313
  }
1000
- async function ingestUrl(address, { fetchImpl = globalThis.fetch, signal } = {}) {
1314
+ async function ingestUrl(address, { fetchImpl = pageFetch, signal } = {}) {
1001
1315
  let url = checkPublicUrl(address);
1002
1316
  let response;
1003
1317
  for (let hop = 0; hop < 6; hop += 1) {
@@ -1013,6 +1327,8 @@ async function ingestUrl(address, { fetchImpl = globalThis.fetch, signal } = {})
1013
1327
  });
1014
1328
  } catch (error) {
1015
1329
  if (signal?.aborted) throw signal.reason ?? error;
1330
+ if (error?.name === "AddressError") throw new MaterialError("bad-url", error.message);
1331
+ if (error?.code === "ETOOLARGE") throw new MaterialError("too-large", "The page is too large");
1016
1332
  throw new MaterialError("network", timeout.aborted ? "The page took too long to load" : "The page could not be loaded");
1017
1333
  }
1018
1334
  if (response.status >= 300 && response.status < 400 && response.headers.get("location")) {
@@ -1057,6 +1373,7 @@ async function ingestUrl(address, { fetchImpl = globalThis.fetch, signal } = {})
1057
1373
  //#region src/host/http.js
1058
1374
  const UPLOAD_PATH = "/api/aha-tutor/upload";
1059
1375
  const TTS_PATH = "/api/aha-tutor/tts";
1376
+ const FONT_PATH = "/api/aha-tutor/font";
1060
1377
  async function readCapped(stream, max, signal) {
1061
1378
  const parts = [];
1062
1379
  let size = 0;
@@ -1140,6 +1457,34 @@ function ttsRoute({ speak }) {
1140
1457
  }
1141
1458
  };
1142
1459
  }
1460
+ function fontsDir() {
1461
+ return join(dirname(createRequire(import.meta.url).resolve("dsh-aha-tutor/package.json")), "assets", "fonts");
1462
+ }
1463
+ const FONT_FILES = new Set(BOARD_FONT_FILES.map((entry) => entry.file));
1464
+ function fontRoute({ dir = fontsDir() } = {}) {
1465
+ const loaded = /* @__PURE__ */ new Map();
1466
+ return {
1467
+ path: FONT_PATH,
1468
+ methods: ["GET"],
1469
+ requestBody: "buffered",
1470
+ fetch: async (request) => {
1471
+ const name = new URL(request.url).searchParams.get("f") ?? "";
1472
+ if (!FONT_FILES.has(name)) return new Response("Not found", { status: 404 });
1473
+ try {
1474
+ if (!loaded.has(name)) loaded.set(name, await readFile(join(dir, name)));
1475
+ } catch {
1476
+ return new Response("Not found", { status: 404 });
1477
+ }
1478
+ return new Response(loaded.get(name), {
1479
+ status: 200,
1480
+ headers: {
1481
+ "content-type": "font/woff2",
1482
+ "cache-control": "public, max-age=31536000, immutable"
1483
+ }
1484
+ });
1485
+ }
1486
+ };
1487
+ }
1143
1488
  //#endregion
1144
1489
  //#region src/host/jobs.js
1145
1490
  const KEEP_FINISHED_MS = 10 * 6e4;
@@ -1162,7 +1507,7 @@ function createJobs({ logger, now = Date.now } = {}) {
1162
1507
  sweep();
1163
1508
  if (key && byKey.has(key)) {
1164
1509
  const existing = jobs.get(byKey.get(key));
1165
- if (existing && !existing.finishedAt) return snapshot(existing);
1510
+ if (existing && !existing.finishedAt && !existing.controller.signal.aborted) return snapshot(existing);
1166
1511
  }
1167
1512
  const controller = new AbortController();
1168
1513
  const job = {
@@ -1206,7 +1551,10 @@ function createJobs({ logger, now = Date.now } = {}) {
1206
1551
  job.result = result;
1207
1552
  }).catch((error) => {
1208
1553
  job.status = controller.signal.aborted ? "cancelled" : "failed";
1209
- job.error = {
1554
+ job.error = controller.signal.aborted ? {
1555
+ code: "cancelled",
1556
+ message: "Cancelled"
1557
+ } : {
1210
1558
  code: error?.code ?? "failed",
1211
1559
  message: publicMessage(error)
1212
1560
  };
@@ -1241,7 +1589,11 @@ function createJobs({ logger, now = Date.now } = {}) {
1241
1589
  function running(key) {
1242
1590
  const id = byKey.get(key);
1243
1591
  const job = id ? jobs.get(id) : void 0;
1244
- return job && !job.finishedAt ? snapshot(job) : null;
1592
+ return job && !job.finishedAt && !job.controller.signal.aborted ? snapshot(job) : null;
1593
+ }
1594
+ function cancelKey(key) {
1595
+ const job = running(key);
1596
+ return job ? cancel(job.id) : null;
1245
1597
  }
1246
1598
  function dispose() {
1247
1599
  for (const job of jobs.values()) if (!job.finishedAt) job.controller.abort(/* @__PURE__ */ new Error("plugin stopped"));
@@ -1252,6 +1604,7 @@ function createJobs({ logger, now = Date.now } = {}) {
1252
1604
  start,
1253
1605
  get,
1254
1606
  cancel,
1607
+ cancelKey,
1255
1608
  running,
1256
1609
  dispose
1257
1610
  });
@@ -1768,6 +2121,7 @@ function round2(value) {
1768
2121
  //#endregion
1769
2122
  //#region src/host/lessons.js
1770
2123
  const EVENTS_KEPT = 200;
2124
+ const STEP_ID = /^s\d{1,4}$/u;
1771
2125
  function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__PURE__ */ new Date() }) {
1772
2126
  const stamp = () => now().toISOString();
1773
2127
  async function context(courseId, lessonId) {
@@ -1781,10 +2135,11 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1781
2135
  }
1782
2136
  async function get({ courseId, lessonId }) {
1783
2137
  const { course, row } = await context(courseId, lessonId);
1784
- const [board, practice, progress] = await Promise.all([
2138
+ const [board, practice, progress, asides] = await Promise.all([
1785
2139
  store.readJson(store.paths.board(courseId, lessonId), null),
1786
2140
  store.readJson(store.paths.practice(courseId, lessonId), null),
1787
- readProgress(store, courseId)
2141
+ readProgress(store, courseId),
2142
+ store.readJson(store.paths.asides(courseId, lessonId), null)
1788
2143
  ]);
1789
2144
  return {
1790
2145
  courseId,
@@ -1800,6 +2155,7 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1800
2155
  lesson: row.lesson,
1801
2156
  board,
1802
2157
  practice,
2158
+ asides: Array.isArray(asides?.items) ? asides.items : [],
1803
2159
  state: progress.lessons?.[lessonId] ?? {
1804
2160
  status: "new",
1805
2161
  stepIndex: 0
@@ -1845,6 +2201,11 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1845
2201
  }
1846
2202
  async function prepare({ courseId, lessonId, force = false, style }) {
1847
2203
  const { course, row } = await context(courseId, lessonId);
2204
+ ensurePractice(course, row);
2205
+ if (force) {
2206
+ jobs.cancelKey(`board:${courseId}:${lessonId}`);
2207
+ await store.writeJson(store.paths.asides(courseId, lessonId), { items: [] });
2208
+ }
1848
2209
  if (!force) {
1849
2210
  const existing = await store.readJson(store.paths.board(courseId, lessonId), null);
1850
2211
  if (existing) {
@@ -1939,7 +2300,18 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1939
2300
  }
1940
2301
  throw new TutorError("invalid", "Unknown board");
1941
2302
  }
1942
- function ask({ scope, stepIndex = 0, question }) {
2303
+ async function keepAside(scope, aside) {
2304
+ if (scope?.kind !== "lesson") return null;
2305
+ const saved = {
2306
+ id: newId("asd"),
2307
+ ...aside,
2308
+ at: stamp()
2309
+ };
2310
+ await store.updateJson(store.paths.asides(scope.courseId, scope.lessonId), null, (value) => ({ items: [...Array.isArray(value?.items) ? value.items : [], saved].slice(-30) }));
2311
+ return saved;
2312
+ }
2313
+ const anchorFor = (board, stepIndex, anchorStepId) => STEP_ID.test(String(anchorStepId)) ? anchorStepId : board?.steps?.[Math.max(0, Number(stepIndex) || 0)]?.id ?? "s1";
2314
+ function ask({ scope, stepIndex = 0, question, anchorStepId }) {
1943
2315
  const request = text(question, 1500);
1944
2316
  if (!request) throw new TutorError("invalid", "Type your question");
1945
2317
  return jobs.start("lesson/ask", async (api) => {
@@ -1963,15 +2335,24 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1963
2335
  conceptIds: lesson?.concepts?.map((concept) => concept.id) ?? [],
1964
2336
  onStep: (step) => api.push(step)
1965
2337
  });
2338
+ const aside = await keepAside(scope, {
2339
+ kind: "question",
2340
+ question: request,
2341
+ anchorStepId: anchorFor(board, stepIndex, anchorStepId),
2342
+ steps: answer.steps
2343
+ });
1966
2344
  if (scope.kind === "lesson") await logEvent(scope.courseId, {
1967
2345
  type: "question",
1968
2346
  lessonId: scope.lessonId,
1969
2347
  text: request.slice(0, 200)
1970
2348
  });
1971
- return { steps: answer.steps };
2349
+ return {
2350
+ steps: answer.steps,
2351
+ aside
2352
+ };
1972
2353
  });
1973
2354
  }
1974
- function reexplain({ scope, stepIndex = 0, style = "example" }) {
2355
+ function reexplain({ scope, stepIndex = 0, style = "example", anchorStepId }) {
1975
2356
  return jobs.start("lesson/reexplain", async (api) => {
1976
2357
  const { course, lesson, board, language } = await scopeBoard(scope);
1977
2358
  if (!board?.steps?.length) throw new TutorError("invalid", "Nothing to re-explain yet");
@@ -1993,6 +2374,12 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
1993
2374
  conceptIds: lesson?.concepts?.map((concept) => concept.id) ?? [],
1994
2375
  onStep: (next) => api.push(next)
1995
2376
  });
2377
+ const aside = await keepAside(scope, {
2378
+ kind: "reexplain",
2379
+ style,
2380
+ anchorStepId: anchorFor(board, index, anchorStepId),
2381
+ steps: answer.steps
2382
+ });
1996
2383
  if (scope.kind === "lesson" && course) {
1997
2384
  const conceptIds = lesson.concepts.map((concept) => concept.id);
1998
2385
  await record({
@@ -2002,7 +2389,10 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
2002
2389
  evidence: { kind: "reexplain" }
2003
2390
  });
2004
2391
  }
2005
- return { steps: answer.steps };
2392
+ return {
2393
+ steps: answer.steps,
2394
+ aside
2395
+ };
2006
2396
  });
2007
2397
  }
2008
2398
  async function record({ courseId, lessonId, conceptIds = [], evidence = {} }) {
@@ -2169,37 +2559,34 @@ function createLessons({ store, llm, jobs, courses, learner, now = () => /* @__P
2169
2559
  const { course, row } = await context(courseId, lessonId);
2170
2560
  const existing = await store.readJson(store.paths.practice(courseId, lessonId), null);
2171
2561
  if (existing) return { practice: existing };
2172
- return { job: jobs.start("lesson/practice", async (api) => {
2173
- const materials = await readMaterials(store, course.materialIds ?? []);
2174
- const sets = await generateJson(llm, {
2175
- purpose: "teach",
2176
- prompt: practicePrompt({
2177
- course,
2178
- lecture: row.lecture,
2179
- lessons: [row.lesson],
2180
- language: course.language,
2181
- passages: passagesFor(materials, row.lesson.title, 4e3)
2182
- }),
2183
- maxTokens: 5e3,
2184
- signal: api.signal,
2185
- normalize: (raw) => raw?.lessons ?? raw
2186
- });
2187
- const set = normalizePractice(sets?.[lessonId] ?? Object.values(sets ?? {})[0] ?? { items: [] }, row.lesson.concepts.map((concept) => concept.id));
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 };
2562
+ return { job: lecturePractice(course, row) };
2563
+ }
2564
+ function lecturePractice(course, row) {
2565
+ return jobs.start("lesson/practice", async (api) => {
2566
+ const missing = [];
2567
+ for (const lesson of row.lecture.lessons) if (!await store.exists(store.paths.practice(course.id, lesson.id))) missing.push(lesson);
2568
+ const written = missing.length ? await courses.writeLecturePractice({
2569
+ course,
2570
+ lecture: row.lecture,
2571
+ lessons: missing,
2572
+ signal: api.signal
2573
+ }) : {};
2574
+ const sets = {};
2575
+ for (const lesson of row.lecture.lessons) sets[lesson.id] = written[lesson.id] ?? await store.readJson(store.paths.practice(course.id, lesson.id), null);
2576
+ if (!Object.values(sets).some(Boolean)) throw new TutorError("bad-output", "No practice items came back. Try again.");
2577
+ return { sets };
2196
2578
  }, {
2197
- key: `practice:${courseId}:${lessonId}`,
2579
+ key: `practice:${course.id}:${row.lecture.id}`,
2198
2580
  meta: {
2199
- courseId,
2200
- lessonId
2581
+ courseId: course.id,
2582
+ lectureId: row.lecture.id
2201
2583
  }
2202
- }) };
2584
+ });
2585
+ }
2586
+ function ensurePractice(course, row) {
2587
+ store.exists(store.paths.practice(course.id, row.lesson.id)).then((exists) => {
2588
+ if (!exists && !jobs.running(`practice:${course.id}:${row.lecture.id}`)) lecturePractice(course, row);
2589
+ }).catch(() => void 0);
2203
2590
  }
2204
2591
  async function unitSheet({ courseId, unitId, force = false }) {
2205
2592
  const course = await courses.readCourse(courseId);
@@ -2648,6 +3035,7 @@ function createStore({ root }) {
2648
3035
  sheetsDir: (id) => join(paths.courseDir(id), "sheets"),
2649
3036
  board: (id, lessonId) => join(paths.courseDir(id), "boards", `${assertId(lessonId, "les")}.json`),
2650
3037
  practice: (id, lessonId) => join(paths.courseDir(id), "practice", `${assertId(lessonId, "les")}.json`),
3038
+ asides: (id, lessonId) => join(paths.courseDir(id), "asides", `${assertId(lessonId, "les")}.json`),
2651
3039
  sheet: (id, unitId) => join(paths.courseDir(id), "sheets", `${assertId(unitId, "unt")}.json`),
2652
3040
  unitQuiz: (id, unitId) => join(paths.courseDir(id), "quizzes", `${assertId(unitId, "unt")}.json`),
2653
3041
  materials: () => join(root, "materials"),
@@ -3401,12 +3789,14 @@ function createRoutes({ courses, lessons, learner, studio, projects, jobs, setti
3401
3789
  "lesson/ask": (payload) => ({ job: lessons.ask({
3402
3790
  scope: scopeOf(payload),
3403
3791
  stepIndex: payload.stepIndex,
3404
- question: payload.question
3792
+ question: payload.question,
3793
+ anchorStepId: payload.anchorStepId
3405
3794
  }) }),
3406
3795
  "lesson/reexplain": (payload) => ({ job: lessons.reexplain({
3407
3796
  scope: scopeOf(payload),
3408
3797
  stepIndex: payload.stepIndex,
3409
- style: STYLES.includes(payload.style) ? payload.style : "example"
3798
+ style: STYLES.includes(payload.style) ? payload.style : "example",
3799
+ anchorStepId: payload.anchorStepId
3410
3800
  }) }),
3411
3801
  "lesson/record": (payload) => lessons.record({
3412
3802
  courseId: need(payload, "courseId", "crs"),
@@ -4083,6 +4473,7 @@ const PREF_DEFAULTS = Object.freeze({
4083
4473
  voiceEngine: "browser",
4084
4474
  voiceRate: 1,
4085
4475
  boardTheme: "auto",
4476
+ boardFont: "hand",
4086
4477
  ttsProvider: "openai",
4087
4478
  tts: Object.fromEntries(TTS_PROVIDERS.map((provider) => [provider, providerDefaults(provider)]))
4088
4479
  });
@@ -4112,6 +4503,7 @@ function cleanPrefs(input = {}, base = PREF_DEFAULTS) {
4112
4503
  "light",
4113
4504
  "dark"
4114
4505
  ].includes(input.boardTheme)) next.boardTheme = input.boardTheme;
4506
+ if (["hand", "standard"].includes(input.boardFont)) next.boardFont = input.boardFont;
4115
4507
  if (TTS_PROVIDERS.includes(input.ttsProvider)) next.ttsProvider = input.ttsProvider;
4116
4508
  for (const provider of TTS_PROVIDERS) {
4117
4509
  const patch = input.tts?.[provider];
@@ -4221,6 +4613,8 @@ const ASSIST_MODES = [
4221
4613
  "solve",
4222
4614
  "visualize"
4223
4615
  ];
4616
+ const DIGEST_SINGLE_CHARS = 24e3;
4617
+ const DIGEST_NOTES_CHARS = 48e3;
4224
4618
  function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date(), uiLanguage = () => "zh-CN" }) {
4225
4619
  const stamp = () => now().toISOString();
4226
4620
  async function saveMaterial(result, { bytes, signal, extra = {} }) {
@@ -4246,7 +4640,7 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
4246
4640
  purpose: "quick",
4247
4641
  prompt: materialBriefPrompt({
4248
4642
  title: meta.title,
4249
- passages: result.chunks.slice(0, 8).map((chunk) => chunk.text).join("\n\n").slice(0, 9e3),
4643
+ passages: formatPassages(spreadPassages(result.chunks, { maxChars: 12e3 }), ""),
4250
4644
  language: detectLanguage(result.chunks[0].text, uiLanguage())
4251
4645
  }),
4252
4646
  maxTokens: 1500,
@@ -4328,36 +4722,77 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
4328
4722
  return jobs.start("material/digest", async (api) => {
4329
4723
  const [material] = await readMaterials(store, [assertId(id, "mat")]);
4330
4724
  if (!material?.chunks.length) throw new TutorError("invalid", "This material has no text to digest");
4725
+ const title = material.meta.title;
4331
4726
  const language = detectLanguage(material.chunks[0].text, uiLanguage());
4727
+ const size = material.chunks.reduce((sum, chunk) => sum + chunk.text.length, 0);
4728
+ let prompt;
4729
+ let missing = [];
4730
+ if (size <= DIGEST_SINGLE_CHARS) {
4731
+ api.progress(0, 1, "writing");
4732
+ prompt = digestPrompt({
4733
+ title,
4734
+ passages: formatPassages(material.chunks, ""),
4735
+ language
4736
+ });
4737
+ } else {
4738
+ const parts = documentParts(material.chunks);
4739
+ const notes = new Array(parts.length).fill(null);
4740
+ const readPart = async (index) => {
4741
+ try {
4742
+ notes[index] = await generateJson(llm, {
4743
+ purpose: "teach",
4744
+ prompt: digestPartPrompt({
4745
+ title,
4746
+ part: index + 1,
4747
+ parts: parts.length,
4748
+ range: passageRange(parts[index]),
4749
+ passages: formatPassages(parts[index], ""),
4750
+ language
4751
+ }),
4752
+ maxTokens: 6e3,
4753
+ signal: api.signal,
4754
+ normalize: normalizeDigestPart
4755
+ });
4756
+ } catch (error) {
4757
+ if (api.signal.aborted) throw error;
4758
+ }
4759
+ };
4760
+ const queue = parts.map((part, index) => index);
4761
+ let done = 0;
4762
+ api.progress(0, parts.length + 1, "reading");
4763
+ const worker = async () => {
4764
+ while (queue.length) {
4765
+ api.signal.throwIfAborted();
4766
+ await readPart(queue.shift());
4767
+ done += 1;
4768
+ api.progress(done, parts.length + 1, "reading");
4769
+ }
4770
+ };
4771
+ await Promise.all([worker(), worker()]);
4772
+ for (const [index, note] of notes.entries()) if (!note) await readPart(index);
4773
+ const read = notes.map((note, index) => note ? {
4774
+ part: index + 1,
4775
+ of: parts.length,
4776
+ range: passageRange(parts[index]),
4777
+ ...note
4778
+ } : null).filter(Boolean);
4779
+ 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.");
4780
+ missing = parts.map((part, index) => notes[index] ? null : passageRange(part) || `${index + 1}/${parts.length}`).filter(Boolean);
4781
+ api.progress(parts.length, parts.length + 1, "writing");
4782
+ prompt = digestPrompt({
4783
+ title,
4784
+ notes: digestNotesText(read, DIGEST_NOTES_CHARS),
4785
+ language
4786
+ });
4787
+ }
4332
4788
  const result = await generateJson(llm, {
4333
4789
  purpose: "teach",
4334
- prompt: digestPrompt({
4335
- title: material.meta.title,
4336
- passages: passagesFor([material], "", 24e3),
4337
- language
4338
- }),
4790
+ prompt,
4339
4791
  maxTokens: 9e3,
4340
4792
  signal: api.signal,
4341
- normalize: (raw) => ({
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
- })
4793
+ normalize: normalizeDigest
4360
4794
  });
4795
+ if (missing.length) result.missing = missing;
4361
4796
  return { material: await store.updateJson(store.paths.material(id), null, (value) => ({
4362
4797
  ...value,
4363
4798
  digest: {
@@ -4618,21 +5053,24 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
4618
5053
  board,
4619
5054
  at: stamp()
4620
5055
  };
4621
- if (!thread) thread = {
4622
- id: /^thd_[a-z0-9]{6,40}$/u.test(String(newThreadId)) ? newThreadId : newId("thd"),
4623
- title: board.title || ask.slice(0, 60),
4624
- language,
4625
- materialIds: ids,
4626
- turns: [],
4627
- createdAt: stamp()
4628
- };
4629
- thread.turns = [...thread.turns, turn].slice(-30);
4630
- thread.materialIds = ids;
4631
- thread.updatedAt = stamp();
4632
- await store.writeJson(store.paths.item("assist", thread.id), thread);
5056
+ const id = thread?.id ?? (/^thd_[a-z0-9]{6,40}$/u.test(String(newThreadId)) ? newThreadId : newId("thd"));
5057
+ const saved = await store.updateJson(store.paths.item("assist", id), null, (current) => {
5058
+ const next = current ?? {
5059
+ id,
5060
+ title: board.title || ask.slice(0, 60),
5061
+ language,
5062
+ materialIds: [],
5063
+ turns: [],
5064
+ createdAt: stamp()
5065
+ };
5066
+ next.turns = [...next.turns ?? [], turn].slice(-30);
5067
+ next.materialIds = [.../* @__PURE__ */ new Set([...next.materialIds ?? [], ...ids])].slice(0, 8);
5068
+ next.updatedAt = stamp();
5069
+ return next;
5070
+ });
4633
5071
  return {
4634
- threadId: thread.id,
4635
- turn: thread.turns.length - 1,
5072
+ threadId: saved.id,
5073
+ turn: saved.turns.length - 1,
4636
5074
  board
4637
5075
  };
4638
5076
  }, { meta: { threadId: threadId ?? null } });
@@ -4702,6 +5140,60 @@ function createStudio({ store, llm, jobs, now = () => /* @__PURE__ */ new Date()
4702
5140
  makeShort
4703
5141
  });
4704
5142
  }
5143
+ function normalizeDigest(raw) {
5144
+ return {
5145
+ overview: text(raw?.overview, 2e3),
5146
+ structure: (Array.isArray(raw?.structure) ? raw.structure : []).slice(0, 30).map((item) => ({
5147
+ heading: text(item?.heading, 160),
5148
+ points: (item?.points ?? []).map((point) => text(point, 400)).filter(Boolean).slice(0, 10),
5149
+ pages: text(item?.pages, 30)
5150
+ })).filter((item) => item.heading),
5151
+ keyIdeas: (raw?.keyIdeas ?? []).map((item) => text(item, 400)).filter(Boolean).slice(0, 15),
5152
+ arguments: (raw?.arguments ?? []).slice(0, 15).map((item) => ({
5153
+ claim: text(item?.claim, 400),
5154
+ support: text(item?.support, 600),
5155
+ page: text(item?.page, 20)
5156
+ })).filter((item) => item.claim),
5157
+ glossary: (raw?.glossary ?? []).slice(0, 30).map((item) => ({
5158
+ term: text(item?.term, 80),
5159
+ meaning: text(item?.meaning, 400)
5160
+ })).filter((item) => item.term),
5161
+ questions: (raw?.questions ?? []).map((item) => text(item, 300)).filter(Boolean).slice(0, 8)
5162
+ };
5163
+ }
5164
+ function normalizeDigestPart(raw) {
5165
+ const value = {
5166
+ sections: (Array.isArray(raw?.sections) ? raw.sections : []).slice(0, 12).map((item) => ({
5167
+ heading: text(item?.heading, 160),
5168
+ pages: text(item?.pages, 30),
5169
+ points: (Array.isArray(item?.points) ? item.points : []).map((point) => text(point, 300)).filter(Boolean).slice(0, 6)
5170
+ })).filter((item) => item.heading),
5171
+ keyIdeas: (Array.isArray(raw?.keyIdeas) ? raw.keyIdeas : []).map((item) => text(item, 300)).filter(Boolean).slice(0, 8),
5172
+ arguments: (Array.isArray(raw?.arguments) ? raw.arguments : []).slice(0, 8).map((item) => ({
5173
+ claim: text(item?.claim, 300),
5174
+ support: text(item?.support, 400),
5175
+ page: text(item?.page, 20)
5176
+ })).filter((item) => item.claim),
5177
+ glossary: (Array.isArray(raw?.glossary) ? raw.glossary : []).slice(0, 12).map((item) => ({
5178
+ term: text(item?.term, 80),
5179
+ meaning: text(item?.meaning, 300)
5180
+ })).filter((item) => item.term)
5181
+ };
5182
+ if (!value.sections.length && !value.keyIdeas.length) throw new Error("no notes for this part");
5183
+ return value;
5184
+ }
5185
+ function digestNotesText(notes, maxChars) {
5186
+ const share = Math.max(600, Math.floor(maxChars / Math.max(1, notes.length)));
5187
+ return notes.map((note) => {
5188
+ const lines = [`[Part ${note.part}/${note.of}${note.range ? ` · ${note.range}` : ""}]`];
5189
+ for (const section of note.sections) lines.push(`- ${section.heading}${section.pages ? ` (p.${section.pages})` : ""}: ${section.points.join("; ")}`);
5190
+ if (note.keyIdeas.length) lines.push(`Key ideas: ${note.keyIdeas.join("; ")}`);
5191
+ for (const argument of note.arguments) lines.push(`Claim: ${argument.claim}${argument.page ? ` (p.${argument.page})` : ""} — ${argument.support}`);
5192
+ if (note.glossary.length) lines.push(`Terms: ${note.glossary.map((entry) => `${entry.term}: ${entry.meaning}`).join("; ")}`);
5193
+ const block = lines.join("\n");
5194
+ return block.length > share ? `${block.slice(0, share)}…` : block;
5195
+ }).join("\n\n");
5196
+ }
4705
5197
  //#endregion
4706
5198
  //#region src/index.js
4707
5199
  const name = "aha-tutor";
@@ -4822,6 +5314,7 @@ function apply(ctx) {
4822
5314
  if (typeof fetchRoutes?.register !== "function") return;
4823
5315
  connectionCtx.effect(() => fetchRoutes.register(uploadRoute({ studio })), "aha-tutor: upload route");
4824
5316
  connectionCtx.effect(() => fetchRoutes.register(ttsRoute({ speak })), "aha-tutor: tts route");
5317
+ connectionCtx.effect(() => fetchRoutes.register(fontRoute()), "aha-tutor: font route");
4825
5318
  });
4826
5319
  ctx.effect(() => publishRuntime({
4827
5320
  store,