Commit 1da33cb
authored
Release v0.34.0 (#304)
* Foundation for the staged-apply fix: a pmxcfs writer and a pvesh that answers like the real one
First commit of the series designed in
diagnostics/design-staged-apply-pmxcfs-2026-09-02.md (fable-check bugs 1-5,
verified live on a PVE 9.1.9 node).
pmxcfsWriteFile writes one file under /etc/pve behind the same mounted guard
restore_ha.go and restore_access_control_ui.go already enforce (isMounted via
a seam var, root seamed for tests): with pmxcfs not mounted a write would be a
shadow file on the root filesystem that the real mount hides forever, so the
helper refuses. No rollback capture, on the maintainer's call: the workflow's
existing safety backup already archives everything these writes can touch.
TDD: three tests written first (write-under-root, not-mounted refusal with no
shadow file, mount-check error surfaced), red on the missing symbol, green on
the implementation.
schemaAwarePvesh is the test-side half: a CommandRunner that answers the way
the live node answered, verbatim - "No 'set' handler defined for
'/cluster/config'", "meta: property is not defined in schema", "storage ID
'local' already defined" - and stays permissive for the two pvesh callers the
series does not touch. The exact-key FakeCommandRunner could only echo what a
test taught it, which is how endpoints that do not exist stayed green for
months. A self-test pins the fake to the live strings so nobody can un-teach
it the rejections.
Nothing wired yet: no production call site changes in this commit.
* datacenter.cfg is restored by writing pmxcfs, not by calling an endpoint that does not exist
Both rails - the staged arm (applyPVEDatacenterCfgFromStage) and the SAFE-apply
UI arm (confirmAndApplyDatacenterCfg) - called
`pvesh set /cluster/config -conf <file>`. A live PVE 9.1.9 node answers that
with `No 'set' handler defined for '/cluster/config'` (probed 2026-09-02), so
datacenter.cfg was NEVER restored on any non-recovery restore; the failure just
landed in failedItems as a warning. fable-check bug 1.
The API has no whole-file endpoint (options live per-key under
/cluster/options), and /etc/pve IS pmxcfs: writing the staged file replicates
it cluster-wide exactly the way the call would have. Both rails now go through
pmxcfsWriteFile - mounted guard included - and pvesh is out of this arm
entirely, together with its which-check. The UI confirmation still gates the
SAFE rail.
TDD, red first against the schema-aware fake, which reproduced the LIVE
failure verbatim in a unit test for the first time:
staged datacenter.cfg apply failed against the real pvesh surface:
pvesh [set /cluster/config -conf /stage/etc/pve/datacenter.cfg] failed:
No 'set' handler defined for '/cluster/config'
Green: both rails land the staged bytes at <pmxcfs>/datacenter.cfg, zero
/cluster/config calls, and the unmounted guard refuses with no shadow file.
The two tests that PINNED the dead endpoint (pve_staged_apply_additional_test,
restore_coverage_extra_test) now pin the file write instead.
* vzdump.cron finally comes back from a staged restore
Collected under pve_jobs, documented in RESTORE_GUIDE.md as staged-applied,
and never read back by any restore path: legacy cron backup jobs silently
vanished from every staged restore (fable-check bug 5; a repo-wide grep finds
zero restore-side consumers before this commit).
There is no pvesh endpoint for vzdump.cron. The file lives in pmxcfs, so
applyPVEVzdumpCronFromStage writes the staged bytes through pmxcfsWriteFile -
mounted guard included - exactly the way datacenter.cfg is now handled, and is
wired into the pve_jobs branch beside jobs.cfg, gated off cluster RECOVERY
like its sibling (config.db owns the file there). A failure lands in
failedItems as "vzdump.cron", warning-weight like every other arm.
TDD, red first (missing symbol, then the wiring pin): write-through test,
absent/empty silent skips that leave pmxcfs untouched, unmounted-guard
refusal, and a wiring test that fails if the arm ever becomes dead code again.
This makes RESTORE_GUIDE.md:156 true instead of amending it downward.
* storage.cfg apply updates existing definitions instead of failing on them
applyStorageCfg only ever ran `pvesh create /storage`. `dir: local` exists on
every node and in every backup, so every staged/SAFE storage apply on a live
node failed on it - the live node answers "create storage failed: storage ID
'local' already defined" (probed 2026-09-02) - ended "with warnings", and an
existing definition was never updated (fable-check bug 4). The proof the
pattern was known sits twenty lines away: the backup-jobs apply has had
create-then-set all along.
On create failure the arm now retries as `pvesh set /storage/<id>` with the
same args minus --storage and --type (create-only keys; `pvesh usage
/storage/local` confirms the set handler exists). Both failing keeps today's
warning, now carrying both causes. No file fallback, on the maintainer's call:
per-block API preserves the definitions an operator added after the backup.
TDD, red first against the schema-aware fake: a two-block storage.cfg
(existing `local` + new `backup_ext`) scored applied=1 failed=1; green it
scores 2/0, the fallback call is `set /storage/local` without create-only
keys, and the new block still goes through create. A second test pins the
both-fail arm at 0/1.
* Guest configs apply through the API minus its blind spots, with the conf file as the net
Two proven failures in one arm (fable-check bugs 2-3, probed live 2026-09-02
on PVE 9.1.9):
- Every VM created on PVE >= 7.2 carries `meta:` in its conf, the qemu update
schema has no --meta ("meta: property is not defined in schema"), and one
rejected key fails the WHOLE `pvesh set`: no modern guest ever got its
config applied.
- A missing LXC could never be created: pveshCreateGuestArgs demanded an
ostemplate that is create-time-only and never persists into a conf. The
passing unit test hand-fed it - an input no real backup produces.
applyVMConfigs now works in the shapes the maintainer chose:
- Existing guest: `pvesh set` first, minus the create-only keys the schemas
refuse (filterGuestCreateOnlyArgs: --meta, --ostemplate). If the set still
fails, the staged conf is written byte-for-byte into
/etc/pve/nodes/<node>/<dir>/<vmid>.conf - /etc/pve is pmxcfs, the write IS
the cluster-wide apply - UNLESS status/current answers "running": a config
race with a live guest is the one case where the file must not win, so the
arm warns naming the guest and the reason and counts the failure.
- Missing guest: no pvesh create at all; writing the conf into pmxcfs is how
a guest comes into existence, and the log states it restores the CONFIG,
not the disks. pveshCreateGuestArgs and its hand-fed test are deleted.
TDD, red first against the schema-aware fake (extended with guests, running
state and a failSet seam): meta-carrying guest scored 0/1, missing LXC 0/1,
both green at 1/0 with the API attempt stripped of the refused keys and the
file landing only when the API lost. The running-guest guard and the
stopped-guest fallback each have their own pin. The one legacy test pinning
create-then-set now pins register-via-pmxcfs.
* The restore docs and prompts stop describing the endpoint that never existed
Companion to the staged-apply series (fable-check bugs 1-5): four passages
documented `pvesh set /cluster/config -conf <file>` as the datacenter apply -
RESTORE_TECHNICAL.md's pseudocode, CLUSTER_RECOVERY.md's SAFE list,
RESTORE_GUIDE.md's post-restore actions and its datacenter section. All four
now describe what the code does since this series: datacenter.cfg written
into pmxcfs (no whole-file endpoint exists), storage create with the
set-fallback for existing ids, guests via set minus create-only keys with the
conf file as the net, missing guests registered by writing the conf.
The two datacenter prompts ("Apply datacenter.cfg via pvesh?") and the SAFE
header line said "via pvesh" too; a prompt must not name a mechanism the code
no longer uses, so the mechanism is simply gone from the words. Sample
transcripts in RESTORE_GUIDE updated to match.
Release notes 0.33.0 gain the two operator-facing lines: staged restore now
really applies datacenter.cfg/vzdump.cron/existing storage, and guest configs
survive on modern PVE.
* The live node caught two more schema truths; the arms now handle both
Ran the whole staged-apply matrix on a real PVE 9.1.9 node (livepve_test.go,
build tag livepve: idempotent by construction - identical bytes, identical
values, and the one thing it creates, config-only CT 990, it deletes again).
First run: 3/5. The two failures were fresh live-only facts the exact-key
fakes had always masked:
- A missing guest never read as missing: pvesh prints "Configuration file
'...' does not exist" on its OUTPUT while the Go error is a bare
"exit status 2", so isPveshNotFoundError never matched on a real node and
pveshGuestExists answered "check failed" instead of "absent" - also under
the OLD create path, which was therefore unreachable live.
pveshGuestExists now reads the output too (isPveshNotFoundText).
- `path` is create-only for storage as well: the set fallback died with
"Unknown option: path". The set schema varies by storage type and PVE
version, so a whitelist would drift; pveshSetStorageDroppingCreateOnly
instead drops exactly the key pvesh names and retries, converging or
failing with the real cause. All settable keys already matching is a
success, not a failure.
The schema-aware fake learned both live shapes (reason-on-output with bare
exit status; --path refused on storage set), which turned the two unit tests
red first; both fixes green; full suite green.
Second live run: 5/5 PASS -
datacenter.cfg written to pmxcfs and byte-identical after the apply;
vzdump.cron the same;
storage 'local': create refused, --path dropped, set applied
("Updated existing storage definition local");
VM 101 (stopped, meta-carrying): full set applied minus --meta, meta line
preserved in the conf;
CT 990: registered by writing the conf, answers on the API, deleted after.
One benign nuance recorded: the API path is not byte-idempotent - PVE
canonicalizes storage.cfg content lists and re-setting an empty cdrom
appended ide2 to VM 101's boot order (restored by hand). Fidelity-relevant
only for byte-for-byte expectations, which the file-write arms already serve.
* The staged-restore notes move to 0.34.0: 0.33.0 shipped while they were written
The maintainer merged PR #303 and tagged v0.33.0 while the staged-apply series
was in flight, so the release-notes lines this series had added to the 0.33.0
entry described a release that had already shipped without them - and the
registry is append-only over FINAL versions. The 0.33.0 entry is restored
byte-identical to the tag (zero deletions against v0.33.0), and the
staged-restore story gets its own 0.34.0 entry: datacenter.cfg/vzdump.cron/
storage really applied, guest configs surviving modern PVE, missing guests
registered from their config file, plus the one operator pointer at the
restore log.
* Cloud retention attribution is floored and the log delete speaks single-object rclone
Two rclone faults from the fable-check sweep, both on the cloud cleanup path:
resolveRetentionOwners ran one `rclone cat` per archive on the raw cancel-only
run ctx and waited on ALL of them, so a single wedged cat hung the unattended
cron/daemon run forever - while cloud.go's header promises the retention paths
are floored. The whole attribution phase now runs under boundManagementCtx:
archives left unresolved when the budget expires keep an empty Hostname and
degrade to the filename token, the documented fallback.
deleteAssociatedLog removed ONE file with the directory-oriented `delete`: a
merely-absent log came back as "directory not found" on directory-listing
backends, which the error branch misread as the whole CLOUD_LOG_PATH being gone
(false WARNING, exit 1, logPathMissing poisoning cleanup for every remaining
backup), and as exit 0 on prefix backends, counting a deletion that never
happened. Both reproduced live with rclone v1.75.0. The verb is now
`deletefile` and every not-found wording lands in the benign already-removed
branch; the real path-missing detection stays with countLogFiles' lsf.
* A crashed bundle's temp file no longer counts as a backup forever
The bundle build stages <archive>.bundle.tar.tmp-<rand> in BACKUP_PATH
(fs.CreateTemp with pattern "<base>.tmp-*"), with no leading dot - but
isBackupTempArtifact only recognized a leading-dot .tmp- prefix. A crash during
bundling therefore left a file every List counted as a backup: it matches the
backup glob, triggers the missing-.metadata WARNING each pass (pinning exit 1),
inflates counts, and nothing ever deletes it. The temp marker now matches
anywhere in the base name.
* Mount points own a path by boundary, not by string prefix
getMountPoint matched /proc/mounts entries with a bare strings.HasPrefix, so
with mounts / and /mnt/nas a BACKUP_PATH of /mnt/nas2 was attributed to
/mnt/nas - and a dead /mnt/nas then turned into a critical StorageError
aborting the backup of a perfectly healthy sibling path. The match now requires
a path boundary (root, exact, or prefix + "/"), and the selection loop moved
into bestMountPointFor so the rule is testable against synthetic mount tables.
* A second --daemon refuses to start instead of burying the first
There was no single-instance guard: a second hand-run daemon (the exact
ExecStart line DAEMON.md invites operators to paste) overwrote
.daemon.pid/.daemon_info.json with its own identity and, on exit, DELETED both,
leaving the still-running unit daemon undiscoverable - standalone backup
handoffs find no live daemon and outcomes go unpinged until a unit restart -
and the daily backup was double-scheduled while both lived.
run() now probes the recorded pid before publishing anything, with the same
liveness + /proc cmdline gate the standalone handoff already trusts, and
refuses to start when a live proxsave --daemon owns it, leaving the incumbent's
files untouched. A stale file (dead pid, recycled pid belonging to something
else) never blocks a restart, so kill -9 + systemd restart still boots. The
refusal exits ExitBackupSkipped for the same reason the concurrent-backup skip
does: nothing is wrong with the host, the work is already owned.
* The in-progress lock speaks once: the bare pre-log drops to Debug
All four benign-concurrency arms of CheckLockFile (three formatInProgress
returns and the lost O_EXCL create race) logged the bare message at ERROR right
before returning it - and the caller's logResult then rendered the same fact
again as the one red "✗ Lock File (BACKUP_IN_PROGRESS)" line. One skip
recapped errors=2 with two red lines saying the same thing. The ERROR level on
the ✗ line is intended and stays; the bare pre-log stays too, for debugging, at
Debug.
* The tier closing line reports the worst thing the adapter saw
After a non-critical Store failure with a clean retention pass, the closing
branch read only hasWarnings and printed the green "✓ ... operations
completed" at INFO - the log's last word on the backend contradicted the
notification's "error" status and the two "Backup was not saved" warnings a
few lines above. Reproduced end to end on the real secondary backend (read-only
destination) and the real cloud backend (rclone failing copyto); the local arm
never reaches this branch (IsCritical aborts the run first).
The closing line now mirrors finalizeStorageStatus: errors outrank warnings,
"✗ ... operations completed with errors" at WARNING. Deliberately not ERROR:
the store failure itself is logged as recoverable and the exit contract stays
warning-weight (maintainer call, 2026-09-02). Nothing pinned any of the three
arms before; all three are pinned now.
* Critical-file and custom-path copy failures finally speak, and an aborted recipe names its hole
Since the initial Go port (#44), a REAL copy failure of /etc/passwd, /etc/shadow,
/etc/sudoers, /etc/network/interfaces or a CUSTOM_BACKUP_PATHS entry logged only
at Debug: WarningCount, exit code, notifications and healthchecks stayed green
while the archive silently lacked the file. The same recipe already warned loudly
for fstab, logrotate and mount units, so these were the mute odd ones out, not a
doctrine - no commit ever touched those levels on purpose. The interfaces arm
also lied: safeCopyFile answers a missing source with nil, so its err was always
a real failure, yet the message said "No /etc/network/interfaces found".
Real failures now warn naming the file and the cause; not-found stays silent by
design. And when a brick error aborts a recipe, the tail used to vanish without a
trace at any level (bricks that never ran record nothing, not even in the
manifest): the abort now warns naming the recipe, the failed brick and how many
bricks never ran, with a Debug line per skipped brick.
Reproduced live before fixing: unreadable /etc/shadow on this host rendered
nothing at INFO while FilesFailed counted 4; a read-only staging tree aborted the
system recipe at the commands brick with everything after it missing untraced.
* The prefilter touches only what it claims to touch: CRLF pairs in plain text
normalizeTextFile did bytes.ReplaceAll(data, "\r", nil) on every small
.txt/.log/.md/.conf/.cfg/.ini in the whole staging tree, CUSTOM_BACKUP_PATHS
payload included, while CONFIGURATION.md sells the step as safe,
semantic-preserving removal of \r from CRLF text files. Measured live before
fixing: a UTF-16LE "hi\r\nyo" lost the 0x0D byte of its 0x0D 0x00 pair, went
odd-length and decoded to garbage from that point on; a lone-\r progress log
had its lines silently merged. The corruption lands in the staged copy, so it is
the backup - and any restore of it - that carries the damage.
The rewrite now collapses only \r\n pairs, and only in plain single-byte text:
a UTF-16/UTF-32 BOM or any NUL byte (the cheapest reliable tell for wide
encodings and binary payloads alike) leaves the file byte-identical. The
existing pure-CRLF fixtures pass unchanged - CRLF-only input normalizes to the
same bytes as before.
* config.db is captured through sqlite3 .backup, not a raw read of a live WAL database
The pmxcfs backing store - the artifact RECOVERY writes back verbatim - runs in
WAL mode, and the capture was a plain file copy of the base file: torn pages on
a mid-copy write, and on a standalone node (which skips the directory snapshot)
every write since the last checkpoint simply absent. Measured on the live test
node: base file 40KB, hours old; config.db-wal 4.1MB, current - the raw capture
was missing most of the recent state even with no race at all.
The capture now runs sqlite3 -cmd '.timeout 5000' <db> '.backup <target>': the
online-backup API takes a shared lock and reads base+WAL as one coherent
snapshot, verified live under the running pmxcfs on PVE 9.1.9 (integrity_check
ok, WAL content included; sqlite3 ships on the node). On any failure - sqlite3
absent, database locked past the busy timeout - the old raw copy still runs,
now behind a WARNING that names the torn-page and missing-WAL consequence. The
snapshot lands after the clustered directory copy on the same target path, so
the consistent artifact is the one that wins in both arms.
* The parked bundle-pair double count is pinned as a characterization
Bug 6 of the fable-check sweep is real but parked (maintainer call: the
both-forms state needs a removeAssociatedFiles failure right after bundling and
has never been seen in the wild). These tests keep the state measured instead
of remembered: with BUNDLE_ASSOCIATED_FILES=true - the default everyone runs -
the standalone+bundle pair collapses to one logical backup, which is exactly
why no user has ever seen a double count; with it false, List still reports two
entries for one archive while deleting either entry removes both forms, so
simple retention keeps fewer real backups than MAX_LOCAL_BACKUPS promises. If
either side changes, it now changes a failing test - consciously. A deliberate
fix of bug 6 flips the OFF-side assertions.
* The log-level threshold mutes the console, not the truth
One gate sat before the counters, the issue capture and the file sink alike, so
--log-level error made a warning vanish from every channel at once: HasWarnings
painted the footer green, the shipped log had no line for the re-parse to find,
and the run exited 0 - for a run that DID warn. Maintainer call (2026-09-02):
the threshold is a CONSOLE filter. Warning-weight lines and above are always
counted and always reach the log file - the artifact notifications ship keeps
the evidence for the exit code - and only their display (console and mirror
tap) is muted. Below warning the threshold keeps its full meaning everywhere.
CLI_REFERENCE.md states the contract.
* A notify failure exits 1 on every install, not only when Prometheus is on
The post-notification re-parse (finalizeSuccessIssueStats) decides the PROCESS
exit code - exportBackupMetrics runs as a defer inside RunGoBackup and mutates
the same stats the cmd layer returns - yet it sat behind the
shouldExportBackupMetrics gate: the same notify failure exited 1 with
METRICS_ENABLED=true and 0 on a default install. Both halves of the
contradiction shipped in the same release (90338af): NOTIFICATIONS.md promised
the exit code frozen before any send, while the helper's comment and test
promised promotion to 1.
Maintainer call (2026-09-02): a notification failure is warning-weight ALWAYS.
The re-parse now runs before the metrics gate on every successful non-dry run,
and NOTIFICATIONS.md states the decided contract: warning-weight, exit 1, never
an error code - monitoring learns notifications are broken exactly when email
cannot say so.
* The mount table answers with its last word, not its first
getFilesystemType took the FIRST /proc/mounts entry for the mount point. Under
a systemd automount the autofs placeholder precedes the triggered real
filesystem at the same path - the live PVE test node shows the exact pair for
binfmt_misc, and stacked-mount experiments there confirm the kernel appends in
mount order, so the LAST entry is what a path actually resolves to. With the
first entry winning, a backup path behind an automount parsed as autofs ->
FilesystemUnknown: not a network filesystem, so the ownership write-probe never
ran, and SetPermissions silently skipped chown/chmod 0600 on every stored
backup. The lookup now keeps the last matching entry, extracted into
lastMountEntryFor and pinned with the node's verbatim lines.
* The 0.34.0 notes cover the whole fable-check batch
The pending entry described only the staged-restore series; everything the
sweep fixed since - collection failures that warn, the prefilter that no longer
corrupts, the coherent config.db snapshot, the retention hang, the exit-code
contracts, the daemon guard - lands in the same release and belongs on
Screen 0. Eight lines, the gate's ceiling, so the most niche fixes (mount
boundary details, closing-line wording) stay in the log and the release notes
draft instead.
* Ignore local Superpowers planning artifacts
* Fail closed on uncertain PVE guest status
* Guard PVE guest apply with cluster inventory
* Harden live PVE guest safety checks
* Confine pmxcfs writes to the verified mount
* Make daemon ownership atomic
* Honor dry-run for SQLite snapshots
* Centralize advisory file locking
* Reuse advisory locks across runtime services
* Preserve NUL-free binary backup data
* Keep valid tmp-named backups visible
* Report optional network copy failures
* Use live storage values in PVE test
* Keep muted log records in the mirror
* Cover failed-run notification reparse guard
* Label pmxcfs restore confirmation accurately
* Clarify notification exit-code release note
* Align restore docs with payload-driven recovery
* Clean up PVE guest fallback test
* fix: detect interactive auto-confirmed upgrades by tty
* fix: reopen dashboard with upgraded binary
* test: cover unattended upgrade notes warning
* fix: clarify trusted personal script paths
* fix: serialize PVE guest config restores
* fix: resolve dashboard lint failures
* refactor: share daemon status diagnostics
* refactor: share personal script inspection
* feat: report personal script daemon diagnostics
* docs: explain daemon script diagnostics
* fix: bound daemon uid conversion
* fix: normalize statfs block size
* docs: clarify amd64 syscall assumption
* fix: clear daemon diagnostics CI regressions
* fix: execute inspected personal script path1 parent b6765c7 commit 1da33cb
84 files changed
Lines changed: 5898 additions & 549 deletions
File tree
- cmd/proxsave
- docs
- internal
- backup
- checks
- filelock
- identity
- logging
- orchestrator
- safefs
- storage
- whatsnew
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
10 | 13 | | |
11 | 14 | | |
12 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
311 | 311 | | |
312 | 312 | | |
313 | 313 | | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
314 | 333 | | |
315 | 334 | | |
316 | 335 | | |
317 | 336 | | |
318 | 337 | | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
319 | 347 | | |
320 | 348 | | |
321 | 349 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 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 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 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 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
0 commit comments