jackherd 1.8.0 → 1.9.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/INSTALL.md +2 -0
  3. package/README.md +41 -60
  4. package/assets/branding/README.md +5 -7
  5. package/assets/branding/jackherd-logo-outline.svg +1 -0
  6. package/assets/branding/outline.test.ts +30 -0
  7. package/assets/icons/bark.svg +1 -1
  8. package/assets/icons/bowl.svg +1 -1
  9. package/assets/icons/decide.svg +1 -1
  10. package/assets/icons/ear.svg +1 -1
  11. package/assets/icons/lanes.svg +1 -1
  12. package/assets/icons/plan.svg +1 -1
  13. package/dist/{chunk-M6DDZEW4.js → chunk-MCP4XJQH.js} +17 -0
  14. package/dist/config.d.ts +6 -0
  15. package/dist/config.js +19 -3
  16. package/dist/plan-format.d.ts +22 -3
  17. package/dist/plan-format.js +21 -7
  18. package/herdr-plugin/herdr-plugin.toml +1 -1
  19. package/install.sh +1 -1
  20. package/kit/hooks/hooks/approval-gate/index.ts +22 -4
  21. package/kit/hooks/hooks/approval-gate/run.ts +29 -6
  22. package/kit/hooks/hooks/approval-gate/subagent.ts +18 -0
  23. package/kit/hooks/hooks/merge-guard/decision.ts +70 -21
  24. package/kit/hooks/hooks/merge-guard/xargs-program.ts +182 -0
  25. package/kit/hooks/hooks/sent-file/index.ts +19 -0
  26. package/kit/hooks/hooks/sent-file/record.ts +128 -0
  27. package/kit/hooks/hooks/sent-file/run.ts +48 -0
  28. package/kit/hooks/hooks/sent-file/store.ts +18 -0
  29. package/kit/hooks/hooks/shared/board-lanes.ts +15 -2
  30. package/kit/hooks/hooks.json +9 -0
  31. package/kit/hooks/statusline.sh +1 -1
  32. package/kit/workflow/skills/implement/SKILL.md +2 -0
  33. package/kit/workflow/skills/orchestrate/SKILL.md +31 -6
  34. package/package.json +3 -1
  35. package/schemas/jackherd.schema.json +26 -2
  36. package/src/cli.ts +3 -0
  37. package/src/config/read-config.ts +5 -1
  38. package/src/config/schema.ts +22 -2
  39. package/src/context/fill.ts +12 -0
  40. package/src/context/session-log.ts +43 -1
  41. package/src/plan-format/clock.ts +4 -0
  42. package/src/plan-format/dependencies.ts +2 -5
  43. package/src/plan-format/lanes.ts +30 -5
  44. package/src/plan-format/terminal-text.ts +4 -0
  45. package/src/plan-format/waiting.ts +48 -0
  46. package/src/plans/active-tasks.ts +60 -0
  47. package/src/plans/current-phase.ts +17 -7
  48. package/src/plans/current-task.ts +63 -5
  49. package/src/plans/lane-standing.ts +12 -6
  50. package/src/plans/lane-summary.ts +141 -74
  51. package/src/plans/lane-tickets.ts +15 -0
  52. package/src/plans/layout-phase.ts +57 -18
  53. package/src/plans/layout-summary.ts +85 -67
  54. package/src/plans/layout.ts +253 -89
  55. package/src/plans/live.ts +22 -0
  56. package/src/plans/phase-models.ts +1 -1
  57. package/src/plans/phase-ranges.ts +45 -0
  58. package/src/plans/pull-requests.ts +6 -0
  59. package/src/plans/selection.ts +19 -16
  60. package/src/plans/sent-files-read.ts +22 -0
  61. package/src/plans/sent-files.ts +121 -0
  62. package/src/plans/signals-read.ts +54 -0
  63. package/src/plans/snapshot.ts +251 -55
  64. package/src/plans/subagents-read.ts +82 -0
  65. package/src/plans/subagents.ts +132 -0
  66. package/src/plans/texts.ts +16 -11
  67. package/src/plans/unlisted-lanes.ts +10 -5
  68. package/src/plans/view.ts +3 -3
  69. package/src/plans/waiting-click.ts +76 -0
  70. package/src/preview/command.ts +83 -0
  71. package/src/preview/embed.ts +209 -0
  72. package/src/preview/images.ts +89 -0
  73. package/src/preview/open.ts +12 -0
  74. package/src/preview/options.ts +32 -0
  75. package/src/preview/page.ts +89 -0
  76. package/src/preview/render.ts +41 -0
  77. package/src/settled/board-row.ts +1 -2
  78. package/src/shared/is-record.ts +2 -0
  79. package/src/shared/private-records.ts +48 -0
  80. package/src/task-signals/agent.ts +15 -0
  81. package/src/task-signals/claude-read.ts +72 -0
  82. package/src/task-signals/claude-signals.ts +112 -0
  83. package/src/task-signals/command.ts +71 -0
  84. package/src/task-signals/fixtures/session.jsonl +7 -0
  85. package/src/task-signals/matcher.ts +96 -0
  86. package/src/task-signals/record-store.ts +40 -0
  87. package/src/task-signals/record.ts +68 -0
  88. package/src/task-signals/text.ts +13 -0
  89. package/src/task-signals/types.ts +14 -0
  90. package/src/terminal/open.ts +13 -6
  91. package/src/terminal/text.ts +8 -1
  92. package/src/terminal/width.ts +2 -1
  93. package/src/update/command.ts +2 -0
  94. package/src/update/config-shares.ts +30 -0
  95. package/src/update/update.ts +12 -1
  96. package/src/vocabulary/index.ts +33 -1
  97. package/src/waiting/command.ts +35 -0
  98. package/src/watch/appointments.ts +5 -5
  99. package/src/watch/approvals.ts +2 -2
  100. package/src/watch/command.ts +91 -5
  101. package/src/watch/failed-tests.ts +56 -10
  102. package/src/watch/failure-read.ts +18 -6
  103. package/src/watch/failures.ts +29 -5
  104. package/src/watch/feedback.ts +1 -1
  105. package/src/watch/gh-process.ts +9 -3
  106. package/src/watch/json-guards.ts +0 -3
  107. package/src/watch/lane-fill.ts +1 -1
  108. package/src/watch/lane-model.ts +1 -1
  109. package/src/watch/lane-parallel.ts +1 -1
  110. package/src/watch/lane-progress.ts +19 -7
  111. package/src/watch/lane-report.ts +5 -1
  112. package/src/watch/lane-rest.ts +28 -0
  113. package/src/watch/plan-badges.ts +9 -2
  114. package/src/watch/previews.ts +1 -1
  115. package/src/watch/pull-requests.ts +2 -1
  116. package/src/watch/source-path.ts +1 -1
  117. package/src/watch/sources.ts +1 -1
  118. package/src/watch/stream-output.ts +12 -7
  119. package/src/watch/task-parallel-input.ts +118 -0
  120. package/src/watch/task-parallel-read.ts +149 -0
  121. package/src/watch/task-parallel-touched.ts +39 -0
  122. package/src/watch/task-parallel.ts +206 -0
  123. package/src/watch/waiting-line.ts +19 -0
  124. package/src/watch/watch-events.ts +13 -1
  125. package/src/watch/workflow-runs.ts +2 -1
  126. package/assets/icons/bark-dark.svg +0 -1
  127. package/assets/icons/bowl-dark.svg +0 -1
  128. package/assets/icons/decide-dark.svg +0 -1
  129. package/assets/icons/ear-dark.svg +0 -1
  130. package/assets/icons/lanes-dark.svg +0 -1
  131. package/assets/icons/plan-dark.svg +0 -1
