jackherd 1.7.1 → 1.8.1
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/CHANGELOG.md +47 -0
- package/INSTALL.md +2 -0
- package/{NOTICE → NOTICE.txt} +1 -1
- package/README.md +86 -1037
- package/assets/branding/README.md +5 -7
- package/assets/branding/jackherd-logo-outline.svg +1 -0
- package/assets/branding/outline.test.ts +30 -0
- package/assets/icons/bark.svg +1 -1
- package/assets/icons/bowl.svg +1 -1
- package/assets/icons/decide.svg +1 -1
- package/assets/icons/ear.svg +1 -1
- package/assets/icons/lanes.svg +1 -1
- package/assets/icons/plan.svg +1 -1
- package/dist/{chunk-OBUWTQ6Z.js → chunk-OU2KALXP.js} +26 -10
- package/dist/config.d.ts +11 -5
- package/dist/config.js +53 -21
- package/dist/plan-format.d.ts +75 -7
- package/dist/plan-format.js +180 -100
- package/docs/workflow-dark.svg +1 -1
- package/docs/workflow.svg +1 -1
- package/herdr-plugin/herdr-plugin.toml +1 -1
- package/install.sh +1 -1
- package/kit/hooks/hooks/approval-gate/herdr-panes.ts +2 -12
- package/kit/hooks/hooks/approval-gate/index.ts +10 -8
- package/kit/hooks/hooks/approval-gate/run.ts +21 -12
- package/kit/hooks/hooks/ask-hint/decision.ts +3 -3
- package/kit/hooks/hooks/git-guard/decision.ts +189 -15
- package/kit/hooks/hooks/git-guard/index.ts +13 -3
- package/kit/hooks/hooks/git-guard/push-target.ts +85 -0
- package/kit/hooks/hooks/git-guard/repository.ts +63 -0
- package/kit/hooks/hooks/merge-guard/check-free.ts +1 -13
- package/kit/hooks/hooks/merge-guard/decision.ts +344 -102
- package/kit/hooks/hooks/merge-guard/index.ts +6 -4
- package/kit/hooks/hooks/merge-guard/plain-path.ts +15 -0
- package/kit/hooks/hooks/merge-guard/plan-approval-record.ts +23 -0
- package/kit/hooks/hooks/merge-guard/plan-approval-settings.ts +142 -0
- package/kit/hooks/hooks/merge-guard/plan-approval-sources.ts +196 -0
- package/kit/hooks/hooks/merge-guard/plan-approval.ts +168 -0
- package/kit/hooks/hooks/merge-guard/plan-growth.ts +40 -0
- package/kit/hooks/hooks/merge-guard/plan-pointers.ts +194 -0
- package/kit/hooks/hooks/merge-guard/pull-request.ts +67 -21
- package/kit/hooks/hooks/merge-guard/run.ts +118 -29
- package/kit/hooks/hooks/merge-guard/settings.ts +8 -8
- package/kit/hooks/hooks/merge-guard/worker.ts +3 -3
- package/kit/hooks/hooks/merge-guard/xargs-program.ts +182 -0
- package/kit/hooks/hooks/shared/base-branch.ts +23 -0
- package/kit/hooks/hooks/shared/board-lanes.ts +93 -0
- package/kit/hooks/hooks/shared/command-text-runners.ts +71 -0
- package/kit/hooks/hooks/shared/command.ts +14 -2
- package/kit/hooks/hooks/shared/commit.ts +2 -0
- package/kit/hooks/hooks/shared/dialog-answers.ts +4 -1
- package/kit/hooks/hooks/shared/json.ts +10 -0
- package/kit/hooks/hooks/shared/lane.ts +57 -0
- package/kit/hooks/hooks/shared/once.ts +8 -0
- package/kit/hooks/hooks/shared/own-pane.ts +31 -0
- package/kit/hooks/hooks/shared/pane-agent.ts +24 -0
- package/kit/hooks/hooks/shared/plan-open-phases.ts +114 -0
- package/kit/hooks/hooks/shared/program-position.ts +148 -5
- package/kit/hooks/hooks/shared/shell-aliases.ts +258 -0
- package/kit/hooks/hooks/shared/shell-snapshots.ts +68 -0
- package/kit/hooks/hooks/shared/shell.ts +167 -20
- package/kit/hooks/hooks.json +11 -2
- package/kit/hooks/statusline.sh +29 -16
- package/kit/review/skills/diagnose/SKILL.md +1 -1
- package/kit/review/skills/review/SKILL.md +2 -0
- package/kit/rules/rules/kit/testing.md +2 -5
- package/kit/rules/rules/kit/writing-for-agents.md +3 -1
- package/kit/workflow/agents/spec-review.md +1 -1
- package/kit/workflow/skills/follow/SKILL.md +3 -3
- package/kit/workflow/skills/grill/SKILL.md +1 -1
- package/kit/workflow/skills/implement/SKILL.md +10 -11
- package/kit/workflow/skills/orchestrate/SKILL.md +156 -117
- package/kit/workflow/skills/orchestrate/references/coordinator-handover.md +17 -0
- package/kit/workflow/skills/orchestrate/references/herd.md +27 -0
- package/kit/workflow/skills/orchestrate/references/plan-commit.md +22 -0
- package/kit/workflow/skills/orchestrate/references/sensitive-input.md +23 -0
- package/kit/workflow/skills/plan/SKILL.md +5 -2
- package/kit/workflow/skills/plan/references/template-English.md +6 -0
- package/kit/workflow/skills/plan/references/template-German.md +6 -0
- package/package.json +4 -2
- package/recipes/README.md +21 -0
- package/recipes/github-issues.md +23 -0
- package/recipes/github-projects.md +22 -0
- package/recipes/jira-cli.md +26 -0
- package/recipes/jira-rest.md +24 -0
- package/recipes/linear.md +25 -0
- package/recipes/sentry.md +18 -0
- package/recipes/sources/jira.ts +51 -0
- package/recipes/sources/linear.ts +19 -0
- package/recipes/sources/sentry.ts +12 -0
- package/recipes/sources.md +80 -0
- package/recipes/status-page.md +19 -0
- package/schemas/jackherd.schema.json +42 -18
- package/src/check/command.ts +2 -2
- package/src/check/parallel-report.ts +19 -9
- package/src/cli.ts +1 -0
- package/src/config/context-shares.ts +130 -0
- package/src/config/read-config.ts +16 -4
- package/src/config/schema.ts +75 -20
- package/src/context/auto-compact.ts +68 -0
- package/src/context/command.ts +68 -17
- package/src/context/coordinator-name.ts +27 -9
- package/src/context/index.ts +0 -1
- package/src/context/level.ts +18 -11
- package/src/context/report.ts +6 -3
- package/src/plan-format/dependencies.ts +144 -32
- package/src/plan-format/index.ts +6 -0
- package/src/plan-format/lanes.ts +6 -0
- package/src/plan-format/progress.ts +19 -8
- package/src/plans/command.ts +14 -5
- package/src/plans/current-phase.ts +63 -7
- package/src/plans/current-task.ts +51 -0
- package/src/plans/ensure-panes.ts +25 -8
- package/src/plans/frame.ts +99 -0
- package/src/plans/git.ts +8 -0
- package/src/plans/herd-memory.ts +107 -0
- package/src/plans/lane-plans.ts +5 -3
- package/src/plans/lane-standing.ts +5 -4
- package/src/plans/lane-summary.ts +222 -0
- package/src/plans/layout-phase.ts +148 -0
- package/src/plans/layout-summary.ts +140 -0
- package/src/plans/layout.ts +164 -420
- package/src/plans/live.ts +11 -6
- package/src/plans/plan-panes.ts +15 -0
- package/src/plans/planned.ts +9 -42
- package/src/plans/selection.ts +2 -6
- package/src/plans/settings.ts +2 -7
- package/src/plans/snapshot.ts +38 -39
- package/src/plans/symbols.ts +2 -2
- package/src/plans/texts.ts +32 -31
- package/src/plans/view.ts +0 -1
- package/src/plans/worked-phases.ts +2 -2
- package/src/settled/board-row.ts +133 -0
- package/src/settled/check.ts +129 -0
- package/src/settled/command.ts +65 -0
- package/src/settled/evidence-version.ts +14 -0
- package/src/settled/options.ts +69 -0
- package/src/settled/send.ts +27 -0
- package/src/settled/settle.ts +87 -0
- package/src/settled/topics.ts +56 -0
- package/src/sync/render.ts +13 -4
- package/src/sync/sync.ts +25 -5
- package/src/terminal/herdr.ts +46 -10
- package/src/terminal/none.ts +1 -0
- package/src/terminal/types.ts +15 -2
- package/src/update/command.ts +2 -0
- package/src/update/config-shares.ts +30 -0
- package/src/update/update.ts +12 -1
- package/src/vocabulary/index.ts +51 -11
- package/src/watch/appointments.ts +206 -0
- package/src/watch/command.ts +62 -19
- package/src/watch/lane-report.ts +11 -3
- package/src/watch/texts.ts +35 -59
- package/src/watch/watch-events.ts +21 -28
- package/assets/icons/bark-dark.svg +0 -1
- package/assets/icons/bowl-dark.svg +0 -1
- package/assets/icons/decide-dark.svg +0 -1
- package/assets/icons/ear-dark.svg +0 -1
- package/assets/icons/lanes-dark.svg +0 -1
- package/assets/icons/plan-dark.svg +0 -1
- package/kit/hooks/hooks/approval-gate/lane.ts +0 -14
package/src/watch/command.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* lane's new head commit (only with `watch.previews`), a new or changed entry of a configured source or its failure (only
|
|
6
6
|
* with `watch.sources`), a gh outage, a lane's or the coordinator's own context fill rising to warn or alert, or the
|
|
7
7
|
* heartbeat. A blocked lane adds one duty line, a merge one per lane, a lane at alert one, and every report ends with one status line
|
|
8
|
-
* per lane and one for the coordinator, in
|
|
8
|
+
* per lane and one for the coordinator, in English. When the installed kit changes version
|
|
9
9
|
* it prints `=== kit updated <old> → <new>` and ends; once a day it asks npm and prints `=== update available <old> → <new>`
|
|
10
10
|
* for a newer release, once per version. The coordinator is the agent in the
|
|
11
|
-
* watcher's own herdr pane unless `--coordinator` names it, else `orchestrator-<repository
|
|
11
|
+
* watcher's own herdr pane unless `--coordinator` names it, else `jack-<repository>` (or the old `orchestrator-<repository>`). A new start replaces a running watcher of the same
|
|
12
12
|
* repository; one in another repository keeps running.
|
|
13
13
|
*
|
|
14
14
|
* Without `--stream` it exits after one report, whose last line says so and points to the stream: that run is the
|
|
@@ -31,7 +31,7 @@ import { homedir } from 'node:os'
|
|
|
31
31
|
import { basename, dirname, join, relative } from 'node:path'
|
|
32
32
|
import { readResolvedConfig } from '../config/read-config'
|
|
33
33
|
import type { JackherdConfig } from '../config/schema'
|
|
34
|
-
import {
|
|
34
|
+
import { resolveCoordinatorName } from '../context/coordinator-name'
|
|
35
35
|
import { coordinatorSettings } from '../context/options'
|
|
36
36
|
import { contextReport } from '../context/report'
|
|
37
37
|
import { agentLog } from '../context/session-log'
|
|
@@ -42,12 +42,19 @@ import { ensurePlanPanes } from '../plans/ensure-panes'
|
|
|
42
42
|
import { errorText } from '../plans/error-text'
|
|
43
43
|
import { mainCheckout, worktreeNames, worktreeRoot } from '../plans/git'
|
|
44
44
|
import { discoverLanes, isUnchanged, laneSetChange, laneSetLines } from '../plans/lane-discovery'
|
|
45
|
-
import {
|
|
45
|
+
import { CLOCK_LOCALE, type PlansSettings, plansSettingsOf, worktreeOf } from '../plans/settings'
|
|
46
46
|
import { boardTexts } from '../plans/texts'
|
|
47
47
|
import { defaultUpdateCheck } from '../sync/if-changed'
|
|
48
48
|
import { herdrLaneStatusSource } from '../terminal/herdr'
|
|
49
49
|
import { AGENT_STATUS } from '../terminal/types'
|
|
50
50
|
import { startedKit } from '../version/started-kit'
|
|
51
|
+
import {
|
|
52
|
+
type AppointmentTable,
|
|
53
|
+
appointmentEvents,
|
|
54
|
+
isAppointmentEvent,
|
|
55
|
+
readAppointmentTable,
|
|
56
|
+
recordAppointments,
|
|
57
|
+
} from './appointments'
|
|
51
58
|
import { type ApprovalRequestFile, approvalEvents, readApprovalRequests, recordApprovals } from './approvals'
|
|
52
59
|
import {
|
|
53
60
|
type CoordinatorRead,
|
|
@@ -81,6 +88,7 @@ import { type LaneModelReading, laneModelEvents, recordLaneModels } from './lane
|
|
|
81
88
|
import { laneParallelEvents, recordLaneParallels } from './lane-parallel'
|
|
82
89
|
import { boardCheckoutRows, watchedLaneParallel, watchedLaneProgress } from './lane-progress'
|
|
83
90
|
import {
|
|
91
|
+
appointmentEventLine,
|
|
84
92
|
approvalDutyLines,
|
|
85
93
|
armLine,
|
|
86
94
|
blockedDutyLines,
|
|
@@ -140,7 +148,7 @@ import { runSource, SOURCE_LIMITS } from './source-run'
|
|
|
140
148
|
import { recordWatchedSources } from './source-tickets'
|
|
141
149
|
import { isSourceDue, type SourceRun, type SourceSettings, type SourceState, sourceEvents } from './sources'
|
|
142
150
|
import { streamHeartbeatLine } from './stream-output'
|
|
143
|
-
import {
|
|
151
|
+
import { type WatchTexts, watchTexts } from './texts'
|
|
144
152
|
import { updateAnnouncer } from './update-available'
|
|
145
153
|
import {
|
|
146
154
|
coordinatorWatchEvent,
|
|
@@ -254,6 +262,8 @@ type Watching = {
|
|
|
254
262
|
laneParallelReadings: Record<string, string[]>
|
|
255
263
|
/** The approval requests of the last poll; null before the first read, so the stored ids stay. */
|
|
256
264
|
approvalRequests: ApprovalRequestFile[] | null
|
|
265
|
+
/** The board's appointment table at the last poll and the time it was read at; null before the first read and while the board cannot be read. */
|
|
266
|
+
appointments: { table: AppointmentTable; readAt: number } | null
|
|
257
267
|
planViews: PlanViews
|
|
258
268
|
}
|
|
259
269
|
|
|
@@ -262,8 +272,7 @@ const GITHUB_POLL_MS = 60_000
|
|
|
262
272
|
const MINUTE_MS = 60_000
|
|
263
273
|
const USAGE_EXIT = 2
|
|
264
274
|
|
|
265
|
-
const clock = (
|
|
266
|
-
new Date(epochMs).toLocaleTimeString(clockLocaleOf(watch.settings))
|
|
275
|
+
const clock = (epochMs: number): string => new Date(epochMs).toLocaleTimeString(CLOCK_LOCALE)
|
|
267
276
|
|
|
268
277
|
const agentNamesOf = (agents: readonly HerdrAgent[]): string[] => agents.flatMap((agent) => agent.name ?? [])
|
|
269
278
|
|
|
@@ -292,6 +301,9 @@ const recordedOf = (watch: Watch, watching: Watching): WatchState => {
|
|
|
292
301
|
laneParallels: recordLaneParallels(withReads.laneParallels, watching.laneParallelReadings, watching.lanes),
|
|
293
302
|
approvals: watching.approvalRequests ? recordApprovals(watching.approvalRequests) : withReads.approvals,
|
|
294
303
|
sources: recordWatchedSources(withReads.sources, watching.sourceRuns, watch.sources, watching.githubReadAt),
|
|
304
|
+
appointments: watching.appointments
|
|
305
|
+
? recordAppointments(withReads.appointments, watching.appointments.table, watching.appointments.readAt)
|
|
306
|
+
: withReads.appointments,
|
|
295
307
|
}
|
|
296
308
|
return withReportBaselines(withLevels, watching.lanes, (lane) => reportMtime(reportPathOf(watch, lane)))
|
|
297
309
|
}
|
|
@@ -337,11 +349,14 @@ const stopMessageOf = (watch: Watch, lane: string, status: string, state: WatchS
|
|
|
337
349
|
reportedMtime: state.reportMtimes[lane] ?? null,
|
|
338
350
|
})
|
|
339
351
|
|
|
340
|
-
/**
|
|
352
|
+
/**
|
|
353
|
+
* `--coordinator` if given, else the agent in the watcher's own pane, else `jack-<repository>`, or the old
|
|
354
|
+
* `orchestrator-<repository>` while only that one runs.
|
|
355
|
+
*/
|
|
341
356
|
const coordinatorNameFor = (watch: Watch, agents: readonly HerdrAgent[]): string =>
|
|
342
357
|
watch.options.coordinator ??
|
|
343
358
|
coordinatorNameOf(agents, process.env.HERDR_PANE_ID) ??
|
|
344
|
-
|
|
359
|
+
resolveCoordinatorName(basename(watch.root), agentNamesOf(agents))
|
|
345
360
|
|
|
346
361
|
/**
|
|
347
362
|
* One read of the fills: the coordinator's, and each watched lane's (null without a value), with `models`, lane → the
|
|
@@ -402,6 +417,10 @@ const eventLinesOf = async (
|
|
|
402
417
|
lines.push(...sourceEventLines(event))
|
|
403
418
|
continue
|
|
404
419
|
}
|
|
420
|
+
if (isAppointmentEvent(event)) {
|
|
421
|
+
lines.push(appointmentEventLine(event))
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
405
424
|
const headSha = event.kind === WATCH_EVENT.deploy ? runs.find((run) => run.id === event.runId)?.headSha : undefined
|
|
406
425
|
const target =
|
|
407
426
|
event.kind === WATCH_EVENT.deploy && headSha && watch.deploy
|
|
@@ -483,20 +502,20 @@ const statusLinesOf = async (
|
|
|
483
502
|
const laneLines = watching.lanes.map((lane) =>
|
|
484
503
|
laneReportLine(laneReportOf(lane, watching, state, pullRequests, progress[lane] ?? null), watch.texts),
|
|
485
504
|
)
|
|
486
|
-
const outage = state.ghDownSince === null ? [] : [ghUnavailableStatusLine(clock(
|
|
505
|
+
const outage = state.ghDownSince === null ? [] : [ghUnavailableStatusLine(clock(state.ghDownSince))]
|
|
487
506
|
const board = { term: watch.settings.board.term, checkoutRows }
|
|
488
507
|
const coordinator = coordinatorStatusLine(watching.coordinator.name, watching.coordinator.read, watch.texts, board)
|
|
489
508
|
return {
|
|
490
509
|
laneLines,
|
|
491
510
|
coordinator,
|
|
492
511
|
others: others === null ? [] : [others],
|
|
493
|
-
rest: [...notes, ...outage, ...failingSourceLines(
|
|
512
|
+
rest: [...notes, ...outage, ...failingSourceLines(state.sources)],
|
|
494
513
|
}
|
|
495
514
|
}
|
|
496
515
|
|
|
497
|
-
const failingSourceLines = (
|
|
516
|
+
const failingSourceLines = (sources: SourceState): string[] =>
|
|
498
517
|
Object.entries(sources).flatMap(([name, { failingSince }]) =>
|
|
499
|
-
failingSince === null ? [] : [sourceFailingStatusLine(name, clock(
|
|
518
|
+
failingSince === null ? [] : [sourceFailingStatusLine(name, clock(failingSince))],
|
|
500
519
|
)
|
|
501
520
|
|
|
502
521
|
/** The section of each stopped lane (its header and message) and the report times it leaves behind. */
|
|
@@ -775,15 +794,31 @@ const pollGithubAndCoordinator = async (watch: Watch, watching: Watching, now: n
|
|
|
775
794
|
]
|
|
776
795
|
}
|
|
777
796
|
|
|
778
|
-
/** The board's
|
|
779
|
-
const
|
|
797
|
+
/** The board's text, null when it cannot be read; parsing it is the caller's, so a parser error is not taken for an unreadable board. */
|
|
798
|
+
const readBoardText = (watch: Watch): string | null => {
|
|
780
799
|
try {
|
|
781
|
-
return
|
|
800
|
+
return readFileSync(watch.sprintFile, 'utf8')
|
|
782
801
|
} catch {
|
|
783
802
|
return null
|
|
784
803
|
}
|
|
785
804
|
}
|
|
786
805
|
|
|
806
|
+
/**
|
|
807
|
+
* The board's appointment table at `now`, in the plan language, and when it was read; null when the board cannot be
|
|
808
|
+
* read, so the reported appointments stay as they were.
|
|
809
|
+
*/
|
|
810
|
+
const readAppointments = (watch: Watch, now: number): Watching['appointments'] => {
|
|
811
|
+
const board = readBoardText(watch)
|
|
812
|
+
if (board === null) return null
|
|
813
|
+
return { table: readAppointmentTable(board, watch.settings.planLanguage, new Date(now)), readAt: now }
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/** The board's lanes, null when the board cannot be read. */
|
|
817
|
+
const readSprintLanes = (watch: Watch): SprintLane[] | null => {
|
|
818
|
+
const board = readBoardText(watch)
|
|
819
|
+
return board === null ? null : parseSprintLanes(board, watch.settings.planLanguage)
|
|
820
|
+
}
|
|
821
|
+
|
|
787
822
|
/** The sprint's lane names; the previous ones when the sprint cannot be read, so no lane drops out over it. */
|
|
788
823
|
const sprintLaneNames = (watch: Watch, previous: string[]): string[] =>
|
|
789
824
|
readSprintLanes(watch)?.map((lane) => lane.name) ?? previous
|
|
@@ -872,7 +907,7 @@ const printStreamHeartbeat = async (watch: Watch, watching: Watching, now: numbe
|
|
|
872
907
|
const counts = currentPhaseCountsOf(progress)
|
|
873
908
|
const notes = progressNotes(watching.lanes, watching.current, counts, watching.heartbeatCounts)
|
|
874
909
|
watching.heartbeatCounts = { ...watching.heartbeatCounts, ...counts }
|
|
875
|
-
console.log(streamHeartbeatLine(clock(
|
|
910
|
+
console.log(streamHeartbeatLine(clock(now), watching.lanes, watching.current, notes))
|
|
876
911
|
}
|
|
877
912
|
|
|
878
913
|
/**
|
|
@@ -889,7 +924,14 @@ const pollOnce = async (watch: Watch, watching: Watching): Promise<boolean> => {
|
|
|
889
924
|
// read at every poll, not with GitHub: a lane waits for the answer only minutes; after the await, so a state saved
|
|
890
925
|
// during the GitHub read records no request as seen before it was reported
|
|
891
926
|
watching.approvalRequests = readApprovalRequests(watch.root)
|
|
892
|
-
|
|
927
|
+
// read at every poll like the approvals; the events and the record use the same read and time, so an appointment
|
|
928
|
+
// that falls due between the two is neither recorded unreported nor reported twice
|
|
929
|
+
watching.appointments = readAppointments(watch, now)
|
|
930
|
+
const polledEvents = [
|
|
931
|
+
...githubEvents,
|
|
932
|
+
...approvalEvents(watching.state.approvals, watching.approvalRequests, now),
|
|
933
|
+
...appointmentEvents(watching.state.appointments, watching.appointments?.table ?? null, now),
|
|
934
|
+
]
|
|
893
935
|
const stopped = [...firedLanes(watching.baseline, watching.current, watching.lanes), ...watching.departed]
|
|
894
936
|
watching.departed = []
|
|
895
937
|
const heartbeat = isHeartbeatDue(watching.quietSince, now, heartbeatMinutes * MINUTE_MS)
|
|
@@ -942,6 +984,7 @@ const initialWatching = (
|
|
|
942
984
|
laneModelReadings: {},
|
|
943
985
|
laneParallelReadings: {},
|
|
944
986
|
approvalRequests: null,
|
|
987
|
+
appointments: null,
|
|
945
988
|
planViews: { failureReported: false },
|
|
946
989
|
})
|
|
947
990
|
|
|
@@ -1007,7 +1050,7 @@ const watchOf = (options: WatchOptions): Watch => {
|
|
|
1007
1050
|
checks: config.watch.checks,
|
|
1008
1051
|
previews: config.watch.previews,
|
|
1009
1052
|
sources: config.watch.sources,
|
|
1010
|
-
texts:
|
|
1053
|
+
texts: watchTexts(settings.responseLanguage),
|
|
1011
1054
|
herdr: insideHerdr(settings.adapter, process.env),
|
|
1012
1055
|
}
|
|
1013
1056
|
}
|
package/src/watch/lane-report.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { currentPhase, isTickedUnmerged, type LaneProgress, phasesText } from '.
|
|
|
3
3
|
import { terminalSafe } from '../plan-format/terminal-text'
|
|
4
4
|
import { CHECK_NAME_LENGTH, type ChecksState } from '../plans/pull-requests'
|
|
5
5
|
import { shownWithMore } from '../plans/shown-with-more'
|
|
6
|
+
import type { AppointmentEvent } from './appointments'
|
|
6
7
|
import type { ApprovalEvent } from './approvals'
|
|
7
8
|
import type { CoordinatorRead } from './coordinator-fill'
|
|
8
9
|
import { type FeedbackEvent, firstLine } from './feedback'
|
|
@@ -74,8 +75,8 @@ const contextSegment = (level: ContextLevel | null): string[] =>
|
|
|
74
75
|
level === null || level === CONTEXT_LEVEL.ok ? [] : [`context ${level}`]
|
|
75
76
|
|
|
76
77
|
/**
|
|
77
|
-
* One line per lane, in the words of `texts`: `<lane> <status> [· context warn|alert] · <branch>|
|
|
78
|
-
* PR #<n> <checks>|
|
|
78
|
+
* One line per lane, in the words of `texts`: `<lane> <status> [· context warn|alert] · <branch>|no branch ·
|
|
79
|
+
* PR #<n> <checks>|no PR · open phase …|phase … ticked, not merged|plan finished|no plan`.
|
|
79
80
|
*/
|
|
80
81
|
export const laneReportLine = (report: LaneReport, texts: WatchTexts): string =>
|
|
81
82
|
[
|
|
@@ -158,6 +159,13 @@ export const watchEventLine = (event: WatchEvent, target: string | null): string
|
|
|
158
159
|
return `=== ${event.kind}`
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The line of an appointment event: `=== due <when> · <action>` for one that fell due, `=== appointment unreadable
|
|
164
|
+
* <when> · <action>` for an open row whose time cell could not be read. Both texts come from the board as written.
|
|
165
|
+
*/
|
|
166
|
+
export const appointmentEventLine = (event: AppointmentEvent): string =>
|
|
167
|
+
`=== ${event.kind} ${terminalSafe(event.when)} · ${terminalSafe(event.action).slice(0, REPORT_TEXT_LENGTH)}`
|
|
168
|
+
|
|
161
169
|
/**
|
|
162
170
|
* The lines of a feedback event: `=== feedback #<number> (lane) <author> <label> · <k> new`, then one line per entry,
|
|
163
171
|
* `<path>:<line> <first line>` or `<first line>`, cut to a length and to `FEEDBACK_ENTRY_LIMIT` entries.
|
|
@@ -230,7 +238,7 @@ const coordinatorValue = (name: string | null, read: CoordinatorRead | null, tex
|
|
|
230
238
|
}
|
|
231
239
|
|
|
232
240
|
/**
|
|
233
|
-
* `coordinator <name> 62 % warn`, `coordinator <name>
|
|
241
|
+
* `coordinator <name> 62 % warn`, `coordinator <name> no value (<reason>)` or `coordinator no name`;
|
|
234
242
|
* while the board has rows only in the checkout, `· board: 2 rows only in the checkout` follows.
|
|
235
243
|
*/
|
|
236
244
|
export const coordinatorStatusLine = (
|
package/src/watch/texts.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { APPROVAL_TEXTS,
|
|
1
|
+
import { APPROVAL_TEXTS, type PlanLanguage } from '../vocabulary'
|
|
2
2
|
|
|
3
|
-
/** The words of the watcher's status and duty lines
|
|
3
|
+
/** The words of the watcher's status and duty lines. */
|
|
4
4
|
export type WatchTexts = {
|
|
5
5
|
noBranch: string
|
|
6
6
|
noPullRequest: string
|
|
@@ -37,60 +37,36 @@ export type WatchTexts = {
|
|
|
37
37
|
/** The mark the approval gate hook reads from the question, as its `requestMark` writes it (contract test). */
|
|
38
38
|
const approvalMark = (id: string, hash: string): string => `\`approval ${id} ${hash}\``
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
phase: 'phase',
|
|
74
|
-
startsAfter: 'starts after',
|
|
75
|
-
planFinished: 'plan finished',
|
|
76
|
-
noPlan: 'no plan',
|
|
77
|
-
noName: 'no name',
|
|
78
|
-
noValue: 'no value',
|
|
79
|
-
unnamedPane: (name) => `pane without a name, herdr agent rename "$HERDR_PANE_ID" ${name}`,
|
|
80
|
-
noAgentNamed: (name) => `no agent named ${name}`,
|
|
81
|
-
afterMerge: (number) => `after merge #${number}`,
|
|
82
|
-
mergedLaneDuty: 'start the next phase or close the lane',
|
|
83
|
-
otherLaneDuty: 'rebase, then start the next phase or name the reason to wait',
|
|
84
|
-
blockedDuty:
|
|
85
|
-
'vet the question against the plan and the rules, answer it in the lane or ask the user in a dialog; never hand the pane over',
|
|
86
|
-
laneAlertDuty: 'request the hand-over at the next phase boundary (§ 8)',
|
|
87
|
-
approvalDuty: (id, hash) =>
|
|
88
|
-
`ask through AskUserQuestion, the question contains ${approvalMark(id, hash)} (hash as in the file shown), options "${APPROVAL_TEXTS.en.allow}" and "${APPROVAL_TEXTS.en.deny}" (§ 4)`,
|
|
89
|
-
parallelDuty: (phases) =>
|
|
90
|
-
`${phases} can run in parallel: propose it to the user, check content and release files yourself (the table covers paths and markers only)`,
|
|
91
|
-
laneModelDuty:
|
|
92
|
-
'switch it while idle: /exit, then claude --resume <session> --model <id> in the same pane (§ 2 step 6)',
|
|
93
|
-
checkoutRows: (term, count) => `${term}: ${count} ${count === 1 ? 'row' : 'rows'} only in the checkout`,
|
|
94
|
-
otherPullRequests: 'other PRs',
|
|
95
|
-
},
|
|
96
|
-
}
|
|
40
|
+
/**
|
|
41
|
+
* The watcher's words: English whatever the project's languages. Only the two option labels in the approval duty follow
|
|
42
|
+
* `dialogLanguage` (the config's `responseLanguage`), because the coordinator asks the user with them and the approval
|
|
43
|
+
* gate hook matches the answer against exactly those labels, as `jackherd sync` renders them into it.
|
|
44
|
+
*/
|
|
45
|
+
export const watchTexts = (dialogLanguage: PlanLanguage): WatchTexts => ({
|
|
46
|
+
noBranch: 'no branch',
|
|
47
|
+
noPullRequest: 'no PR',
|
|
48
|
+
openPhase: 'open phase',
|
|
49
|
+
tickedUnmerged: 'ticked, not merged',
|
|
50
|
+
phase: 'phase',
|
|
51
|
+
startsAfter: 'starts after',
|
|
52
|
+
planFinished: 'plan finished',
|
|
53
|
+
noPlan: 'no plan',
|
|
54
|
+
noName: 'no name',
|
|
55
|
+
noValue: 'no value',
|
|
56
|
+
unnamedPane: (name) => `pane without a name, herdr agent rename "$HERDR_PANE_ID" ${name}`,
|
|
57
|
+
noAgentNamed: (name) => `no agent named ${name}`,
|
|
58
|
+
afterMerge: (number) => `after merge #${number}`,
|
|
59
|
+
mergedLaneDuty: 'start the next phase or close the lane',
|
|
60
|
+
otherLaneDuty: 'rebase, then start the next phase or name the reason to wait',
|
|
61
|
+
blockedDuty:
|
|
62
|
+
'vet the question against the plan and the rules, answer it in the lane or ask the user in a dialog; never hand the pane over',
|
|
63
|
+
laneAlertDuty: 'request the hand-over at the next phase boundary (§ 8)',
|
|
64
|
+
parallelDuty: (phases) =>
|
|
65
|
+
`${phases} can run in parallel: propose it to the user, check content and release files yourself (the table covers paths and markers only)`,
|
|
66
|
+
laneModelDuty:
|
|
67
|
+
'switch it while idle: /exit, then claude --resume <session> --model <id> in the same pane (§ 2 step 6)',
|
|
68
|
+
checkoutRows: (term, count) => `${term}: ${count} ${count === 1 ? 'row' : 'rows'} only in the checkout`,
|
|
69
|
+
otherPullRequests: 'other PRs',
|
|
70
|
+
approvalDuty: (id, hash) =>
|
|
71
|
+
`ask through AskUserQuestion, the question contains ${approvalMark(id, hash)} (hash as in the file shown), options "${APPROVAL_TEXTS[dialogLanguage].allow}" and "${APPROVAL_TEXTS[dialogLanguage].deny}" (§ 4)`,
|
|
72
|
+
})
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { CHECKS, type ChecksState } from '../plans/pull-requests'
|
|
2
|
+
import {
|
|
3
|
+
APPOINTMENT_EVENT,
|
|
4
|
+
type AppointmentEvent,
|
|
5
|
+
type AppointmentState,
|
|
6
|
+
emptyAppointmentState,
|
|
7
|
+
isAppointmentState,
|
|
8
|
+
} from './appointments'
|
|
2
9
|
import { APPROVAL_EVENT, type ApprovalEvent } from './approvals'
|
|
3
10
|
import { type CoordinatorLevel, type CoordinatorReading, isContextLevel, levelStep } from './coordinator-fill'
|
|
4
11
|
import { emptyFailureState, type FailureState, failedTestsOf, isFailureState } from './failures'
|
|
@@ -29,6 +36,8 @@ export const WATCH_EVENT = {
|
|
|
29
36
|
laneParallel: LANE_PARALLEL_EVENT,
|
|
30
37
|
approval: APPROVAL_EVENT,
|
|
31
38
|
source: SOURCE_EVENT,
|
|
39
|
+
due: APPOINTMENT_EVENT.due,
|
|
40
|
+
appointmentUnreadable: APPOINTMENT_EVENT.unreadable,
|
|
32
41
|
} as const
|
|
33
42
|
|
|
34
43
|
export type PullRequestObservation = Omit<WatchedPullRequest, 'number' | 'branch' | 'failedRuns'>
|
|
@@ -85,6 +94,8 @@ export type WatchState = {
|
|
|
85
94
|
reportMtimes: Record<string, number | null>
|
|
86
95
|
/** The lane lines of the status block last printed; null before the first report. */
|
|
87
96
|
statusLines: string[] | null
|
|
97
|
+
/** The board's appointments reported as due and its unreadable appointment rows reported, each once (`appointments.ts`). */
|
|
98
|
+
appointments: AppointmentState
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
/** The kinds of the events a pull request fires. */
|
|
@@ -130,6 +141,7 @@ export type WatchEvent =
|
|
|
130
141
|
| LaneParallelEvent
|
|
131
142
|
| ApprovalEvent
|
|
132
143
|
| SourceEvent
|
|
144
|
+
| AppointmentEvent
|
|
133
145
|
|
|
134
146
|
export const isPullRequestEvent = (event: WatchEvent): event is PullRequestEvent =>
|
|
135
147
|
(PULL_REQUEST_KINDS as readonly string[]).includes(event.kind)
|
|
@@ -165,8 +177,12 @@ export const emptyWatchState = (): WatchState => ({
|
|
|
165
177
|
sources: emptySourceState(),
|
|
166
178
|
reportMtimes: {},
|
|
167
179
|
statusLines: null,
|
|
180
|
+
appointments: emptyAppointmentState(),
|
|
168
181
|
})
|
|
169
182
|
|
|
183
|
+
/** The fields every state file carries since the first one; each field added later is read as empty when missing. */
|
|
184
|
+
const FIRST_FORMAT_FIELDS = ['seenSeqs', 'pullRequests', 'runs', 'ghDownSince'] as const
|
|
185
|
+
|
|
170
186
|
const isOneOf = (values: Record<string, string>, value: unknown): boolean =>
|
|
171
187
|
typeof value === 'string' && Object.values(values).includes(value)
|
|
172
188
|
|
|
@@ -207,7 +223,8 @@ const isWatchState = (value: Record<string, unknown>): value is WatchState =>
|
|
|
207
223
|
isSourceState(value.sources) &&
|
|
208
224
|
everyValue(value.reportMtimes, isSeq) &&
|
|
209
225
|
(value.statusLines === null ||
|
|
210
|
-
(Array.isArray(value.statusLines) && value.statusLines.every((line) => typeof line === 'string')))
|
|
226
|
+
(Array.isArray(value.statusLines) && value.statusLines.every((line) => typeof line === 'string'))) &&
|
|
227
|
+
isAppointmentState(value.appointments)
|
|
211
228
|
|
|
212
229
|
/**
|
|
213
230
|
* Reads the state file; throws on any other shape, so a damaged file is seen, not read as empty. The
|
|
@@ -217,22 +234,8 @@ export const parseWatchState = (json: string): WatchState => {
|
|
|
217
234
|
const value: unknown = JSON.parse(json)
|
|
218
235
|
if (!isRecord(value)) throw new Error('watch state: unexpected shape')
|
|
219
236
|
if (isRecord(value.seenSeqs)) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
laneBranches: {},
|
|
223
|
-
coordinatorLevel: null,
|
|
224
|
-
feedback: emptyFeedbackState(),
|
|
225
|
-
failures: emptyFailureState(),
|
|
226
|
-
previews: emptyPreviewState(),
|
|
227
|
-
laneLevels: {},
|
|
228
|
-
laneModels: {},
|
|
229
|
-
laneParallels: {},
|
|
230
|
-
approvals: [],
|
|
231
|
-
sources: emptySourceState(),
|
|
232
|
-
reportMtimes: {},
|
|
233
|
-
statusLines: null,
|
|
234
|
-
...value,
|
|
235
|
-
}
|
|
237
|
+
if (!FIRST_FORMAT_FIELDS.every((field) => field in value)) throw new Error('watch state: unexpected shape')
|
|
238
|
+
const complete = { ...emptyWatchState(), ...value }
|
|
236
239
|
if (!isWatchState(complete)) throw new Error('watch state: unexpected shape')
|
|
237
240
|
return complete
|
|
238
241
|
}
|
|
@@ -289,23 +292,13 @@ export const recordWatchState = (previous: WatchState, observation: Observation,
|
|
|
289
292
|
return { ...previous, seenSeqs: seenSeqsOf(lanes), ghDownSince: previous.ghDownSince ?? now, laneBranches }
|
|
290
293
|
}
|
|
291
294
|
return {
|
|
295
|
+
...previous,
|
|
292
296
|
seenSeqs: seenSeqsOf(lanes),
|
|
293
297
|
pullRequests: recordsOf(previous, github.pullRequests, github.own ?? []),
|
|
294
298
|
runs: runsOf(github.runs),
|
|
295
299
|
ghDownSince: null,
|
|
296
300
|
savedAt: now,
|
|
297
301
|
laneBranches: keptLaneBranches(previous, observation, github.pullRequests),
|
|
298
|
-
coordinatorLevel: previous.coordinatorLevel,
|
|
299
|
-
feedback: previous.feedback,
|
|
300
|
-
failures: previous.failures,
|
|
301
|
-
previews: previous.previews,
|
|
302
|
-
laneLevels: previous.laneLevels,
|
|
303
|
-
laneModels: previous.laneModels,
|
|
304
|
-
laneParallels: previous.laneParallels,
|
|
305
|
-
approvals: previous.approvals,
|
|
306
|
-
sources: previous.sources,
|
|
307
|
-
reportMtimes: previous.reportMtimes,
|
|
308
|
-
statusLines: previous.statusLines,
|
|
309
302
|
}
|
|
310
303
|
}
|
|
311
304
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30.55 24" width="28" height="22" preserveAspectRatio="xMidYMin meet" fill="none" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><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"/></svg>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { isAbsolute, relative, resolve, sep } from 'node:path'
|
|
2
|
-
|
|
3
|
-
/** herdr's agent names; a worktree whose directory has another name cannot be a lane. */
|
|
4
|
-
const LANE_NAME = /^[a-z][a-z0-9_-]{0,31}$/
|
|
5
|
-
|
|
6
|
-
export type LaneLocation = { cwd: string; main: string; worktreeDirectory: string }
|
|
7
|
-
|
|
8
|
-
/** The lane whose worktree holds `cwd`: the first directory below the main checkout's worktree directory, else null. */
|
|
9
|
-
export const laneOf = ({ cwd, main, worktreeDirectory }: LaneLocation): string | null => {
|
|
10
|
-
const path = relative(resolve(main, worktreeDirectory), resolve(cwd))
|
|
11
|
-
if (path === '' || path.startsWith('..') || isAbsolute(path)) return null
|
|
12
|
-
const [lane] = path.split(sep)
|
|
13
|
-
return LANE_NAME.test(lane) ? lane : null
|
|
14
|
-
}
|