@@ -0,0 +1,149 @@
1
+ import { existsSync, readdirSync, statSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { firstAnswerTokens } from '../context/fill'
4
+ import { agentLogPath, readHeadLines, readTailLines, TAIL_BYTES } from '../context/session-log'
5
+ import type { SprintLane } from '../plan-format'
6
+ import { MS_PER_MINUTE } from '../plan-format/clock'
7
+ import { STALE_ACTIVITY_MINUTES } from '../plans/lane-summary'
8
+ import { type PlansSettings, worktreeOf } from '../plans/settings'
9
+ import { readClaudeSignals } from '../task-signals/claude-read'
10
+ import { recordSignals } from '../task-signals/record'
11
+ import { readTaskRecords } from '../task-signals/record-store'
12
+ import type { TaskSignal } from '../task-signals/types'
13
+ import { AGENT_STATUS, type LaneAgent } from '../terminal/types'
14
+ import { watchedLanePlanText } from './lane-progress'
15
+ import type { TaskParallelInput } from './task-parallel'
16
+ import { planTaskViewOf, taskParallelInputOf } from './task-parallel-input'
17
+ import { isWithinWorktree, touchedFilesOf } from './task-parallel-touched'
18
+
19
+ const RECENT_WRITE_MS = 30 * 60_000
20
+ const HEAD_BYTES = 256 * 1024
21
+ const SUBAGENT_LOG = /^agent-[A-Za-z0-9]+\.jsonl$/
22
+ /** How many subagent logs of one session have their writes read, the newest first. */
23
+ const MAX_SUBAGENT_LOGS = 20
24
+
25
+ /** One agent's session: its log, the signals in it and its subagents, and the tails of the logs the writes are read from. */
26
+ type AgentRead = { agent: LaneAgent; logPath: string | null; signals: TaskSignal[]; tails: string[][] }
27
+
28
+ const modifiedAt = (path: string): number => {
29
+ try {
30
+ return statSync(path).mtimeMs
31
+ } catch {
32
+ return 0
33
+ }
34
+ }
35
+
36
+ /** The newest `MAX_SUBAGENT_LOGS` subagent logs of a session, by modification time, so a long session bounds the read. */
37
+ const subagentLogPaths = (logPath: string): string[] => {
38
+ const directory = join(logPath.replace(/\.jsonl$/, ''), 'subagents')
39
+ try {
40
+ return existsSync(directory)
41
+ ? readdirSync(directory)
42
+ .filter((name) => SUBAGENT_LOG.test(name))
43
+ .map((name) => ({ path: join(directory, name), modified: modifiedAt(join(directory, name)) }))
44
+ .sort((left, right) => right.modified - left.modified)
45
+ .slice(0, MAX_SUBAGENT_LOGS)
46
+ .map(({ path }) => path)
47
+ : []
48
+ } catch {
49
+ return []
50
+ }
51
+ }
52
+
53
+ const tailOf = (path: string): string[] => {
54
+ try {
55
+ return readTailLines(path, TAIL_BYTES)
56
+ } catch {
57
+ return []
58
+ }
59
+ }
60
+
61
+ const readAgent = (agent: LaneAgent, projectsDirectory: string | undefined, now: number): AgentRead => {
62
+ const logPath = agentLogPath(agent, projectsDirectory)
63
+ const notOlderThan = now - STALE_ACTIVITY_MINUTES * MS_PER_MINUTE
64
+ return {
65
+ agent,
66
+ logPath,
67
+ signals: logPath ? readClaudeSignals(logPath, { notOlderThan }) : [],
68
+ tails: logPath ? [logPath, ...subagentLogPaths(logPath)].map(tailOf) : [],
69
+ }
70
+ }
71
+
72
+ const baselineCache = new Map<string, number | null>()
73
+
74
+ /**
75
+ * What a fresh agent carries before it has worked, measured as `jh context` measures a fill: the input of the first
76
+ * answer in a session log (system prompt, project instructions and the first request). The smallest honest source on
77
+ * hand: a log of a started session, not a guess; cached per log, since the head of a log never changes.
78
+ */
79
+ const baselineOf = (logPath: string): number | null => {
80
+ if (!baselineCache.has(logPath)) {
81
+ try {
82
+ baselineCache.set(logPath, firstAnswerTokens(readHeadLines(logPath, HEAD_BYTES)))
83
+ } catch {
84
+ baselineCache.set(logPath, null)
85
+ }
86
+ }
87
+ return baselineCache.get(logPath) ?? null
88
+ }
89
+
90
+ const baselineFor = (lane: string, reads: readonly AgentRead[]): number | null => {
91
+ const own = reads.find(({ agent }) => agent.name === lane)
92
+ const sources = [own, ...reads.filter((read) => read !== own)]
93
+ for (const read of sources) {
94
+ const tokens = read?.logPath ? baselineOf(read.logPath) : null
95
+ if (tokens !== null) return tokens
96
+ }
97
+ return null
98
+ }
99
+
100
+ const uniqueSignals = (signals: readonly TaskSignal[]): TaskSignal[] => [
101
+ ...new Map(signals.map((signal) => [`${signal.agent}|${signal.text}`, signal])).values(),
102
+ ]
103
+
104
+ export type TaskParallelSources = {
105
+ root: string
106
+ settings: PlansSettings
107
+ boardFile: string
108
+ thresholdTokens: number
109
+ now: number
110
+ /** Where Claude Code keeps its session logs; the user's by default. */
111
+ projectsDirectory?: string
112
+ }
113
+
114
+ /**
115
+ * The input of the parallel-task check for each of `lanes`, read from the plan of the lane's newest row, the sessions
116
+ * of every listed agent (a lane's work, and the coordinator's subagents in the lane's worktree) and the records of
117
+ * `jh task`. A lane without a plan, without a token baseline, without a task left or without active work (a working
118
+ * agent, a running subagent or an open record in its worktree) is not in the answer.
119
+ */
120
+ export const readTaskParallelInputs = (
121
+ lanes: readonly SprintLane[],
122
+ agents: readonly LaneAgent[],
123
+ sources: TaskParallelSources,
124
+ ): Record<string, TaskParallelInput> => {
125
+ const reads = agents.map((agent) => readAgent(agent, sources.projectsDirectory, sources.now))
126
+ const records = recordSignals(readTaskRecords(sources.root))
127
+ const since = sources.now - RECENT_WRITE_MS
128
+ return Object.fromEntries(
129
+ lanes.flatMap((lane) => {
130
+ const text = watchedLanePlanText(sources.root, sources.settings, sources.boardFile, lane)
131
+ const baselineTokens = baselineFor(lane.name, reads)
132
+ if (text === null || baselineTokens === null) return []
133
+ const worktree = worktreeOf(sources.root, sources.settings, lane.name)
134
+ const signals = uniqueSignals([...reads.flatMap((read) => read.signals), ...records]).filter((signal) =>
135
+ isWithinWorktree(signal.cwd, worktree),
136
+ )
137
+ const input = taskParallelInputOf({
138
+ lane: lane.name,
139
+ plan: planTaskViewOf(text, sources.settings.planLanguage),
140
+ signals,
141
+ touchedFiles: reads.flatMap((read) => read.tails.flatMap((tail) => touchedFilesOf(tail, worktree, since))),
142
+ laneWorking: agents.some((agent) => agent.name === lane.name && agent.status === AGENT_STATUS.working),
143
+ baselineTokens,
144
+ thresholdTokens: sources.thresholdTokens,
145
+ })
146
+ return input.open.length === 0 || input.active.length === 0 ? [] : [[lane.name, input]]
147
+ }),
148
+ )
149
+ }
@@ -0,0 +1,39 @@
1
+ import { isAbsolute, relative } from 'node:path'
2
+ import { parseLogEntry } from '../context/session-log'
3
+ import { isRecord } from '../shared/is-record'
4
+
5
+ const WRITING_TOOLS: ReadonlySet<string> = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit'])
6
+
7
+ const writtenPathsOf = (entry: Record<string, unknown>): string[] => {
8
+ const content = isRecord(entry.message) && Array.isArray(entry.message.content) ? entry.message.content : []
9
+ return content.flatMap((block) => {
10
+ if (!isRecord(block) || block.type !== 'tool_use' || !WRITING_TOOLS.has(String(block.name))) return []
11
+ const input = isRecord(block.input) ? block.input : {}
12
+ const path = input.file_path ?? input.notebook_path
13
+ return typeof path === 'string' ? [path] : []
14
+ })
15
+ }
16
+
17
+ const insideWorktree = (path: string, worktree: string): string | null => {
18
+ const inside = relative(worktree, path)
19
+ return inside === '' || inside.startsWith('..') || isAbsolute(inside) ? null : inside
20
+ }
21
+
22
+ /** Whether `path` is the worktree or lies below it. */
23
+ export const isWithinWorktree = (path: string, worktree: string): boolean =>
24
+ insideWorktree(path, worktree) !== null || path === worktree
25
+
26
+ /**
27
+ * The files the log lines show written (`Edit`, `Write`, `MultiEdit`, `NotebookEdit`) at or after `sinceMs` inside
28
+ * `worktree`, relative to it and without repeats, in order of first write. A path outside the worktree, a line that is
29
+ * no JSON and a write without a time are left out.
30
+ */
31
+ export const touchedFilesOf = (lines: readonly string[], worktree: string, sinceMs: number): string[] => {
32
+ const touched = lines.flatMap((line) => {
33
+ const entry = parseLogEntry(line)
34
+ const time = typeof entry?.timestamp === 'string' ? Date.parse(entry.timestamp) : Number.NaN
35
+ if (!entry || Number.isNaN(time) || time < sinceMs) return []
36
+ return writtenPathsOf(entry).flatMap((path) => insideWorktree(path, worktree) ?? [])
37
+ })
38
+ return [...new Set(touched)]
39
+ }
@@ -0,0 +1,206 @@
1
+ import { ellipsize, terminalSafe } from '../plan-format/terminal-text'
2
+
3
+ export const TASK_PARALLEL_EVENT = 'parallel tasks'
4
+
5
+ /** A proposal for the non-stream watcher: the line `formatTaskParallelLine` made for `lane`. */
6
+ export type TaskParallelEvent = { kind: typeof TASK_PARALLEL_EVENT; lane: string; line: string }
7
+
8
+ /** Lane → the fingerprint last seen at a heartbeat; a lane without an entry has had none. */
9
+ export type TaskParallelFingerprints = Record<string, string>
10
+
11
+ export const isTaskParallelFingerprints = (value: unknown): value is TaskParallelFingerprints =>
12
+ typeof value === 'object' &&
13
+ value !== null &&
14
+ !Array.isArray(value) &&
15
+ Object.values(value).every((entry) => typeof entry === 'string')
16
+
17
+ export type OpenTask = { text: string; phase: string }
18
+
19
+ /** One agent's recent work: the files it touched, its active task text and phase when the signal names them. */
20
+ export type ActiveWork = { name: string; files: string[]; taskText?: string; phase?: string }
21
+
22
+ export type TaskParallelInput = {
23
+ lane: string
24
+ open: OpenTask[]
25
+ active: ActiveWork[]
26
+ /** Phase id → the paths of its writes cell; `''` is the whole repository. Absent for a phase without one. */
27
+ phaseWrites: Record<string, string[]>
28
+ doneCount: number
29
+ /** Tokens a fresh agent costs before it does anything, measured by the caller. */
30
+ baselineTokens: number
31
+ /** A proposal is made only when the estimate stays below this. */
32
+ thresholdTokens: number
33
+ }
34
+
35
+ export type TaskParallelResult =
36
+ | { proposed: false; reason: string }
37
+ | {
38
+ proposed: true
39
+ tasks: OpenTask[]
40
+ waiting: number
41
+ extraAgents: number
42
+ estimateTokens: number
43
+ reason: string
44
+ }
45
+
46
+ export type TaskParallelProposal = Extract<TaskParallelResult, { proposed: true }>
47
+
48
+ const MIN_TASKS_BESIDE_AGENT = 1
49
+ const MIN_TASKS_WITHOUT_AGENT = 2
50
+ const TEXT_LIMIT = 60
51
+ const TOKENS_PER_K = 1000
52
+ const GLOB_CHARACTER = /[*?[{]/
53
+ const LINE_SUFFIX = /(?::\d+(?:[-:]\d+)*|#L\d+.*)$/
54
+ const PATH_EXTENSIONS = 'ts|tsx|js|mjs|json|md|sh|yml|yaml|css|html|toml|sql'
55
+ const BARE_FILE = new RegExp(`(?<![\\w./\`-])[\\w./-]+\\.(?:${PATH_EXTENSIONS})(?::\\d+(?:[-:]\\d+)*)?(?![\\w/])`, 'g')
56
+ const BACKTICKED = /`([^`]+)`/g
57
+ const FILE_LIKE = new RegExp(`/|\\.(?:${PATH_EXTENSIONS})$|^\\.[\\w-]+`)
58
+
59
+ const normalise = (entry: string): string | null => {
60
+ const trimmed = entry.trim()
61
+ if (trimmed === '' || /\s/.test(trimmed)) return null
62
+ const path = trimmed.replace(LINE_SUFFIX, '').replace(/^\.\//, '').replace(/\/+$/, '')
63
+ return FILE_LIKE.test(path) && path !== '' ? path : null
64
+ }
65
+
66
+ /**
67
+ * The paths a task line names: backticked entries that look like a path or file name and bare file names with a known
68
+ * extension. `:line` suffixes and `./` are cut, globs stay globs, duplicates drop. A task naming none is unknown, and
69
+ * unknown is never proposed.
70
+ */
71
+ export const pathsOfTask = (text: string): string[] => {
72
+ const backticked = [...text.matchAll(BACKTICKED)].map((match) => match[1] ?? '')
73
+ const bare = text.replace(BACKTICKED, ' ').match(BARE_FILE) ?? []
74
+ return [...new Set([...backticked, ...bare].map(normalise).filter((path): path is string => path !== null))]
75
+ }
76
+
77
+ const literalPrefix = (path: string): string => {
78
+ const glob = path.search(GLOB_CHARACTER)
79
+ return glob === -1 ? path : path.slice(0, Math.max(path.lastIndexOf('/', glob), 0))
80
+ }
81
+
82
+ const isInside = (inner: string, outer: string): boolean =>
83
+ outer === '' || inner === outer || inner.startsWith(`${outer}/`)
84
+
85
+ const holdsName = (name: string, path: string): boolean => `/${path}/`.includes(`/${name}/`) || path === name
86
+
87
+ /**
88
+ * Whether two paths may touch the same files. Directories contain what lies below them, a glob stands for the
89
+ * directory its literal part ends in, `''` is the whole repository, and a bare name matches that name in any directory.
90
+ * When unsure the answer is yes.
91
+ */
92
+ export const pathsOverlap = (left: string, right: string): boolean => {
93
+ const [a, b] = [literalPrefix(left), literalPrefix(right)]
94
+ const bareLeft = !left.includes('/') && !GLOB_CHARACTER.test(left) && left !== ''
95
+ const bareRight = !right.includes('/') && !GLOB_CHARACTER.test(right) && right !== ''
96
+ if (bareLeft || bareRight) {
97
+ const [name, other] = bareLeft ? [left, right] : [right, left]
98
+ return GLOB_CHARACTER.test(other) ? true : other === '' || holdsName(name, other)
99
+ }
100
+ return isInside(a, b) || isInside(b, a)
101
+ }
102
+
103
+ const clash = (left: readonly string[], right: readonly string[]): boolean =>
104
+ left.some((a) => right.some((b) => pathsOverlap(a, b)))
105
+
106
+ const activeFootprint = (input: TaskParallelInput): string[] =>
107
+ input.active.flatMap((work) => [
108
+ ...work.files,
109
+ ...pathsOfTask(work.taskText ?? ''),
110
+ ...(work.phase === undefined ? [] : (input.phaseWrites[work.phase] ?? [])),
111
+ ])
112
+
113
+ const estimateTokens = (input: TaskParallelInput, taskCount: number): { extraAgents: number; tokens: number } => {
114
+ const extraAgents = input.active.length > 0 ? taskCount : taskCount - 1
115
+ return { extraAgents, tokens: input.baselineTokens * extraAgents }
116
+ }
117
+
118
+ const kilo = (tokens: number): string => `${Math.round(tokens / TOKENS_PER_K)}k`
119
+
120
+ /** The first group of open tasks, in plan order, whose paths clash neither with the running work nor with each other. */
121
+ const parallelGroup = (input: TaskParallelInput): OpenTask[] => {
122
+ const running = activeFootprint(input)
123
+ const chosen: { task: OpenTask; paths: string[] }[] = []
124
+ for (const task of input.open) {
125
+ const paths = pathsOfTask(task.text)
126
+ const free = paths.length > 0 && !clash(paths, running) && chosen.every((other) => !clash(paths, other.paths))
127
+ if (free) chosen.push({ task, paths })
128
+ }
129
+ return chosen.map(({ task }) => task)
130
+ }
131
+
132
+ /**
133
+ * Open tasks that could start now beside the running work: no path overlap with it or with each other, none without a
134
+ * named path. Proposed for one task beside running work or two tasks without, and when the baseline cost of the extra agents stays below the
135
+ * threshold; the reason says in plain words which way it went.
136
+ */
137
+ export const proposeTaskParallel = (input: TaskParallelInput): TaskParallelResult => {
138
+ const tasks = parallelGroup(input)
139
+ const needed = input.active.length > 0 ? MIN_TASKS_BESIDE_AGENT : MIN_TASKS_WITHOUT_AGENT
140
+ if (tasks.length < needed) return { proposed: false, reason: 'no task can run beside another' }
141
+ const { extraAgents, tokens } = estimateTokens(input, tasks.length)
142
+ if (tokens >= input.thresholdTokens)
143
+ return {
144
+ proposed: false,
145
+ reason: `~${kilo(tokens)} tokens for ${extraAgents} extra agents is not below the ${kilo(input.thresholdTokens)} limit`,
146
+ }
147
+ return {
148
+ proposed: true,
149
+ tasks,
150
+ waiting: input.open.length,
151
+ extraAgents,
152
+ estimateTokens: tokens,
153
+ reason: `${tasks.length} of ${input.open.length} waiting tasks name disjoint paths that the running work does not touch; ~${kilo(tokens)} tokens for ${extraAgents} extra ${extraAgents === 1 ? 'agent' : 'agents'}`,
154
+ }
155
+ }
156
+
157
+ const FNV_OFFSET = 0x811c9dc5
158
+ const FNV_PRIME = 0x01000193
159
+
160
+ const hash = (text: string): string => {
161
+ let value = FNV_OFFSET
162
+ for (const character of text) {
163
+ value = Math.imul(value ^ (character.codePointAt(0) ?? 0), FNV_PRIME) >>> 0
164
+ }
165
+ return value.toString(16).padStart(8, '0')
166
+ }
167
+
168
+ /**
169
+ * A stable fingerprint of what decides a proposal: ticks, active tasks and open tasks, order-independent. Files an
170
+ * agent touches are left out, they move on every keystroke and would repeat the report.
171
+ */
172
+ export const taskParallelFingerprint = (input: TaskParallelInput): string =>
173
+ hash(
174
+ JSON.stringify([
175
+ input.lane,
176
+ input.doneCount,
177
+ input.active.map((work) => `${work.phase ?? ''}|${work.taskText ?? ''}`).sort(),
178
+ input.open.map((task) => `${task.phase}|${task.text}`).sort(),
179
+ ]),
180
+ )
181
+
182
+ /**
183
+ * The proposal to report this heartbeat, if any: only when the fingerprint moved since `previous`, and only a real
184
+ * proposal. The returned fingerprint is what the caller keeps for the next heartbeat, proposal or not.
185
+ */
186
+ export const taskParallelReport = (
187
+ previous: string | undefined,
188
+ input: TaskParallelInput,
189
+ ): { fingerprint: string; proposal: TaskParallelProposal | null } => {
190
+ const fingerprint = taskParallelFingerprint(input)
191
+ if (fingerprint === previous) return { fingerprint, proposal: null }
192
+ const result = proposeTaskParallel(input)
193
+ return { fingerprint, proposal: result.proposed ? result : null }
194
+ }
195
+
196
+ const CHECKBOX = /^\s*(?:[-*]\s*)?\[[ xX]\]\s*/
197
+
198
+ const proposalTaskText = (text: string): string =>
199
+ ellipsize(terminalSafe(text.replace(/\s+/g, ' ')).replace(CHECKBOX, '').replaceAll('"', "'").trim(), TEXT_LIMIT)
200
+
201
+ /** `parallel tasks <lane>: "<a>" ∥ "<b>" · ~<n>k tokens for 1 extra agent`, one line. */
202
+ export const formatTaskParallelLine = (lane: string, proposal: TaskParallelProposal): string => {
203
+ const tasks = proposal.tasks.map((task) => `"${proposalTaskText(task.text)}"`).join(' ∥ ')
204
+ const agents = proposal.extraAgents === 1 ? 'agent' : 'agents'
205
+ return `parallel tasks ${proposalTaskText(lane)}: ${tasks} · ~${kilo(proposal.estimateTokens)} tokens for ${proposal.extraAgents} extra ${agents}`
206
+ }
@@ -0,0 +1,19 @@
1
+ import { ellipsize, terminalSafe } from '../plan-format/terminal-text'
2
+ import type { WaitingItem } from '../plan-format/waiting'
3
+ import { shownWithMore } from '../plans/shown-with-more'
4
+
5
+ const SHOWN_ITEMS = 3
6
+ const ITEM_LENGTH = 40
7
+
8
+ const itemText = ({ item }: WaitingItem): string => ellipsize(terminalSafe(item).replace(/\s+/g, ' '), ITEM_LENGTH)
9
+
10
+ /**
11
+ * The line that brings back what waits on the user's answer, in every heartbeat and status until the item is closed:
12
+ * `for you (<n>): <item>; …`, three items and `+<n>` for the rest. Null when no item is open.
13
+ */
14
+ export const waitingLine = (items: readonly WaitingItem[]): string | null => {
15
+ const open = items.filter(({ open: isOpen }) => isOpen)
16
+ if (open.length === 0) return null
17
+ const { shown, more } = shownWithMore(open, SHOWN_ITEMS)
18
+ return `for you (${open.length}): ${[...shown.map(itemText), ...(more > 0 ? [`+${more}`] : [])].join('; ')}`
19
+ }
@@ -1,4 +1,5 @@
1
1
  import { CHECKS, type ChecksState } from '../plans/pull-requests'
2
+ import { isRecord } from '../shared/is-record'
2
3
  import {
3
4
  APPOINTMENT_EVENT,
4
5
  type AppointmentEvent,
@@ -10,7 +11,6 @@ import { APPROVAL_EVENT, type ApprovalEvent } from './approvals'
10
11
  import { type CoordinatorLevel, type CoordinatorReading, isContextLevel, levelStep } from './coordinator-fill'
11
12
  import { emptyFailureState, type FailureState, failedTestsOf, isFailureState } from './failures'
12
13
  import { emptyFeedbackState, FEEDBACK_EVENT, type FeedbackEvent, type FeedbackState, isFeedbackState } from './feedback'
13
- import { isRecord } from './json-guards'
14
14
  import { isLaneLevels, LANE_FILL_EVENT, type LaneFillEvent, type LaneLevels } from './lane-fill'
15
15
  import { isLaneModels, LANE_MODEL_EVENT, type LaneModelEvent, type LaneModels } from './lane-model'
16
16
  import { isLaneParallels, LANE_PARALLEL_EVENT, type LaneParallelEvent, type LaneParallels } from './lane-parallel'
@@ -18,6 +18,12 @@ import { type LaneSnapshot, type SeenSeqs, seenSeqsOf } from './lane-watch'
18
18
  import { emptyPreviewState, isPreviewState, PREVIEW_EVENT, type PreviewEvent, type PreviewState } from './previews'
19
19
  import { PULL_REQUEST_STATE, type WatchedPullRequest } from './pull-requests'
20
20
  import { emptySourceState, isSourceState, SOURCE_EVENT, type SourceEvent, type SourceState } from './sources'
21
+ import {
22
+ isTaskParallelFingerprints,
23
+ TASK_PARALLEL_EVENT,
24
+ type TaskParallelEvent,
25
+ type TaskParallelFingerprints,
26
+ } from './task-parallel'
21
27
  import { RUN_EVENT, RUN_STATUS, type WorkflowRun } from './workflow-runs'
22
28
 
23
29
  /** What the coordinator is told besides a lane that stopped. The values are the words of the report. */
@@ -34,6 +40,7 @@ export const WATCH_EVENT = {
34
40
  laneFill: LANE_FILL_EVENT,
35
41
  laneModel: LANE_MODEL_EVENT,
36
42
  laneParallel: LANE_PARALLEL_EVENT,
43
+ taskParallel: TASK_PARALLEL_EVENT,
37
44
  approval: APPROVAL_EVENT,
38
45
  source: SOURCE_EVENT,
39
46
  due: APPOINTMENT_EVENT.due,
@@ -86,6 +93,8 @@ export type WatchState = {
86
93
  laneModels: LaneModels
87
94
  /** The phases last reported as able to run together for each watched lane; a lane without two has none. */
88
95
  laneParallels: LaneParallels
96
+ /** The fingerprint of the parallel-task situation of each watched lane at the last heartbeat; a proposal is made only when it moved. */
97
+ taskParallels: TaskParallelFingerprints
89
98
  /** The ids of the approval requests on disk when they were last read, each reported once while it is open. */
90
99
  approvals: string[]
91
100
  /** Per configured source of `watch.sources`: the entries seen (`[id, fingerprint]`) and the start of a failure streak. */
@@ -139,6 +148,7 @@ export type WatchEvent =
139
148
  | LaneFillEvent
140
149
  | LaneModelEvent
141
150
  | LaneParallelEvent
151
+ | TaskParallelEvent
142
152
  | ApprovalEvent
143
153
  | SourceEvent
144
154
  | AppointmentEvent
@@ -173,6 +183,7 @@ export const emptyWatchState = (): WatchState => ({
173
183
  laneLevels: {},
174
184
  laneModels: {},
175
185
  laneParallels: {},
186
+ taskParallels: {},
176
187
  approvals: [],
177
188
  sources: emptySourceState(),
178
189
  reportMtimes: {},
@@ -218,6 +229,7 @@ const isWatchState = (value: Record<string, unknown>): value is WatchState =>
218
229
  isLaneLevels(value.laneLevels) &&
219
230
  isLaneModels(value.laneModels) &&
220
231
  isLaneParallels(value.laneParallels) &&
232
+ isTaskParallelFingerprints(value.taskParallels) &&
221
233
  Array.isArray(value.approvals) &&
222
234
  value.approvals.every((id) => typeof id === 'string') &&
223
235
  isSourceState(value.sources) &&
@@ -1,7 +1,8 @@
1
1
  import type { JackherdConfig } from '../config'
2
2
  import { GITHUB_HOST } from '../plans/github'
3
3
  import { runIdOfLink } from '../plans/pull-requests'
4
- import { isRecord, parseArray } from './json-guards'
4
+ import { isRecord } from '../shared/is-record'
5
+ import { parseArray } from './json-guards'
5
6
 
6
7
  /** Which workflow's runs are deploys, and which environments count as their target (`watch.deploy`). */
7
8
  export type DeployConfig = NonNullable<JackherdConfig['watch']['deploy']>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-0.643 -0.176) scale(0.948)" stroke-width="1.845"><svg x="0" y="4" width="22.4" height="20" viewBox="439 80 402 359" preserveAspectRatio="xMinYMax meet"><defs><clipPath id="jack-dark-head"><path d="M458 250L465 215L480 185L500 160L525 135L560 113L600 103L645 99L690 102L730 114L765 138L792 175L812 215L822 255L820 290L802 306L772 313L748 321L740 350L724 388L700 413L676 420L650 407L600 377L560 348L547 329L535 318L500 309L470 302L458 280Z"/></clipPath><mask id="jack-dark-rim"><path d="M458 250L465 215L480 185L500 160L525 135L560 113L600 103L645 99L690 102L730 114L765 138L792 175L812 215L822 255L820 290L802 306L772 313L748 321L740 350L724 388L700 413L676 420L650 407L600 377L560 348L547 329L535 318L500 309L470 302L458 280Z" fill="#fff" stroke="#fff" stroke-width="36" stroke-linejoin="round"/></mask></defs><path mask="url(#jack-dark-rim)" d="M694 108c.6 .6 .6 .6 4 3.5c2.5 1 2.5 1 6.6 1.6c11.2 2 19 6.7 26.4 15.3c3.3 3.4 7.2 4.9 11.5 7c12.2 6.4 19.5 15.5 25.5 27.6c-.1 1.3-.4 2.7-.5 4c0 10.8 7.3 19.8 14.3 27.6c4.9 4.4 10.5 7.6 16.2 10.9c.5 .8 .5 .8 3 5c.7 .8 1.4 1.7 2.1 2.6c7.5 9.3 12.5 20.2 11.4 32.4c-1.3 1.2-2.6 2.3-4 3.5c-1.4 3.6-1.5 6.4-1.2 10.2c.6 12.6-3.4 22.9-10.3 33.3c-5.1 4.4-5.1 4.4-10.5 5c-4.5 2.8-7 6-10.5 10c-6.9 5.3-12.2 8-21 8c-1.8-.8-3.6-1.6-5.5-2.5c-5-1.6-7.1-2.1-12 0c-8.3 6.2-8.3 6.2-10 10.5c-.6 11.3 .1 16.9 5.4 26.7c6.9 13.8 11.5 30.9 9.1 46.3c-1 .6-2 1.3-3 2c-3.4 4.2-3 7.1-3 12.4c.1 7.5-.4 13.7-3.5 20.6c-.5 1.3-1.1 2.6-1.7 3.9c-4.8 10.7-11.7 16.6-21.8 22.1c-4 3-4 3-7.5 6.5c-.5 .4-.5 .4-3 2.5c-.5 .6-.5 .6-3 4c-1.3 1.1-2.6 2.3-4 3.5c-6.3 5.6-6.3 5.6-7 11c1.4 5.4 3 7 7 11c2 3 2 3 3 8c.5 1.2 1 2.4 1.5 3.6c3.1 8 3.5 13.7 .5 21.9c-6.6 9.9-15.4 13.7-26.7 16.8c-6.4 1.2-12.4 1.5-18.9 .9c-3.6-.2-7.2-.2-10.8-.1c-9.2 0-15.9-2.1-24.1-6.1c-4-.5-4-.5-10.5 0c-10.9-2.4-19.9-9.1-27.4-17.2c-4.1-4.4-5.6-5.2-11.6-5.8c-2.5 .1-4.9 .3-7.3 .5c-34.1 2.3-34.1 2.3-46.2-7c-3-3.5-3-3.5-6.5-8.5c-2.5-2-2.5-2-6.5-4c-2.3-5.5-3.3-10-3.9-15.9c-.6-3.6-.6-3.6-3.6-7.6c-5.9-3.5-5.9-3.5-12.5-3.5c-3 1.5-3 1.5-6.8 5.3c-5.1 5-9.8 8.1-16.2 11.2c-3.6 4.3-4 4.9-4 10.5c.4 1.1 .6 2.3 1 3.5c.1 .6 .1 .6 .4 3.9c.7 4.8 1.7 8 5.6 11.1c-.1 .6-.4 1.3-.5 2c-5.1 1.9-10.1 2.8-15.5 3.5c-1.3 .4-2.6 .6-3.9 1c-7.9 1.9-15.6 2.1-23.6 2.5c-2.1 .1-4.3 .4-6.5 .5c-13.9-1.1-26.6-3.5-36.5-14c-3-6-3-6-4-10.9c-1.1-5.2-2.9-7-6.5-10.6c-3.2-16.4 1.4-30.4 10.5-44c1-1.5 2-2.9 3-4.5c.5-1.5 .5-1.5 .5-7.5c-1.5-3-1.5-3-6-8c-1-2-1-2-1-4c1.8-.6 3.6-1.3 5.5-2c9.9-5.7 16.1-13.1 19.5-24c.4-1.1 .7-2.1 1.1-3.3c3.9-12.8 3.9-12.8 .9-18.7c-3-2.5-3-2.5-6.1-4.1c-6.5-3.6-11.1-8.9-13.9-15.9c0-1.8 0-3.6 0-5.5c-1.8-4.1-3.1-5.5-7-7.5c-7.4-12.1-10.1-24.1-7.1-37.9c2-7.4 5-13.2 9.1-19.6c3.1-4.9 3.2-6.3 2-12c0-11.8 7.7-21.9 15.4-30.2c11.9-11.1 26.8-16.8 43.1-16.3c1.1 .5 2.3 1 3.5 1.5c5.5 .5 5.5 .5 10 .5c2.5 .9 5 1.9 7.5 3c3.5 .5 3.5 .5 8-.5c4.1-3.4 5.6-6.8 8-11.5c2.7-3.8 5.6-7.3 8.5-11c1.9-3.7 1.4-5.9 .5-10c-3-3.5-3-3.5-7-5.5c.1-.5 .4-1 .5-1.5c3.1-1.3 6.4-2.7 9.5-4c12.1-6.8 21.1-16.6 30-26.9c4.1-4.3 8.5-7.5 13.5-10.7c4.5-3.1 5.8-5.7 7.5-10.9c10-11 22.4-17.4 36.6-21.1c5.4-1.4 5.4-1.4 8.4-3.4c13.1-6.5 28.2-8.5 42.5-5c2.7 1 5.4 2 8 3c4.5 .7 6.8 0 10.5-2.5c.8-.7 1.6-1.3 2.5-2c9.5-4.8 9.5-4.8 12.5-4c31.5 0 31.5 0 38.5 4z" fill="#FAF9F8" stroke="#FAF9F8" stroke-width="36" stroke-linejoin="round"/><g clip-path="url(#jack-dark-head)"><g id="jack"><path fill="#212E34" d="M694 108c.6 .6 .6 .6 4 3.5c2.5 1 2.5 1 6.6 1.6c11.2 2 19 6.7 26.4 15.3c3.3 3.4 7.2 4.9 11.5 7c12.2 6.4 19.5 15.5 25.5 27.6c-.1 1.3-.4 2.7-.5 4c0 10.8 7.3 19.8 14.3 27.6c4.9 4.4 10.5 7.6 16.2 10.9c.5 .8 .5 .8 3 5c.7 .8 1.4 1.7 2.1 2.6c7.5 9.3 12.5 20.2 11.4 32.4c-1.3 1.2-2.6 2.3-4 3.5c-1.4 3.6-1.5 6.4-1.2 10.2c.6 12.6-3.4 22.9-10.3 33.3c-5.1 4.4-5.1 4.4-10.5 5c-4.5 2.8-7 6-10.5 10c-6.9 5.3-12.2 8-21 8c-1.8-.8-3.6-1.6-5.5-2.5c-5-1.6-7.1-2.1-12 0c-8.3 6.2-8.3 6.2-10 10.5c-.6 11.3 .1 16.9 5.4 26.7c6.9 13.8 11.5 30.9 9.1 46.3c-1 .6-2 1.3-3 2c-3.4 4.2-3 7.1-3 12.4c.1 7.5-.4 13.7-3.5 20.6c-.5 1.3-1.1 2.6-1.7 3.9c-4.8 10.7-11.7 16.6-21.8 22.1c-4 3-4 3-7.5 6.5c-.5 .4-.5 .4-3 2.5c-.5 .6-.5 .6-3 4c-1.3 1.1-2.6 2.3-4 3.5c-6.3 5.6-6.3 5.6-7 11c1.4 5.4 3 7 7 11c2 3 2 3 3 8c.5 1.2 1 2.4 1.5 3.6c3.1 8 3.5 13.7 .5 21.9c-6.6 9.9-15.4 13.7-26.7 16.8c-6.4 1.2-12.4 1.5-18.9 .9c-3.6-.2-7.2-.2-10.8-.1c-9.2 0-15.9-2.1-24.1-6.1c-4-.5-4-.5-10.5 0c-10.9-2.4-19.9-9.1-27.4-17.2c-4.1-4.4-5.6-5.2-11.6-5.8c-2.5 .1-4.9 .3-7.3 .5c-34.1 2.3-34.1 2.3-46.2-7c-3-3.5-3-3.5-6.5-8.5c-2.5-2-2.5-2-6.5-4c-2.3-5.5-3.3-10-3.9-15.9c-.6-3.6-.6-3.6-3.6-7.6c-5.9-3.5-5.9-3.5-12.5-3.5c-3 1.5-3 1.5-6.8 5.3c-5.1 5-9.8 8.1-16.2 11.2c-3.6 4.3-4 4.9-4 10.5c.4 1.1 .6 2.3 1 3.5c.1 .6 .1 .6 .4 3.9c.7 4.8 1.7 8 5.6 11.1c-.1 .6-.4 1.3-.5 2c-5.1 1.9-10.1 2.8-15.5 3.5c-1.3 .4-2.6 .6-3.9 1c-7.9 1.9-15.6 2.1-23.6 2.5c-2.1 .1-4.3 .4-6.5 .5c-13.9-1.1-26.6-3.5-36.5-14c-3-6-3-6-4-10.9c-1.1-5.2-2.9-7-6.5-10.6c-3.2-16.4 1.4-30.4 10.5-44c1-1.5 2-2.9 3-4.5c.5-1.5 .5-1.5 .5-7.5c-1.5-3-1.5-3-6-8c-1-2-1-2-1-4c1.8-.6 3.6-1.3 5.5-2c9.9-5.7 16.1-13.1 19.5-24c.4-1.1 .7-2.1 1.1-3.3c3.9-12.8 3.9-12.8 .9-18.7c-3-2.5-3-2.5-6.1-4.1c-6.5-3.6-11.1-8.9-13.9-15.9c0-1.8 0-3.6 0-5.5c-1.8-4.1-3.1-5.5-7-7.5c-7.4-12.1-10.1-24.1-7.1-37.9c2-7.4 5-13.2 9.1-19.6c3.1-4.9 3.2-6.3 2-12c0-11.8 7.7-21.9 15.4-30.2c11.9-11.1 26.8-16.8 43.1-16.3c1.1 .5 2.3 1 3.5 1.5c5.5 .5 5.5 .5 10 .5c2.5 .9 5 1.9 7.5 3c3.5 .5 3.5 .5 8-.5c4.1-3.4 5.6-6.8 8-11.5c2.7-3.8 5.6-7.3 8.5-11c1.9-3.7 1.4-5.9 .5-10c-3-3.5-3-3.5-7-5.5c.1-.5 .4-1 .5-1.5c3.1-1.3 6.4-2.7 9.5-4c12.1-6.8 21.1-16.6 30-26.9c4.1-4.3 8.5-7.5 13.5-10.7c4.5-3.1 5.8-5.7 7.5-10.9c10-11 22.4-17.4 36.6-21.1c5.4-1.4 5.4-1.4 8.4-3.4c13.1-6.5 28.2-8.5 42.5-5c2.7 1 5.4 2 8 3c4.5 .7 6.8 0 10.5-2.5c.8-.7 1.6-1.3 2.5-2c9.5-4.8 9.5-4.8 12.5-4c31.5 0 31.5 0 38.5 4z"/><path fill="#4A4E51" d="M651.5 106.5c.6 .2 1.3 .3 2 .5c-.6 .6-.6 .6-4 3.5c-1.4 2.3-2.7 4.7-4 7c-.4 .2-.4 .2-2 1c-.6-.3-1.3-.7-2-1c-.6 .5-1.3 1-2 1.5c.1 .2 .1 .2 .5 1c-2-.5-2-.5-7-4.5c-4.8-2.5-9.4-4.2-14.5-5.5c-1-.3-2-.7-3-1c4.7-1.2 10.2 1.8 14.5 3.5c1.1 .3 2.3 .7 3.5 1c.6 .3 1.3 .7 2 1c.6-.8 1.3-1.7 2-2.5c.6-.2 1.3-.3 2-.5c-.6 1.3-1.3 2.7-2 4c.1 .2 .4 .3 .5 .5c.8 0 1.6 0 2.5 0c1-1.3 2-2.7 3-4c.6-.3 1.3-.7 2-1c0 .8 0 1.7 0 2.5c1-1.5 2-3 3-4.5c1-.8 2-1.7 3-2.5zM606.5 127c0 .5 0 1 0 1.5c-1.4 .4-2.7 .7-4.2 1.2c-8.1 2.7-14.3 6.7-20.3 12.8c1.4-.3 2.7-.7 4.1-.9c4.9-1.1 4.9-1.1 11.4-1.6c1 1 1 1 1 2.5c1 0 2 0 3 0c0 .5 0 1 0 1.5c-1 .5-2 1.1-3 1.6c-12.6 7-19.1 17.5-23.5 30.9c-.5 .3-1 .7-1.5 1c-.5-.2-1-.3-1.5-.5c-.7 1.4-1.4 2.9-2 4.4c-2.5 5.1-2.5 5.1-5.5 10.1c-.5 .2-1 .3-1.5 .5c0-6.8 1.7-12.2 4-18.5c-.4 0-.6 0-1 0c-.1 .3-.1 .3-1 2c-.6 1.2-1.2 2.3-1.8 3.6c-3.2 6.3-5.8 12.7-7.9 19.5c-1.7 5-3.7 8.9-6.3 13.4c-3 7.1-4.5 13.8-4.5 21.5c.4-1.3 .8-2.7 1.2-4.1c4.8-14.4 4.8-14.4 7.8-16.4c.1 1.1 .2 2.2 .3 3.3c1.8 12.3 6.3 24 10.4 35.6c4.8 15 3.9 29.5-1.7 44.1c-1.3 2.4-2.6 4.7-4 7c-.5 0-1 0-1.5 0c0-2.1 0-4.1 .1-6.2c-.1-10.5-2.4-18.9-7.1-28.3c-.4-.1-.6-.4-1-.5c.1 .6 .4 1.3 .5 2c1.3 16-1.7 32.7-11 46c-2.9-2.9-4.4-6.8-6.3-10.4c-2.2-3.8-4.6-7.5-7.2-11.1c-11-16.4-13.9-35.1-10.5-54.5c2.2-7.7 4.8-14.9 8.5-22c-14.6 14.6-18.4 34.4-19.1 54.2c.3 8.1 2.5 15.6 4.6 23.3c0 .5 0 1 0 1.5c-7.4-2.9-12.6-11.8-16.4-18.4c-6.3-14.7-5.4-28.9 .4-43.6c1-1.7 2-3.3 3-5c.4-.7 .6-1.3 1-2c-8 5.9-15 11.4-19.5 20.5c-.4 0-.6 0-1 0c0-13.1 7.6-26.4 16-36c.7-.9 1.4-1.8 2.2-2.7c4.6-5.6 9.7-10.7 14.8-15.8c1.9-2.2 3.7-4.4 5.4-6.7c2.6-3.3 2.6-3.3 7.1-7.8c-3.4 0-7 2.9-10 4.5c-.3 .1-.3 .1-1.5 .5c.5-2 .5-2 4.5-6c.7-1 1.4-2 2-3.1c11.5-15.4 27.5-26.1 46.5-29.4c2.5-.3 5-.7 7.5-1c-2.7-2.8-7.7-2.6-11.5-3c1.3-3.9 7.6-6.3 11.1-8.3c8.1-3.5 16.7-6.2 25.4-7.7c3.4-1.7 7.6 0 11 1zM743.5 149c4 1 6.9 4 10 6.5c.6-.3 1.3-.7 2-1c.1 .7 .4 1.3 .5 2c.1 .3 .4 .7 .5 1c.5 0 1 0 1.5 0c5 5.7 8.4 11.4 11 18.5c6.6 12.3 13.5 20.3 25.5 27.5c-.1 .1-.1 .1-1 .5c-1.3-.7-2.6-1.3-4-2c1 3.5 1 3.5 5 8.5c7 8.8 7 8.8 8 14.5c-3.7 .9-6.9-2.2-10-4c-.6-.4-.6-.4-4-2.5c-.5-.2-1-.3-1.5-.5c1.5 3 1.5 3 5.5 7c3.9 5.3 5 10.1 6 16.6c.3 1.6 .6 3.4 .9 5.2c1.6 13.3 1.6 13.3 .1 16.2c-.4 0-.6 0-1 0c-.3-1.1-.5-2.2-.9-3.3c-3.8-14-11.6-25.8-21.1-36.7c-7.5-8.8-7.5-8.8-7.5-13.5c-2.2-3.4-4.6-6.7-7-10c-1.8-4.4-3.1-8.9-4.5-13.5c-.5-1.2-1-2.3-1.5-3.5c0-.5 0-1 0-1.5c1.5 .5 1.5 .5 5 5.5c3.5 4 3.5 4 5 4.5c-.6-1.2-1.2-2.3-1.8-3.6c-3-6-5.2-12-7.2-18.4c-3.5-5-3.5-5-6-7.5c-1.5-2-1.5-2-4-7c-1.1-1.5-2.3-2.9-3.5-4.5c0-.3 0-.7 0-1zM720.5 140.5c1 0 2 0 3 0c0 .5 0 1 0 1.5c-.4 0-.6 0-1 0c0 .3 0 .7 0 1c1 .3 2 .7 3 1c10.4 9.3 15.4 19 16.5 33c-.6 .2-1.3 .3-2 .5c-1-.8-2-1.7-3-2.5c-8-4.7-14.1-7.7-23.5-6.5c0-3.9 6.3-8.3 9-11c0-.3 0-.7 0-1c-2-1-2-1-7-1c-6.4 2.6-10 6.3-14.5 11.5c.5 2 .5 2 3 4.5c.2 .1 .2 .1 1.5 .5c.1 .5 .4 1 .5 1.5c-1.5 2.8-3 5.7-4.5 8.5c-.4 .8-.6 1.7-1 2.5c-2 .5-4 1-6 1.5c-.1 .2-.1 .2-1 1c-.4 0-.6 0-1 0c1-2.5 1-2.5 2-3.5c.8-.2 .8-.2 5-1c.6-1.7 1.3-3.3 2-5c.6-1 1.3-2 2-3c0-.5 0-1 0-1.5c-1-.8-2-1.7-3-2.5c-.5-.7-1-1.3-1.5-2c1.6-6.6 9.1-11.3 14.5-14.5c3.3-.8 5.9-.8 9 .5c.4 .5 .4 .5 2.5 3c-2.6 2.7-5.3 5.3-8 8c2 .2 4 .3 6 .5c12.9 5.3 12.9 5.3 16.5 9c-.9-9.9-3.9-18.4-10.5-26c-5.5-4-5.5-4-9.5-6c0-1.5 0-1.5 1-2.5zM634 169.5c.8 .1 .8 .1 5 .5c6 2.5 6 2.5 9.5 6c.5 3.5 .5 3.5-2 7c-.4 0-.6 0-1 0c2.5 2.5 2.5 2.5 5.9 5.1c3.1 2.4 3.1 2.4 4.1 4.4c-2.5 2.1-4.3 3.3-7.5 4c.5 1.8 1 3.7 1.5 5.5c.8-.8 1.6-1.6 2.4-2.3c3.7-3.2 7.6-4.8 12.1-6.7c1 .5 2 1 3 1.5c.1 .5 .4 1 .5 1.5c-1.5 2-1.5 2-5 4c-4 3.2-6.9 6.1-10 10c-.4-.2-.6-.3-1-.5c2.9-5.8 8.1-9.7 13.5-13c0-.2 0-.3 0-.5c-6 .8-10 3.1-14.5 7c-.5 .7-1 1.3-1.5 2c-.2-.1-.2-.1-1.5-.5c-.1-1-.1-1-1-6c-.1-.4-.1-.4-1-2.5c.1-.8 .4-1.7 .5-2.5c1.3 .2 2.6 .3 4 .5c1-.5 2-1 3-1.5c-1.2-3.8-7.1-6.5-10.5-8.5c0-.3 0-.7 0-1c1.1-.7 2.3-1.3 3.5-2c1-2 1-2 .5-4.5c-4.1-4.1-8-4.3-13.5-5c-1.6-.5-3.3-1-5-1.5c-6.5 0-10.4 .3-16 3.5c-.1 .3-.4 .7-.5 1c1.3 0 2.6 0 4 0c6 1.6 10.8 4.3 16 7.5c-.1 .2-.1 .2-.5 1.5c-1.6 .2-3.3 .3-5 .5c-13 3.7-20.4 11.7-29 21.5c-3.5 3-3.5 3-5.5 4c10.9 .3 10.9 .3 15-2.5c.1-.2 .1-.2 .5-1.5c.5 0 1 0 1.5 0c-.1 .8-.4 1.7-.5 2.5c-5.5 3.6-8.5 4-15 4c-1.1-.3-2.3-.7-3.5-1c-.1-.7-.4-1.3-.5-2c1.5-1.5 1.5-1.5 5.5-3.5c3.7-3.7 7.1-7.6 10.5-11.5c6.5-6.2 13.2-10.1 22-12.5c-10.5-5.5-10.5-5.5-15-5.5c-.4-.1-.4-.1-2.5-.5c0-.7 0-1.3 0-2c7.7-6.2 15.2-6.8 24.5-4zM740.5 183c.4 .2 .6 .3 1 .5c.5 1.8 .9 3.7 1.3 5.5c1.4 5.5 3.1 10 5.7 15c.1 .5 .4 1 .5 1.5c-4.5-1-4.5-1-8.5-3c0-.3 0-.7 0-1c1.6 .3 3.3 .7 5 1c-6.5-3.3-10.8-4.5-18-4.5c-.1-.3-.4-.7-.5-1c.6-1 1.3-2 2-3c.4 .3 .6 .7 1 1c-.1 .3-.4 .7-.5 1c.6-.1 .6-.1 3.5-.5c3.6 .8 7 1.7 10.5 3c-.4-1.3-.8-2.4-1.2-3.7c-2.3-7.6-2.3-7.6-2.3-11.3c.1-.2 .4-.3 .5-.5zM578 181c.5 0 1 0 1.5 0c-1 3-1 3-2.7 6.9c-6.1 13.9-5.7 28.5-.7 42.7c.5 1.2 .9 2.2 1.4 3.4c1 0 1 0 5.5-4c10-7.4 20.1-11.8 32.5-12.5c.8-.2 1.6-.3 2.5-.5c1.1 .3 2.3 .7 3.5 1c1 0 2 0 3 0c.1 .3 .4 .7 .5 1c-.1 .3-.4 .7-.5 1c-1.3 0-2.6 0-4 0c0 .3 0 .7 0 1c1.4 0 2.7-.1 4.1-.1c4.4 .1 4.4 .1 6.9 1.1c-1.8 2.7-5.2 3.6-8 5c-9.7 6.1-17.5 13.3-24.5 22.5c.5-.3 1-.7 1.5-1c.6-.2 1.3-.3 2-.5c.4 .3 .6 .7 1 1c-.9 3.4-3.1 6.1-5 9c-5.1 10.3-6.7 19.6-6.5 31c-.5 0-1 0-1.5 0c0-.5 0-1 0-1.5c-.4 0-.6 0-1 0c0 1.8 0 3.6 0 5.5c-.4 1-.6 2-1 3c-1.1 4.7 1.1 10.2 3 14.5c-2-.5-2-.5-7-4.5c-1.1-.8-2.3-1.6-3.5-2.4c-3-2.1-3-2.1-5-4.1c.8-2.7 1.6-5.4 2.5-8c2.6-15.9 2.3-29.4-3.7-44.6c-7.5-19.6-7.5-19.6-5.8-29.9c.1 0 .4 0 .5 0c.4 1.7 .6 3.3 1 5c.4 0 .6 0 1 0c-.4-1.3-.6-2.7-1-4c-1.1-13.7 .6-23.9 7-36c.1-.3 .4-.7 .5-1zM621.5 219c0 .2 0 .3 0 .5c.8 0 1.6 0 2.5 0c0-.2 0-.3 0-.5c-.8 0-1.6 0-2.5 0zM591 268c-1.5 5.5-1.5 5.5-1 8c.1 0 .4 0 .5 0c1-5 1-5 1-8c-.1 0-.4 0-.5 0zM452.5 289.5c2.6 .2 5.4 .4 8 .5c.1-.1 .4-.4 .5-.5c.9 0 1.6 0 2.5 0c.1 .3 .1 .3 1 1.5c.4 .1 .4 .1 2 1c1.3 1.5 2.6 2.9 4 4.5c4 2.5 4 2.5 9.5 2.5c3.5 4 3.5 4 7.5 9.5c-1 2-1 2-1.5 2.5c-2.1 0-4.3 0-6.5 0c0-.5 0-1 0-1.5c.5 0 1 0 1.5 0c0-.4 0-.6 0-1c-.9-.1-1.6-.4-2.5-.5c-2.5-1-5-2-7.5-3c-8.3-2.1-16.2-.1-23.5 4c-4.4 3.6-7.6 8.4-9 14c0 6 0 6 1 10c-2.6 2.1-5.3 4.1-7.9 6.1c-6.5 5.3-11.5 11-16.1 17.9c-2.5-.5-2.5-.5-6.5-3c-.6-.1-1.3-.4-2-.5c0-.5 0-1 0-1.5c-.5 0-1 0-1.5 0c-5.6-1.4-9.9-6.9-13-11.5c.1-.5 .4-1 .5-1.5c2.2 2.4 4.4 4.9 6.5 7.5c1.5 1 2.9 2 4.5 3c-.2-.7-.2-.7-1.5-4.5c-.7-4.1-.6-8.3-.5-12.5c.9 .1 1.6 .4 2.5 .5c0-.5 0-1 0-1.5c-.9 0-1.6 0-2.5 0c0-8.6 0-8.6 2.5-12c2 .5 2 .5 3 1.5c.6 2.1 1.3 4.3 2 6.5c3 6 3 6 5.5 9c-.1-1.9-.1-3.7-.1-5.7c.2-14.2 4.5-22.7 14.6-32.8c16.6-10.6 16.6-10.6 23-8.5zM448 290c0 .1 0 .4 0 .5c1 0 2 0 3 0c0-.1 0-.4 0-.5c-1 0-2 0-3 0zM461 290c2 .5 2 .5 2 .5zM405 322c-.4 .4-.6 .6-1 1c.4 0 .6 0 1 0c.1 1.1 .4 2.3 .5 3.5c.4 .1 .6 .4 1 .5c-.5-4-.5-4-1.5-5zM403.5 323.5c.5 2 .5 2 .5 2zM403 326.5c.5 1 .5 1 .5 1zM551.5 328.5c1 1.5 2 2.9 3 4.5c14.9 20 14.9 20 24.5 25.5c1.9 1.5 3.7 3 5.5 4.5c1 .8 2 1.6 3.1 2.4c.4 .4 .4 .4 2.4 2.1c0 .5 0 1 0 1.5c-3.4-2.2-6.6-4.6-9.5-7.5c-.2 6.6 .5 12.5 2 19c.4 1.5 .6 2.9 1 4.5c-1.5 1.5-1.5 1.5-7 3c-.8 .8-1.6 1.6-2.5 2.5c-.8 .8-1.6 1.6-2.5 2.4c-2.5 2.6-2.5 2.6-5 5.6c-.6-.1-1.3-.4-2-.5c-.5-2-.5-2 1-7.5c-2.5 .5-2.5 .5-5.5 4c-.4 0-.6 0-1 0c-.4 .6-.6 1.3-1 2c-1.1 1.3-2.3 2.6-3.5 4c-8.5 12.7-11.5 27.9-11.5 43c-.4 .1-.6 .4-1 .5c-5-4-5.8-10.6-7-16.5c-.1-2.1-.4-4.3-.5-6.5c-.1 0-.4 0-.5 0c-2.1 9.9-2.8 19.9-3.5 30c.4 0 .6 0 1 0c.5 1 .5 1 .5 5c-.5 0-1 0-1.5 0c0-1.1 0-2.3 0-3.5c-1.8-.1-3.6-.4-5.5-.5c0-.4 0-.6 0-1c-1.6 0-3.3 0-5 0c-8.6-2.6-8.6-2.6-12.5-6.5c-1.5-1.2-3-2.4-4.5-3.5c-.4 .4-.4 .4-2.5 2c-6.1-3.3-10.1-6.6-15-11.5c-.6-.5-1.3-1-2-1.5c-.1-.8-.4-1.6-.5-2.5c-1.1-1.3-2.3-2.6-3.5-4c-1.4-2.6-2.7-5.3-4-8c-.4-.4-.6-.6-1-1c-1-1.5-1-1.5-1-5c-.4 0-.6 0-1 0c-.4-.6-.6-1.3-1-2c-1 5-1 5-1.5 11c-.1 .1-.4 .4-.5 .5c.9 6 1.7 11.7 3.5 17.5c0 .6 0 1.3 0 2c-.4 .1-.4 .1-2 1c-3.6-3-6.9-5.9-10-9.5c-.5-.5-1-1-1.5-1.5c0-.4 0-.6 0-1c-.4-.1-.4-.1-2-1c-9.1-13.1-10.6-25.7-9-41.5c-.6 .8-.6 .8-4 4.5c-.6-.1-1.3-.4-2-.5c-1.8-3.6 1.1-10.7 2.1-14.4c3.6-9.5 8.7-16.9 15.9-24.1c-16.7 3.4-31.6 13.6-42 27c-.4-.1-.6-.4-1-.5c1-2.5 1-2.5 2.5-4.5c.1-.8 .4-1.6 .5-2.5c10.4-16.9 22.1-29.1 41-36c15.8-3.5 29.7-1.9 45 3c.7 .1 .7 .1 4.5 1c-.1 .5-.4 1-.5 1.5c-2.5 .9-5 1.7-7.5 2.5c-3.5 1.5-3.5 1.5-4 2.5c1.5 .1 2.9 .4 4.5 .5c1 .2 1 .2 6 1.5c3.1 .5 6.4 1 9.5 1.5c-.6 1.6-1.4 3.4-2 5c8.8-6.4 14.8-11.9 20-21.5c1-.5 1-.5 4.3-.9c3.6-.6 6.7-3 10.2-2.1zM462 348c-.4 .4-.6 .6-1 1c.4 .1 .4 .1 2 1c0-.6 0-1.3 0-2c-.4 0-.6 0-1 0zM562.5 387.5c.5 1 .5 1 .5 1zM471 404c-.1 .6-.4 1.3-.5 2c1.5 0 1.5 0 2.5-.5c-.1-.5-.4-1-.5-1.5c-.5 0-1 0-1.5 0zM472.5 406c.5 1.5 .5 1.5 .5 1.5zM470 407.5c.5 2 .5 2 .5 2zM469.5 410c.5 2 .5 2 .5 2zM474 411.5c.5 1 .5 1 .5 1zM469 423.5c0 1 0 2 0 3c.1 0 .4 0 .5 0c0-1 0-2 0-3c-.1 0-.4 0-.5 0zM469.5 427c.5 1.5 .5 1.5 .5 1.5zM470 430c.5 1.5 .5 1.5 .5 1.5zM470.5 432c.5 1 .5 1 .5 1zM498.5 432.5c.5 3.5 .5 3.5 1.5 5c0-.5 0-1 0-1.5c.5 .1 1 .4 1.5 .5c-.5-1.5-1-2.9-1.5-4.5c-.5 0-.5 0-1.5 .5zM471 433.5c.5 1.5 .5 1.5 .5 1.5zM471.5 435.5c.5 1 .5 1 .5 1zM500.5 436.5c.5 1 .5 1 .5 1zM520.5 450c2 .5 2 .5 2 .5zM528 451.5c0 .1 0 .4 0 .5c.8 0 1.6 0 2.5 0c0-.1 0-.4 0-.5c-.8 0-1.6 0-2.5 0zM531 452.5c0 1 0 2 0 3c.1 0 .4 0 .5 0c0-1 0-2 0-3c-.1 0-.4 0-.5 0z"/><path fill="#9B9D9E" d="M720.5 140.5c.1 .3 .1 .3 .5 2c1.3 .7 2.6 1.3 4 2c9.5 7.6 13.6 15.7 16 27.5c0 1.5 0 2.9 0 4.5c-1.5 0-1.5 0-4-2c-7.4-4.3-13.2-7.4-22-7c0-1.5 0-1.5 2.9-4.4c1-1 2.1-2 3.1-3.1c.8-1 1.6-2 2.5-3c-1.5-1.5-1.5-1.5-3.5-2c-6.6 0-9.4 1.8-14.5 6c-2.9 3.1-2.9 3.1-5 6c.5 2 .5 2 3 4.5c.5 .5 1 1 1.5 1.5c-.5 2-.5 2-3.5 7.5c-.5 1.2-1 2.3-1.5 3.5c-.9 .2-.9 .2-5.5 1c-.1 .2-.1 .2-1 1c-3-3.1-2.1-7.8-2.1-11.9c0-1.4 0-2.9 0-4.3c.1-5.1 .5-9.9 3.1-14.3c.5-.2 1-.3 1.5-.5c.4 .2 .6 .3 1 .5c.1-.8 .4-1.7 .5-2.5c6-7.7 10.4-10.9 20-12.5c1-.5 1-.5 3 0zM642.5 160c1.3 1 2.6 2 4 3c.1-.7 .4-1.3 .5-2c2 0 2 0 5.1 2.8c7.5 8.1 12.9 19 12.9 30.2c-2 .8-4 1.7-6 2.5c-4.5 2.5-4.5 2.5-9.5 7c-.5-.2-1-.3-1.5-.5c-.5-2.2-1-4.3-1.5-6.5c-.1-.5-.4-1-.5-1.5c1.5-.5 1.5-.5 4.5-.5c1.1-.7 2.3-1.3 3.5-2c-1.2-3.7-7-6.3-10-8.5c.1-.5 .4-1 .5-1.5c.6-.2 1.3-.3 2-.5c1-2.5 1-2.5 .5-6c-4.2-4.2-8.7-4.6-14.5-5.5c-1.1-.3-2.3-.7-3.5-1c-7.4-.3-12.1 .6-18.5 4.5c-.1 .2-.1 .2-.5 1c.6-.1 .6-.1 3.5-.5c5.6 1.4 10.5 3.7 15.5 6.5c0 .7 0 1.3 0 2c-1.8 .3-3.6 .7-5.5 1c-10.5 3.8-17.5 9.9-24.5 18.5c-2.6 3.1-4.6 5.2-8.5 6.5c-.1 .2-.1 .2-.5 1.5c6.9 .1 11.9-.1 18-3.5c1.4 2.1 2.8 4.3 4 6.5c1.3 1 2.6 2 4 3c.1 .3 .1 .3 1 1.5c-1.5 1-1.5 1-4.9 1.2c-11.6 .9-21.9 6.4-30.7 13.9c-2.9 2.4-2.9 2.4-4.9 2.4c-6.7-17.5-7.6-33.2 0-50.5c2.2-4.4 4.1-7.2 7.5-11c-.4-.2-.6-.3-1-.5c3.9-7.7 16.8-12.7 24.5-16c12.7-3.5 23.3-3.8 35 2.5zM739.5 180.5c.6 .3 1.3 .7 2 1c0 1.5 0 2.9 0 4.5c2.5 10.3 2.5 10.3 4 14c-1.5 .5-1.5 .5-6-1.5c-2.6-.7-5.3-1.3-8-2c.4-1.3 .6-2.7 1-4c0-5 0-5-.5-10c.5-.3 1-.7 1.5-1c.1 .2 .4 .3 .5 .5c3.5 0 3.5 0 5.5-1.5z"/><path fill="#C4CBCE" d="M722 379.5c2.5 .5 2.5 .5 4.5 2.5c1.3 5 1.3 5 .5 8c-2 1-2 1-4 1.5c-1.5-1.5-1.5-1.5-2.5-3.5c-.6-.1-1.3-.4-2-.5c-.4-.6-.6-1.3-1-2c3-4.5 3-4.5 4.5-6z"/><path fill="#FAF9F8" d="M654.5 104c.9 .1 .9 .1 5.5 .5c-2.3 1.5-4.6 3-7 4.5c-3 3.5-3 3.5-3.5 5.5c1.1-.7 2.3-1.3 3.5-2c7.5-3.7 13.6-4.8 22-5c.1 .1 .1 .1 1 .5c0 .3 0 .7 0 1c-1.5 .8-3 1.7-4.5 2.5c-2.3 2.3-4.5 4.5-6 7.5c2-.5 2-.5 4-2c.8-.2 1.6-.3 2.5-.5c.9-.3 .9-.3 5.5-1.5c9.4 0 17.9 2.5 26.5 6c0 .5 0 1 0 1.5c-5 2-5 2-6 2c.1 .7 .4 1.3 .5 2c.4-.2 .6-.3 1-.5c8.9-.5 14.6 2 21.5 7.5c6 6.5 6 6.5 6 8.5c-1.3-.1-2.6-.2-4-.3c-7.5-.3-13.2 1.6-19.5 5.8c-3.5 4-3.5 4-6 9c-.8 0-1.6 0-2.5 0c-1.6 6.1-2.1 11.2-2.1 17.5c0 1.5 0 3 0 4.6c.1 3.9 .1 3.9 1.1 7.4c-1.5 1.5-1.5 1.5-5 2c-.4 .7-.6 1.3-1 2c1.8-.2 3.6-.3 5.5-.5c11 .8 18.8 4.6 27 12c5.3 .7 5.3 .7 10.5 1c15.8 3.9 26.5 12.1 35.1 25.8c2 3.9 3.3 7.5 4.4 11.7c-.1 .5-.4 1-.5 1.5c-1.5-.5-1.5-.5-5-5c-4.5-4.5-4.5-4.5-6-5c1 3 1 3 2.9 6.1c5.7 10.6 6.6 21.6 4.6 33.4c-3.4 8.7-7.5 15-14 21.5c-.5-.1-1-.4-1.5-.5c.1-1.1 .4-2.3 .5-3.5c.1-5.9 .2-10.7-1.5-16.5c-.4-.1-.6-.4-1-.5c-.2 1.3-.4 2.6-.5 4c-2.1 11.1-7 19.5-15 27.5c-.5 .1-1 .4-1.5 .5c0 .4 0 .6 0 1c-12.6 9.5-12.6 9.5-18.5 9.5c1-2.5 1-2.5 3.5-6c2.5-5.5 2.5-5.5 2.5-8c-.4-.1-.6-.4-1-.5c-.4 .6-.6 1.3-1 2c-8.9 10.1-18.4 16.1-31.5 19c-11.5 .7-20.9-3.4-29.5-11c0-.4 0-.6 0-1c-.4 0-.6 0-1 0c.8 6.3 3.4 9.9 7.5 14.5c0 .4 0 .6 0 1c-14.5 0-27.2-5.3-37.5-15.5c-.6-.8-.6-.8-3.5-5c-.5-.5-1-1-1.5-1.5c-.5 0-1 0-1.5 0c1 6.3 2.6 11.2 5.5 17c0 .6 0 1.3 0 2c-10.8-2.1-20.7-7.8-27.4-16.7c-6-9.4-7.6-18.9-6-29.8c1.9-8.3 4.9-14.9 9.4-22c.6-1.2 1.3-2.3 2-3.5c-2 1-2 1-5 4.5c-.5 0-1 0-1.5 0c1.6-6.3 7.7-12.3 12.5-16.5c.8-.8 1.6-1.6 2.5-2.4c9.6-8.4 20.5-13.8 32.8-17.3c3.7-1.3 3.7-1.3 5.2-3.8c4.5-7 9-12.1 16-16.5c.4 0 .6 0 1 0c.1-.7 .4-1.3 .5-2c-.8-.2-1.6-.3-2.5-.5c-.1-1.4-.3-2.9-.5-4.4c-2-10.8-6.9-20.7-15-28.1c-.4-.2-.6-.3-1-.5c.5 1 1 2 1.5 3c-.1 .5-.4 1-.5 1.5c-.7-.6-.7-.6-4.5-3.5c-10-6-18.7-7.2-30.2-5.2c-15.8 4.4-29.1 13.5-39.3 26.2c-.8 .8-1.6 1.7-2.5 2.5c0-11.4 6-22.8 13-31.5c5.9-5.9 11.7-9.8 19.5-13c0-.2 0-.3 0-.5c-8 0-15.4 1.2-23 3.5c-.5 0-1 0-1.5 0c1.2-4.9 6.6-8.1 10.6-10.7c5.5-3.2 10.6-5 16.9-6.3c0-.5 0-1 0-1.5c-8-2.2-15.3-3.3-23.5-4c-.1-.3-.4-.7-.5-1c19.3-6.7 36.5-6.3 55.5 1c.5 .2 1 .3 1.5 .5c-1.5-2.5-1.5-2.5-3.5-4.5c0-.3 0-.7 0-1c1 0 2 0 3 0c.5-.3 1-.7 1.5-1c.5 0 1 0 1.5 0c.1 .2 .1 .2 1 1c1.6-2.2 3-4.6 4.5-7c1.5-1.3 3-2.7 4.5-4c.5-.7 1-1.3 1.5-2zM640.5 117.5c0 .7 0 1.3 0 2c.5 .3 .5 .3 3 2c.4-.7 .6-1.3 1-2c-1.5-1.5-1.5-1.5-4-2zM679.5 200c-4 4.6-4 4.6-4 9.5c3.6 4.3 6.6 5.1 12 6.5c.4 .3 .4 .3 2.5 2c1.5 .5 3 1 4.5 1.5c.9 5.3 .5 7.1-2 12c-8.1 8.2-15 9.1-26 9.5c-.1 .7-.4 1.3-.5 2c7.6 3.8 14.5 3 22.5 .5c4.7-2.1 7.3-3.7 11-7.5c3.5 .5 3.5 .5 7 1.5c4.3 1.1 7.5 .7 11.5-1c2.5-2.5 2.5-2.5 3.5-4.5c-2-.5-2-.5-5.8-.4c-5.2-.1-8.4-1-12.7-4.1c-1.5-4.5-1.5-4.5-2-10c1.6-1.5 3.3-2.9 5-4.5c2.5-5 2.5-5 3-9c-1.5-4.5-1.5-4.5-4.5-7c-8.7-3.2-17.1-1.4-25 3zM555.5 134.5c-2.5 2.5-2.5 2.5-6.5 5.5c-.8 .8-1.6 1.7-2.5 2.5c-3.3 1.1-6.6 2.1-10 3c-1.5 .7-3 1.3-4.5 2c-.4-.2-.6-.3-1-.5c4.2-7.8 9.8-9 18-11.6c4-.9 4-.9 6.5-.9zM728 178c2.5 1 2.5 1 5.5 3.5c0 1.3 0 2.7 0 4c.1 1.5 .4 2.9 .5 4.5c0 3.5 0 3.5-1.5 6.5c-.6 .1-.6 .1-3.5 .5c-.5-2-.5-2 1-7c0-4.1-.4-6.8-2-10.5c0-.5 0-1 0-1.5zM495.5 193c-2 4-5.7 6.6-9 9.5c-1.7 1.7-3.4 3.3-5 5c-.5-1-.5-1 0-4.5c-1-4.5-1-4.5-4-8.5c.9-.1 .9-.1 5.2-.2c4.3-.2 8.5-1.3 12.8-1.3zM618.5 196.5c-.1 2-.4 3.9-.5 6c1.2 6.3 2.9 9.4 7.5 14c.1 .1 .1 .1 1 .5c0 .5 0 1 0 1.5c-3.3 1.6-7.2 .3-10.5-.5c-4.1-2.9-6.2-5.5-8.5-10c.5-3.5 .5-3.5 5-8c5-3.5 5-3.5 6-3.5zM797 228.5c4.8 1.2 8.5 6.9 11.5 10.5c0 .3 0 .7 0 1c.6 .3 1.3 .7 2 1c.8 1.3 1.6 2.7 2.5 4c.4 .3 .6 .7 1 1c-1.1 1-2.3 2-3.5 3c-1 2.5-1 2.5-1.5 5.5c-1-1.5-1-1.5-1.9-4.7c-2.1-7.4-5.3-13-9.6-19.3c-.1-.7-.4-1.3-.5-2zM466 229c.5 1.5 .5 1.5-2 7.5c-3.6 14.2-3.6 27.9 3.1 41.1c2.9 4.9 2.9 4.9 7.4 9.9c.5 0 1 0 1.5 0c-.2-1.1-.4-2.1-.6-3.2c-.7-7.2-.2-13.9 2.1-20.8c.4 0 .6 0 1 0c.5 1 .5 1 .9 5.3c2 17.8 9.7 30.6 22.6 42.7c7.4 5.1 14.9 8.5 23.5 11c0 .5 0 1 0 1.5c-8.2 2.2-14.6 3.1-22.8 .8c-14.9-3.8-28.8-3.3-43.7 .2c-.5-2-.5-2 1.5-6.5c5.3-6.6 12.7-7.7 20.8-8.6c1.6-.1 3.1-.3 4.7-.4c-1.6-3.1-3.5-6.5-6-9c-1.8 0-3.6 0-5.5 0c-5-3.5-5-3.5-7.9-6.6c-2.6-2.9-2.6-2.9-5.6-3.9c-12.9-.4-23.7 2.9-33.5 11.5c-.5-.1-1-.4-1.5-.5c2-2.5 2-2.5 4-4.5c-1.5-.5-1.5-.5-3-.5c-1.5 3-1.5 3-1.5 6c0 1.5 0 1.5-3.5 6.5c-5.6 10.3-5.9 18.9-5 30.5c-5.1-2.6-7.3-7.6-9.5-12.5c-.5-1.8-1-3.6-1.5-5.5c-.5-.1-1-.4-1.5-.5c-2.1 10.5-2.2 19.9 1.5 30c0 .5 0 1 0 1.5c-9.8-4.9-14.8-13.2-18.5-23c-1.6-6-2.4-11.9-1.5-18c.4-.1 .4-.1 2.5-1c2.5-5 2.5-5 3-7.5c-.9 .5-1.6 1-2.5 1.5c-2.1-4.2-.2-10.6 1-15c5.6-14.8 16.3-25.1 30-32.5c10.8-4.5 10.8-4.5 13-4.5c-.1-.5-.4-1-.5-1.5c-11.3-2.5-21.3-.6-32 3c-.4 0-.6 0-1 0c1.3-5.2 8.4-9 12.5-12c13.6-7.4 26-10.4 41.5-9c.1-.3 .4-.7 .5-1c1.6 .2 3.3 .3 5 .5c4.5-1 4.5-1 7-3zM396.5 263c-2.5 2.5-2.5 2.5-6.5 5.5c-4.8 4.3-9.2 8.4-13 13.5c-.5-1-.5-1 0-4.5c-.1-1.5-.4-2.9-.5-4.5c2-2 2-2 5.5-4c.5-.3 .5-.3 3.1-1.9c8.5-5.1 8.5-5.1 11.4-4.1zM792 278.5c1.5 .5 1.5 .5 2 1.5c.1 5.6-.2 10.9-1 16.5c-1.8 .5-3.6 1-5.5 1.5c-.8 .4-1.6 .6-2.5 1c.9-2.2 2-4.4 3-6.5c2-4.8 3.1-8.9 4-14zM374.5 324c.4 .1 .6 .4 1 .5c.2 1.4 .4 2.9 .6 4.4c2 12.2 7.7 20.3 16.9 28.6c-.1 .3-.1 .3-.5 1.5c-9.6-2.8-9.6-2.8-13-5c-.4-2-.6-3.9-1-6c-2.5-3.5-2.5-3.5-6-5.5c.1-.4 .4-.6 .5-1c.1-4.1 .2-8.3 .3-12.4c.2-3.6 .2-3.6 1.2-5.1zM677.5 347c4.5 1.5 4.5 1.5 5.5 3.5c-1.6 6.6-3.8 13.1-6 19.5c-.6 2-1.2 3.9-1.9 6c-2.1 6.5-2.1 6.5-4.1 8.5c-4.5-.5-4.5-.5-6.5-2.5c1.5-5.3 3.1-10.4 5-15.6c.5-1.8 1.1-3.6 1.8-5.5c.6-1.5 1.1-3.2 1.7-4.9c.5-1.4 .9-2.6 1.4-4c1.1-3 1.1-3 3.1-5zM462.5 349c-1 2-1 2-3.3 4.2c-9.5 9.7-13.8 21.6-15.7 34.8c2-1 2-1 6-6.5c.4 0 .6 0 1 0c-.3 2.9-.6 5.7-1 8.5c-.3 13.1 .6 23.4 8 34.5c.9 .8 1.6 1.6 2.5 2.5c4.5 5 4.5 5 5.5 7c.6 .4 1.3 .6 2 1c1.1 1 2.3 2 3.5 3c.4 0 .6 0 1 0c-.8-3.6-1.6-7.4-2.5-11c-1-7.1-.1-14.1 1-21c.5-.4 1-.6 1.5-1c.5 1.6 1 3.1 1.5 4.8c3.4 9.6 7.3 16.4 15 23.2c1.6 1.5 3.3 2.9 5 4.5c2.3 1.4 4.6 2.7 7 4c.1-.5 .4-1 .5-1.5c-.4-.6-.6-1.3-1-2c0-.6 0-1.3 0-2c2 1 2 1 3.9 3.9c5.4 8 13.2 9.3 22.2 11.3c.8 .2 .8 .2 4.4 .8c1 3.5 1 3.5 2 9.5c1.4 7.6 1.4 7.6 2 10c-7.3 1.4-16-2-22.7-4.7c-1.1-.4-2.2-.9-3.3-1.3c-.4 .1-.4 .1-2 1c-14.9-3-28.1-16-39-26c-1.3 5.2 3.1 11.6 5.5 16c-1.9 9.5-11.4 17.4-19 22.5c-10.2 5.4-20.5 7.6-32 9c3.1 3.1 8.4 3.4 12.5 4.5c6.2 2.1 8.1 4.1 11 10c.5 4.5 .5 4.5-1 8c-1.3 .8-2.6 1.6-4 2.5c-.5-.1-1-.4-1.5-.5c-.4-2-.6-3.9-1-6c-.4-.8-.6-1.6-1-2.5c-1-.1-2-.4-3-.5c.4 1 .6 2 1 3c0 3.5 0 3.5-1.5 7c-3.9 2.6-9.1 2-13.5 2c-.6-.1-1.3-.4-2-.5c-.5-2-1-3.9-1.5-6c-.5-.8-1-1.6-1.5-2.5c0-.4 0-.6 0-1c-.5 0-1 0-1.5 0c-.1 2.1-.4 4.3-.5 6.5c-.4 .8-.6 1.6-1 2.5c-5.5 2.2-11.6-.4-17-2c-7.4-5.2-10.6-9.4-12.5-18c0-4.7 .1-9.3 .5-14c-.5 0-1 0-1.5 0c-.4 .6-.4 .6-2.5 4c-.4 0-.6 0-1 0c-.4 .8-.6 1.6-1 2.5c-.6 1.2-1.3 2.4-2 3.7c-1.9 4-2.6 6.9-3 11.3c-.1 0-.4 0-.5 0c-.4-1.5-.6-2.9-1-4.5c-3-3.5-3-3.5-4-4.5c.4 0 .6 0 1 0c.1-1.1 .4-2.3 .5-3.5c.4 0 .6 0 1 0c.4-1 .6-2 1-3c2.2-4.2 4.6-7.7 7.5-11.5c.5-2.6 1-5.4 1.5-8c5-12.6 12.4-23.1 21-33.5c2.8-3.4 5.4-6.9 8-10.5c-3.8-.9-7.8 1-11.5 2c-1.6 .1-3.3 .4-5 .5c0-.6 0-1.3 0-2c1.3-1.1 2.6-2.3 4-3.5c7.9-8.1 13.4-17.6 18-28c-.3-.1-.3-.1-1.5-.5c1.8-12.7 10.6-21.6 20.1-29.4c8.2-5.9 20.1-13.1 30.4-13.1zM476 422.5c-.4 .8-.6 1.6-1 2.5c-.4 .4-.6 .6-1 1c.5 2.5 .5 2.5 1.5 4c1 0 2 0 3 0c0-.5 0-1 0-1.5c.1-.1 .4-.4 .5-.5c.6 .4 1.3 .6 2 1c-1-2.5-1-2.5-4-6.5c-.4 0-.6 0-1 0zM660.5 353.5c2 1 2 1 5 5c-2.1 3.5-5.2 5.1-8.5 7.5c-.1 .5-.4 1-.5 1.5c1 .6 1.9 1.2 2.9 1.8c3.1 2.2 3.1 2.2 5.6 5.2c-2 4-2 4-3 5c-6-1.5-12.3-7-17-11c1-5.8 7-8.7 11.5-12c1.3-1 2.6-2 4-3zM686 353.5c5.9 1.1 11.4 6.9 15.5 11c-.7 5.1-3.6 6.4-7.5 9.5c-.5 .4-.5 .4-3.1 2.6c-2.4 1.9-2.4 1.9-3.9 2.4c-1.4-1.4-2.6-2.6-4-4c.9-3.4 3.9-5.2 6.5-7.5c.6-.6 1.3-1.3 2-2c-.6-.4-1.3-.6-2-1c-5.9-4.1-5.9-4.1-7-6.5c1.5-2.5 1.5-2.5 3.5-4.5zM579 360c2 .5 2 .5 6.5 4.5c2 1.5 4 3 6 4.5c.9 .6 1.6 1.3 2.5 1.9c4.6 3.5 9.4 6.7 14.2 9.9c1.8 1.3 3.7 2.5 5.6 3.8c4.1 2.6 8.1 5 12.2 7.4c.8 .6 1.6 1.3 2.5 2c2.5 1.5 5 3 7.5 4.5c6.6 4.2 13.1 8.4 19.5 13c.8 .6 .8 .6 4.9 3.3c3.7 2.6 7.1 5.3 10.6 8.2c3.2 2.6 3.2 2.6 6 4.5c6-2 11-6.6 15.5-11c.6-.4 1.3-.6 2-1c.4-.6 .6-1.3 1-2c.4-.4 .4-.4 2-2c.4 0 .6 0 1 0c.4-.6 .6-1.3 1-2c.8-1 1.6-2 2.5-3c.4 0 .6 0 1 0c.4-.8 .6-1.6 1-2.5c1.5-1.6 3-3.3 4.5-5c1.1-1.8 2.3-3.6 3.5-5.5c1-1.4 1.9-2.9 2.9-4.4c4.6-7.2 7.3-14.8 9.6-23.1c3.5 1.7 4.4 5.6 6 9c1.5 2.5 3 5 4.5 7.5c5.4 9.9 5.4 9.9 7 13c.5 .4 1 .6 1.5 1c-1.3 1.1-2.6 2.3-4 3.5c-.4 .9-.4 .9-2 5.5c-.1 0-.4 0-.5 0c-.1-1.5-.4-2.9-.5-4.5c-2-6.4-4.3-11.6-7.5-17.5c-.5-.1-1-.4-1.5-.5c.1 .4 .4 .6 .5 1c1.4 23.4-1.7 45.9-17 64.5c-1.1 1.1-2.3 2.3-3.5 3.5c-.1 0-.4 0-.5 0c.1-1.1 .4-2.3 .5-3.5c.9-6.9 1.7-13.6 1.5-20.5c-1.5 1.5-1.5 1.5-3.1 6c-5 13.5-14.3 24.7-25.9 33c-.6 .5-1.3 1-2 1.5c-.5 0-1 0-1.5 0c-1.1-1.6-2.3-3.3-3.5-5c-4-4.5-7.8-8.4-12.6-12c-4.4-3.4-6-6.4-8.6-11.2c-2.3-4.3-2.3-4.3-5.8-9.3c0-.4 0-.6 0-1c-.4 .1-.4 .1-2 1c-.6 0-1.3 0-2 0c-2.5-2.5-2.5-2.5-3-3.5c-.6-.4-1.3-.6-2-1c-1.1-1-2.3-2-3.5-3c2.5 6.3 5.1 12.3 8.3 18.2c.6 1.1 1.1 2.2 1.7 3.3c-.1 .5-.4 1-.5 1.5c-1.2-.4-2.5-.8-3.7-1.3c-3.8-1.2-3.8-1.2-4.8-1.2c1.3 3.8 7 6.2 10.3 8.4c12.8 9.3 21.8 20.7 28.2 35.1c0 .4 0 .6 0 1c-1.5-.1-3-.4-4.5-.5c0 .5 0 1 0 1.5c3.1 2.4 6.3 4.7 9.5 7c7.2 6.4 10.8 12.6 12.5 22c-1.6 5-2.9 6.9-7 10.5c-1.5-1.5-1.5-1.5-2.5-6.5c-2.5-5-2.5-5-5-7.5c-.4 0-.6 0-1 0c.5 2.5 1.2 5 2 7.5c0 5.5 0 5.5-2 9.5c-5 2.5-5 2.5-10 3.5c-1.3 .4-2.6 .6-4 1c-1.8-.1-3.6-.4-5.5-.5c-1-1.5-1-1.5-1.5-6c-2-5-2-5-3.5-6.5c-.4 .1-.6 .4-1 .5c0 2.1 0 4.3 0 6.5c-1.5 3.5-1.5 3.5-4 5c-9 1.8-17.6-1.5-25.5-6c-4.2-3-7.7-5.5-11-9.5c-.8-.4-1.6-.6-2.5-1c.3 1.2 .6 2.4 1 3.6c.5 2.1 1 4.3 1.5 6.4c-.4 .1-.6 .4-1 .5c-15.7-7.7-24.2-21-30-37c-1.6-5.3-2.6-10.1-3.5-15.5c-.6 .1-1.3 .4-2 .5c-1.9 6.4-2.6 12-2.5 18.6c0 1.4 0 2.8 0 4.2c0 1.1 0 2.1 0 3.2c-8-4-13-13.3-16.5-21c-.7-2.3-1.4-4.6-2-7c-.4-1.1-.6-2.3-1-3.5c-1-11-.6-22.1 3.5-32.5c-.6-.1-1.3-.4-2-.5c-.4 .8-.6 1.6-1 2.5c-.5 .7-.5 .7-3 4.5c-1.9 4.3-3.8 8.6-5.5 13c-.5 .1-1 .4-1.5 .5c0-4.6 .1-8.9 .5-13.5c0-1.2 0-2.4-.1-3.7c.4-19.4 5.6-36.9 19.6-50.8c2.5-2 2.5-2 6-3c-.5 4-.5 4-2 9c2-1 2-1 5.5-5c.8-.8 1.6-1.6 2.5-2.5c.8-1 1.6-2 2.5-3c4-1.5 4-1.5 6.5-2c-.7-3.1-1.4-6.1-2-9.1c-1-5.5-1.1-10.4-1-15.9zM722 380.5c-1.5 1.5-1.5 1.5-3.5 5c.1 .5 .4 1 .5 1.5c.4 .1 .4 .1 2 .5c.4 .5 .4 .5 2 3c1.1-.4 2.3-.6 3.5-1c-.1-.6-.4-1.3-.5-2c0-1 0-1 .5-2.5c-1.5-3.5-1.5-3.5-3-4.5c-.5 0-1 0-1.5 0zM709.5 400c-.5 .5-1 1-1.5 1.5c.1 .5 .4 1 .5 1.5c1-.4 2-.6 3-1c-.4-.6-.6-1.3-1-2c-.4 0-.6 0-1 0zM714.5 428.5c-.6 .6-1.3 1.3-2 2c-.4 0-.6 0-1 0c.1 .6 .4 1.3 .5 2c.4-.1 .6-.4 1-.5c.4 1.1 .6 2.3 1 3.5c2.5 .5 2.5 .5 4 0c.4-1 .6-2 1-3c-1.1-1.3-2.3-2.6-3.5-4c-.4 0-.6 0-1 0z"/><path fill="#03B5BD" d="M569 311.5c3.5 2 3.5 2 7 4.5c4.8 2.3 9.6 4.4 14.5 6.5c1.1 .5 2.3 1 3.5 1.5c28 9.3 28 9.3 42.6 9c4 0 7.5 .9 11.4 2c8.4 1.4 16.6 1.2 25 .5c1.8 0 3.6 0 5.5 0c9.7-.8 19.1-3.5 28-7.5c3.5-1.1 7-2.1 10.5-3c0 10.4-6.5 17.6-12.5 25.5c4.8-2.6 8.6-5.1 12.5-9c.6 0 1.3 0 2 0c0 13-4.1 24.7-10.5 36c-.7 1.4-1.5 2.7-2.2 4.1c-6.8 11.4-16.3 21.3-25.8 30.4c-.8 .1-1.6 .4-2.5 .5c-2.9-2.1-5.7-4.3-8.5-6.5c-5.3-3.8-10.6-7.4-16-11c-1.5-1-3-2-4.5-3c-5.8-3.8-11.6-7.4-17.5-11c-4.3-2.6-8.4-5.2-12.5-8c-1.3-.8-2.6-1.6-4-2.4c-6.4-4.1-12.5-8.5-18.5-13.1c-1-.8-2.1-1.6-3.2-2.4c-12.3-9.6-24-20.3-32.3-33.6c1-2.5 1-2.5 2.5-4c.4 0 .6 0 1 0c.4-.6 .6-1.3 1-2c2.5-3.5 2.5-3.5 3.5-4zM677.5 348c-4 6.8-6 15.1-8.5 22.5c-.8 2.1-1.5 4.2-2.2 6.4c-1.3 4.1-1.3 4.1-.3 6.1c1.5 .1 3 .4 4.5 .5c2.1-3.6 3.1-7.4 4.4-11.3c1.6-5.3 3.4-10.6 5.1-15.9c1-3.3 1-3.3 1.5-6.8c-1.5-.5-3-1-4.5-1.5zM647 365c-.4 .5-.6 1-1 1.5c1 4.7 6.5 6.6 10.2 9.3c1.4 .8 2.8 1.8 4.3 2.7c.4-.1 .4-.1 2-.5c.5-1.3 1-2.6 1.5-4c-2.8-2.3-5.6-4.4-8.5-6.5c0-.5 0-1 0-1.5c2.8-2.1 5.6-4.1 8.5-6c.1-.5 .4-1 .5-1.5c-1-1.3-2-2.6-3-4c-4 0-11.5 8.1-14.5 10.5zM686 354.5c-2 2-2 2-2.5 4c2.5 2.5 2.5 2.5 5.6 4.8c2.9 2.2 2.9 2.2 3.4 3.7c-.4 .1-.4 .1-2 1c-5 4-5 4-6.5 5.5c.5 2 .5 2 3 4.5c3.5-1.7 6.1-4.5 9-7c1.3-1 2.6-2 4-3c.1-1.1 .4-2.3 .5-3.5c-11.3-10-11.3-10-14.5-10z"/><g id="face-lights" fill="#FAF9F8"><circle cx="628.3" cy="198" r="3.4"/><circle cx="714.2" cy="182.6" r="3"/><ellipse cx="692.6" cy="201.6" rx="4.2" ry="1.6" transform="rotate(-12 692.6 201.6)"/></g><path fill="#03B5BD" d="M640 345H706L700 388L645 390Z"/><path d="M660.5 356.5L648 366L660.5 375.5M680.5 350.5L669 382.5M685.5 356.5L698.5 365.5L686 375" fill="none" stroke="#FAF9F8" stroke-width="4.6" stroke-linecap="round" stroke-linejoin="round"/></g><g id="face-lights" fill="#FAF9F8"><circle cx="628.3" cy="198" r="3.4"/><circle cx="714.2" cy="182.6" r="3"/><ellipse cx="692.6" cy="201.6" rx="4.2" ry="1.6" transform="rotate(-12 692.6 201.6)"/></g></g></svg><g stroke="#21BEC5"><path d="M19.4 1.9a2.6 2.6 0 0 1 0 3.6"/><path d="M21.3 0.6a4.4 4.4 0 0 1 0 6.2"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-1.292 -1.073) scale(1.058)" stroke-width="1.655"><path fill="#21BEC5" opacity=".85" d="M4.6 14.5h14.8l-1.1 4.5H5.7z"/><g stroke="#E6EDF3"><path d="M2.5 11.5h19l-2.3 8H4.8z"/><path d="M9 8.5c0-1 .8-1.5 1.5-1h3c.7-.5 1.5 0 1.5 1s-.8 1.5-1.5 1h-3c-.7.5-1.5 0-1.5-1z"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-2.489 -0.233) scale(1.111)" stroke-width="1.575"><g stroke="#E6EDF3"><path d="M12 3v18"/><path d="M9 21h6"/><path d="M12 5H5.5L3.5 7l2 2H12"/></g><path stroke="#21BEC5" d="M12 11h6.5l2 2-2 2H12"/></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-2.562 1.465) scale(1.058)" stroke-width="1.655"><g stroke="#E6EDF3"><path d="M4 10a8 8 0 0 0 10 10z"/><path d="M9 15l3.5-3.5"/><path d="M7.5 20.5h5"/></g><circle fill="#E6EDF3" cx="13" cy="11" r="1.2"/><g stroke="#21BEC5"><path d="M15.5 4.5a4 4 0 0 1 4 4"/><path d="M15.5 1.5a7 7 0 0 1 7 7"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-1.726 0.346) scale(1.063)" stroke-width="1.647"><g stroke="#21BEC5"><path d="M5.8 12C11 12 12.5 5 18.2 5"/><path d="M5.8 12H18.2"/><path d="M5.8 12C11 12 12.5 19 18.2 19"/></g><circle fill="#E6EDF3" cx="4" cy="12" r="2"/><g stroke="#E6EDF3"><circle cx="20" cy="5" r="1.8"/><circle cx="20" cy="12" r="1.8"/><circle cx="20" cy="19" r="1.8"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 52.37" width="28" height="48" fill="none" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-5.267 -0.233) scale(1.111)" stroke-width="1.575"><g stroke="#E6EDF3"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/><path d="M9 11h6"/></g><path stroke="#21BEC5" d="M9 16l2 2 4-4"/></g></svg>